UNITED STATES PATENT AND TRADEMARK OFFICE
UNITED STATES DEPARTMENT OF COMMERCE
United States Patent and Trademark Office
Address: COMMISSIONER FOR PATENTS
P.O. Box 1450
Alexandria, Virginia 22313-1450
www.uspto.gov
APPLICATION NO. FILING DATE FIRST NAMED INVENTOR ATTORNEY DOCKET NO. CONFIRMATION NO.
14/523,175 10/24/2014 Antoine Roland Raux RPS920140025USNP(710.348) 9876
58127 7590 10/29/2019
FERENCE & ASSOCIATES LLC
409 BROAD STREET
PITTSBURGH, PA 15143
EXAMINER
YUN, CARINA
ART UNIT PAPER NUMBER
2194
MAIL DATE DELIVERY MODE
10/29/2019 PAPER
Please find below and/or attached an Office communication concerning this application or proceeding.
The time period for reply, if any, is set in the attached communication.
PTOL-90A (Rev. 04/07)
UNITED STATES PATENT AND TRADEMARK OFFICE
____________
BEFORE THE PATENT TRIAL AND APPEAL BOARD
____________
Ex parte ANTOINE ROLAND RAUX and
AKSHAY CHANDRASHEKARAN
Appeal 2019-000592
Application 14/523,175
Technology Center 2100
____________
Before JOHN A. EVANS, JOHN P. PINKERTON, and
MICHAEL M. BARRY, Administrative Patent Judges.
BARRY, Administrative Patent Judge.
DECISION ON APPEAL
Pursuant to 35 U.S.C. § 134(a), Appellant1 appeals from the
Examiner’s decision to reject claims 1–20, which are all of the claims
pending in this application. We have jurisdiction under 35 U.S.C. § 6(b).
We reverse.
1 We use the word “Appellant” to refer to “applicant” as defined in 37
C.F.R. § 1.42. Appellant identifies the real party in interest as Lenovo
(Singapore) PTE. LTD. Appeal Br. 3.
Appeal 2019-000592
Application 14/523,175
2
STATEMENT OF THE CASE
Introduction
Appellant discloses that on an electronic device, a user may be able to
perform multiple types of input (e.g., touch, click, or speech) within an
application. Spec. ¶ 15. In order to properly carry out the user’s command,
the application may need to know the nature of the user input (e.g., what
object the user selected and where it is located within the application). Id.
“[An existing] approach to determining the object the user has selected is to
write or modify the code associated with the application. However, this can
be both costly and risky,” require “a long development time and many
resources,” and introduce “bugs . . . affect[ing] the basic functionality of the
application.” Id. ¶ 16.
To address these concerns, Appellant’s invention embeds code within
an application such that user input relating to an application object may be
detected and data associated with the object (or the entire object itself) may
be received and sent to the application, allowing the application to navigate
back to the object (or copy the object). See Spec. ¶¶ 28, 33–35. In one
embodiment, programming code is embedded using a JavaScript injector
within a computer software application running on an electronic device. Id.
¶¶ 28, 29, Fig. 3 (item 302), Fig. 4 (item 402). A user opens the application,
touches or clicks on a displayed object, and states “copy this.” Id. ¶¶ 32, 33.
Upon detection of the user input, a JavaScript touch event listener receives a
call back function including an HTML tag associated with the object, which
is then sent to the application. Id. ¶ 34, Fig. 3 (items 303–305), Fig. 4 (item
403). An HTML element processor in the application then processes the
Appeal 2019-000592
Application 14/523,175
3
received call back function to navigate back to the object. Spec. ¶¶ 34–36,
Fig. 4 (item 404).
Claims 1, 11, and 20 are independent; claim 1 is illustrative of the
claims on appeal:
1. A method, comprising:
accessing code associated with an open application;
embedding additional code within the open application,
wherein the embedding comprises identifying, using the code
associated with the open application, objects within the open
application and adding identifiers that identify objects within the
open application to the open application;
detecting, at an electronic device, a user input, comprising
input provided using more than one input modality, within the
open application, wherein the user input selects an object within
the open application;
receiving data associated with the selected object, wherein
the data associated with the selected object is based upon the
additional code embedded within the open application and
identifies the selected object; and
sending data associated with the selected object to an
application selected from the group consisting of the open
application and another application.
Appeal Br. 40 (Claims App’x).
Rejections and References
The Examiner rejected claims 1–20 under 35 U.S.C. § 112(a), as
failing to comply with the written description requirement. Final Act. 3.
The Examiner rejected claims 1–20 under 35 U.S.C. § 112(b) as being
indefinite for failing to particularly point out and distinctly claim the subject
matter which the inventor or a joint inventor regards as the invention. Id. at
3–4.
Appeal 2019-000592
Application 14/523,175
4
The Examiner rejected claims 1–20 under 35 U.S.C. § 101 because
the claimed invention is directed to a judicial exception without significantly
more. Id. at 4–5.
The Examiner rejected claims 1–20 under 35 U.S.C. § 103 as being
unpatentable over Reesman et al. (US 2012/0102392 A1; publ. Apr. 26,
2012) (“Reesman”) and Allor (US 2003/0226102 A1; publ. Dec. 4, 2003).
Id. at 5–10.
ANALYSIS
A. The § 112 Rejections
1. § 112(a) Written Description
Compliance with the written description requirement is a question of
fact that is context sensitive. Ariad Pharm., Inc. v. Eli Lilly & Co., 598 F.3d
1336, 1351 (Fed. Cir. 2010) (en banc) (“[T]he level of detail required to
satisfy the written description requirement varies depending on the nature
and scope of the claims and on the complexity and predictability of the
relevant technology.”). The test is whether the disclosure “conveys to those
skilled in the art that the inventor had possession of the claimed subject
matter as of the filing date.” Id. The Specification must adequately describe
the claimed subject matter, but “the exact terms need not be used in haec
verba.” Lockwood v. Am. Airlines, 107 F.3d 1565, 1572 (Fed. Cir. 1997).
Claim 1 recites, in relevant part, “wherein the embedding comprises
identifying, using the code associated with the open application, objects
within the open application and adding identifiers that identify objects
within the open application to the open application.” The Examiner
determines the Specification lacks written description support for the phrase
“to the open application,” because the Specification discloses that “elements
Appeal 2019-000592
Application 14/523,175
5
are added to the code, not the open application.” Final Act. 3 (citing Spec.
¶ 29); see also Ans. 11.
Appellant argues the Examiner errs, contending the phrase “to the
open application” is clearly described in the Specification, which discloses
preprocessing code by adding invisible elements to it and embedding or
injecting the code into an application that may be opened and interacted with
by a user on an electronic device. Appeal Br. 17 (citing Spec. ¶¶ 17, 28, 29);
Reply Br. 18–19.
We agree with Appellant that the Examiner errs in the written
description rejection. Although the Examiner is correct that invisible
elements (e.g., identifiers such as tags) are added to the code, the
Specification also makes clear that this code, including its added identifiers,
may be embedded within an application to aid the application in identifying
what object a user has selected within the application. See, e.g., Spec.
¶¶ 28–29. In other words, by embedding the code (including the added
identifiers) within the application, the embedding comprises adding
identifiers not only to the code, but also to the application. In addition, to the
extent the Examiner is asserting that the Specification does not provide
written description support for adding the identifiers to an “open”
application, we disagree. As discussed in further detail below in the analysis
of the § 112(b) rejection, the Specification’s disclosure of an application that
has received an embedment or injection of code adequately describes an
“open” application, as recited.
Therefore, the Specification provides adequate written description
support for “wherein the embedding comprises . . . adding identifiers . . . to
the open application.”
Appeal 2019-000592
Application 14/523,175
6
Accordingly, we do not sustain the Examiner’s rejection of claims
1–20 under 35 U.S.C. § 112(a).
2. § 112(b) Definiteness
The test for definiteness is whether “those skilled in the art would
understand what is claimed when the claim is read in light of the
specification.” Orthokinetics, Inc. v. Safety Travel Chairs, Inc., 806 F.2d
1565, 1576 (Fed. Cir. 1986). Language in a claim is unclear if, when given
its broadest reasonable interpretation, it is “ambiguous, vague, incoherent,
opaque, or otherwise unclear in describing and defining the claimed
invention,” In re Packard, 751 F.3d 1307, 1311 (Fed. Cir. 2014), or if it “is
amenable to two or more plausible claim constructions,” Ex parte Miyazaki,
89 USPQ2d 1207, 1211 (BPAI 2008) (precedential). Because the language
of 35 U.S.C. § 112(b) is substantially the same as its predecessor, 35 U.S.C.
§ 112, second paragraph, the same test for definiteness applies here.
The Examiner concludes the independent claims are indefinite for
three different reasons (and, accordingly, their dependent claims are also
indefinite). Final Act. 4. The Examiner also concludes dependent claims 2
and 12 are indefinite for an additional reason. Id.
a. Embedding Additional Code within the Open Application
The Examiner determines the recitation in claims 1, 11, and 20 of
“embedding additional code within the [open application, wherein the]
embedding comprises identifying, using the code associated with the open
application, objects within the open application and adding identifiers that
identify objects within the open application to the open application” is
indefinite. Final Act. 4. The Examiner explains that “[i]t is not clear how
identifiers can be added to the open application,” “what the open application
Appeal 2019-000592
Application 14/523,175
7
is,” or “how the identifiers could be added to a browser” (which the
Examiner interprets as “the open application”). Id.
Appellant argues that, in view of the Specification, “it is sufficiently
clear how identifiers can be added to the open application, specifically, by
injecting code into the application, where the code includes identifiers, for
example, tags, invisible elements, or the like.” Appeal Br. 19 (citing
Spec. ¶¶ 29–31). Appellant contends “one skilled in computer programming
would also understand how identifiers could be added to the open
application.” Id. at 19–20.
The Examiner responds that paragraph 31 of the Specification “states
that tags could be added to the code,” but “does not say it could be added to
an open application.” Ans. 12. The Examiner adds that they “do[] not
understand how code could be added to an open application,” and
“Appellant does not show in the specification[] where it describes identifiers
are added to an open application” or “specify what is considered an open
application.” Id.
We agree with Appellant that the Examiner errs in determining the
disputed claim limitation is indefinite. As an initial matter, the Examiner’s
interpretation of an “open application” as a user-opened browser is
unreasonably narrow. Neither the claims nor the Specification provides a
limiting definition of “open application.” Rather, the Specification merely
provides non-limiting examples of the term. See, e.g., Spec. ¶ 28 (“For
example, a user may open an application (e.g., a word processing program, a
spreadsheet program, web browser, etc.).”) Although an “open application”
encompasses a user-opened browser, one of ordinary skill in the art would
understand the term is not so limited, and the term encompasses other
Appeal 2019-000592
Application 14/523,175
8
“open” software programs. Id. (also explaining that an embodiment embeds
code “within a WINDOWS application”). This clearly describes multiple
examples of an “open application,” as recited. Moreover, as discussed above
for the written description rejection, the Specification further describes “how
code could be added to an open application” and “identifiers [e.g., tags] are
added to an open application.” Ans. 12.; see, e.g., Spec. ¶¶ 28–29.
b. Receiving Data Associated with the Selected Object
The Examiner determines “receiving data associated with the selected
object, wherein the data . . . is based upon the additional code embedded
within the open application,” as recited in claims 1, 11, and 20, is indefinite
because “[i]t is not clear what the relationship between the data associated
with the selected object and [the] embedded code is” and what “based on”
means. Final Act. 4. Appellant contends “the claim itself clearly defines the
relationship between the data associated with the selected object and the
embedded code, specifically, that the embedded code identifies the selected
object and that the selected object is based upon the additional code.”
Appeal Br. 20. Appellant also contends this is consistent with the
Specification, which discloses that “embodiment[s] may receive data
associated with the selected object” and “[t]his data may comprise
information indicating where the object is located within the application” or
“the invisible element associated with the object selected by the user, if
invisible elements were injected into the application.” Id. (quoting Spec.
¶ 33) (explaining that “one skilled in computer programming would also
understand the relationship between the object and the code”).
Appellant’s argument is persuasive. Paragraph 33 of the Specification
clearly describes how the data associated with the selected object and the
Appeal 2019-000592
Application 14/523,175
9
additional code embedded in the application may be related. More
specifically, paragraph 33 discloses that the data associated with selected
object may contain the invisible element, tag, or hierarchy associated with
the object selected by the user. Spec. ¶ 33. Thus, one of ordinary skill in the
art would understand that “data associated with the selected object” being
“based upon” the “additional code embedded” means that the data may
contain one of the invisible elements, tags, or a hierarchy previously
embedded within the application.
c. Receiving and Sending Data
The Examiner determines the “receiving” and “sending” steps as
recited in claims 1, 11, and 20 are indefinite because “[i]t is not clear who is
receiving the data and who is sending the data.” Final Act. 4. Appellant cites
paragraphs 33 and 34 of the Specification, which describe embodiments for
sending and receiving data, and argues “it is an entity other than the open
application that is receiving data and sending data, as clearly identified by
the [S]pecification.” Appeal Br. 21. The Examiner responds that “the
[S]pecification only states that an embodiment receives the application, and
does not address what receives or sends data.” Ans. 12.
We agree with Appellant the Examiner errs, because one of ordinary
skill in the art would understand the recited “receiving” and “sending” of
data is, consistent with the Specification, performed by “an entity other than
the open application,” i.e., by a computer element such as a processor or
software being executed on a computing device. Appeal Br. 21. This is
consistent with both the claim language and the Specification. For example,
independent claim 11 (which recites limitations commensurate with those of
claim 1) and the Brief Summary of Appellant’s invention describe sending
Appeal 2019-000592
Application 14/523,175
10
and receiving the data using a processor of an information handling device.
Appeal Br. 41–42 (Claims App.); Spec. ¶¶ 3–5. Similarly, an embodiment
disclosed in the Specification describes a JavaScript Touch Event Listener
(i.e., software running on hardware) as sending and receiving the data. See
Spec. ¶ 34, Fig. 4 (item 403).
d. Open Application Embedded within Another Application
The Examiner determines claims 2 and 12, which recite “wherein the
open application is embedded within another application,” are indefinite
because “it is not clear how the open application could be embedded within
another application.” Final Act. 4. Appellant argues “that embedding one
application within another application is a very common computer
programming technique” and “not only does the [S]pecification specifically
identify how the open application could be embedded within another
application, but, additionally, one skilled in computer programming would
also understand the how to embed one application within another
application.” Appeal Br. 21–22 (citing Spec. ¶ 28, Fig. 4 (disclosing an open
application running an embedded web browser)).
We agree with Appellant that the Examiner errs. As an initial matter,
we note the Examiner explains “[i]t is not clear how the open application
could be embedded within another application” (Final Act. 4), which
substantively is an enablement concern, not indefiniteness. In this respect,
the Examiner errs by not providing appropriate analysis, i.e., the Wands
factors in reaching a determination. See In re Wands, 858 F.2d 731 (Fed.
Cir. 1988) (laying out a non-exhaustive list of eight fact-based factors to be
weighed in determining the legal question of enablement). The limitation
recited in claims 2 and 12 is both definite and enabled. Embedding one
Appeal 2019-000592
Application 14/523,175
11
application within another application, as recited, “is a very common
computer programming technique” and one skilled in computer
programming would understand how to accomplish this. See, e.g., Nicholas
Kassem, Designing Enterprise Applications with the JavaTM 2 Platform,
Enterprise Edition (Ver. 1.0.1) 59–60 (Sun Microsystems 2000); Matthew
Scarpino et al., SWT/JFace in Action 280–83 (Manning Publ. Co. 2005). An
application for patent need not teach, and preferably omits, what is
well-known in the art. In re Buchner, 929 F. 2d 660, 661 (Fed. Cir. 1991)
(citing Lindemann Maschinenfabrik GMBH v. Am. Hoist & Derrick Co., 730
F.2d 1452, 1463 (Fed. Cir. 1984)).
e. § 112(b) Definiteness – Conclusion
For the foregoing reasons, and upon review of claims 1, 2, 11, 12, and
20 in their entirety, we determine that, although broadly recited, the
limitations discussed above do not render the bounds of the claims
ambiguous, unclear, or amenable to multiple constructions, such that any of
the claims is indefinite. Thus, we are persuaded that the Examiner erred in
determining that claims 1, 2, 11, 12, and 20 are indefinite. Accordingly, we
do not sustain the Examiner’s § 112(b) rejections of claims 1, 2, 11, 12, and
20, and, for similar reasons, the Examiner’s § 112(b) rejections of dependent
claims 3–10 and 13–19.
B. The § 101 rejection
General § 101 Law and the USPTO 2019 Guidance
An invention is patent-eligible if it claims a “new and useful process,
machine, manufacture, or composition of matter.” 35 U.S.C. § 101. The
Supreme Court, however, has long interpreted 35 U.S.C. § 101 to include
implicit exceptions: “[l]aws of nature, natural phenomena, and abstract
Appeal 2019-000592
Application 14/523,175
12
ideas” are not patentable. E.g., Alice Corp. v. CLS Bank Int’l, 573 U.S. 208,
216 (2014).
In determining whether a claim falls within an excluded category, we
are guided by the Supreme Court’s two-step framework, described in Mayo
and Alice. Id. at 217–18 (citing Mayo Collaborative Servs. v. Prometheus
Labs., Inc., 566 U.S. 66, 71–73 (2012)). In accordance with that framework,
we first determine what concept the claim is “directed to.” See Alice, 573
U.S. at 219 (“On their face, the claims before us are drawn to the concept of
intermediated settlement, i.e., the use of a third party to mitigate settlement
risk.”); see also Bilski v. Kappos, 561 U.S. 593, 611 (2010) (“Claims 1 and 4
in petitioners’ application explain the basic concept of hedging, or protecting
against risk.”).
Concepts determined to be abstract ideas, and, thus, patent ineligible,
include certain methods of organizing human activity, such as fundamental
economic practices (Alice, 573 U.S. at 219–20; Bilski, 561 U.S. at 611);
mathematical concepts (Parker v. Flook, 437 U.S. 584, 594–95 (1978)); and
mental processes (Gottschalk v. Benson, 409 U.S. 63, 67 (1972)). In
Diamond v. Diehr, the claim at issue recited a judicial exception in the
category of mathematical concepts, but the Supreme Court held that “[a]
claim drawn to subject matter otherwise statutory does not become
nonstatutory simply because it uses a mathematical formula.” 450 U.S. 175,
176 (1981).
If the claim is “directed to” an abstract idea, we turn to the second
step of the Alice and Mayo framework, where “we must examine the
elements of the claim to determine whether it contains an ‘inventive
concept’ sufficient to ‘transform’ the claimed abstract idea into a patent-
Appeal 2019-000592
Application 14/523,175
13
eligible application.” Alice, 573 U.S. at 221 (internal quotation marks
omitted). “A claim that recites an abstract idea must include ‘additional
features’ to ensure ‘that the [claim] is more than a drafting effort designed to
monopolize the [abstract idea].’” Id. (alterations in original) (quoting Mayo,
566 U.S. at 77). “[M]erely requiring generic computer implementation fails
to transform that abstract idea into a patent-eligible invention.” Id. at 212.
The USPTO has published revised guidance on the application of
§ 101. 2019 Revised Patent Subject Matter Eligibility Guidance, 84 Fed.
Reg. 50–57 (Jan. 7, 2019) (“Guidance”). Under the Guidance, we first look
to whether the claim recites:
(1) any judicial exceptions, including certain groupings of abstract
ideas (i.e., mathematical concepts, certain methods of organizing human
activity such as a fundamental economic practice, or mental processes); and
(2) additional elements that integrate the judicial exception into a
practical application (see Manual of Patent Examining Procedure (MPEP)
§§ 2106.05(a)–(c), (e)–(h)).
See Guidance, 84 Fed. Reg. at 52–55. Only if a claim (1) recites a judicial
exception and (2) does not integrate that exception into a practical
application, do we then look to whether the claim:
(3) adds a specific limitation beyond the judicial exception that are not
“well-understood, routine, conventional” in the field (see MPEP
§ 2106.05(d)); or
(4) simply appends well-understood, routine, conventional activities
previously known to the industry, specified at a high level of generality, to
the judicial exception.
See Guidance, 84 Fed. Reg. at 56.
Appeal 2019-000592
Application 14/523,175
14
Our Analysis
Appellant argues the independent claims—which recite commensurate
limitations—together as a group, from which we select claim 1 as
representative. Appeal Br. 22–32; Reply Br. 23–33; 37 C.F.R.
§ 41.37(c)(1)(iv).
In following the Guidance, we first consider under prong one of Step
2A whether claim 1 recites a judicial exception. Guidance, 84 Fed. Reg. at
54. For this analysis, we remain mindful that we must not express the
claim’s basic concept in a way that is “untethered from the language of the
claims” and, accordingly, we assess what the claim 1 recites at the same
level of generality or abstraction expressed in the claim. Enfish, LLC v.
Microsoft Corp., 822 F.3d 1327, 1337 (Fed. Cir. 2016).
The five recited steps are for a method of embedding code within an
application, such that user input may be detected, and data associated with
the user input may be received and sent to the application, allowing the
application to take action with respect to the user input.
In the first step, code associated with an open application is accessed.
In the second step, additional code is embedded within the application that
identifies objects within the application and adds object identifiers to the
application. The third step detects a user input comprising more than one
input modality, which selects an object within the application. The fourth
step receives data that is associated with and identifies the selected object
and is based on the additional code. The fifth step sends the received data to
the application or another application.
The terms “object,” “code,” “application,” and “embedd[ed]” are
technical terms of art in software engineering and computer science. See,
Appeal 2019-000592
Application 14/523,175
15
e.g., MICROSOFT COMPUTER DICTIONARY (5th ed. 2002). Artisans of
ordinary skill would have understood the basic focus of claim 1 is the use of
software technology implemented on a computer processor for embedding
code within a computer software application, such that user input relating to
an application object may be detected and data associated with the object
may be received and sent to the application, allowing the application to
navigate back to the object. The basic focus of claim 1, as recited, is neither
a mathematical concept, nor a method of organizing human activity, nor a
mental process, and, thus, under the Guidance and consistent with relevant
precedent, claim 1 does not recite an abstract idea. See 84 Fed. Reg. at 52.
Claim 1’s basic focus is not, as the Examiner determines, similar to
the abstract ideas recited by the claims in Digitech or Benson. See Final Act.
5 (citing Digitech Image Techs., LLC v. Elecs. for Imaging, Inc., 758 F.3d
1344, 1350 (Fed. Cir. 2014); Benson, 409 U.S. at 65). The claims at issue in
Digitech were merely directed to “[d]ata in its ethereal, non-physical form,”
did not claim a processor’s use of the claimed data, and were so broad as to
“encompass all embodiments of the information contained in the device
profile, regardless of the process through which this information is obtained
or the physical medium in which it is stored.” Digitech, 758 F.3d at 1349–
51. Similarly, the claims in Benson were “so abstract and sweeping as to
cover both known and unknown uses of the [binary-coded decimal (BCD)]
to pure binary conversion.” Benson, 409 U.S. at 68.
By contrast, claim 1 focuses on a specific solution to a technical
problem (i.e., a particular software technique for embedding or injecting
code within an application to handle multi-modal user input so that the code
associated with the application does not have to be re-written or modified)
Appeal 2019-000592
Application 14/523,175
16
with a specific set of rules (as detailed in the embedding, detecting,
receiving, and sending steps described above). Claim 1 does not effectively
foreclose all other computer implementations to accomplish the same result
(i.e., “embedding” is limited by identifying objects within the open
application and adding object identifiers; “detecting” is limited by an input
using more than one input modality; “sending” and “receiving” are limited
by data associated with the selected object based on the embedded code).
Thus, claim 1 reflects an improvement in computer software functionality by
reciting specific steps that accomplish a result, akin to the patent-eligible
claims in Finjan, which recited an improved software virus scanner that
recited specific steps for generating a security profile that identifies
suspicious code and linking it to a downloadable. See Finjan, Inc. v. Blue
Coat Sys., Inc., 879 F.3d 1299, 1305 (Fed. Cir. 2018).
Claim 1 is also analogous to the claims at issue in DDR Holdings, as a
key aspect of the claims in both cases focuses on a challenge particular to
executing computer software over a network. See DDR Holdings, LLC v.
Hotels.com, L.P., 773 F.3d 1245, 1257 (Fed. Cir. 2014). In particular,
claim 1 details how to identify objects selected by a user’s multi-modal input
without having to modify the code of an open software application by
injecting or embedding code into the application, thereby allowing the
application to identify and provide an appropriate response to the user input.
As with the claims in DDR Holdings, Appellant’s claim 1 is not directed to
an abstract idea because it does “not merely recite the performance of some
business practice known from the pre-Internet world along with the
requirement to perform it on the Internet,” but rather “is necessarily rooted
Appeal 2019-000592
Application 14/523,175
17
in computer technology in order to overcome a problem specifically arising
in the realm of computer networks.” Id.
Thus, at prong one of step 2A of the Guidance, we determine claim 1
does not recite a judicial exception, and we terminate our analysis.
Accordingly, because we determine claim 1 is patent-eligible under
35 U.S.C. § 101, and claims 2–20 include commensurate limitations, we do
not sustain the Examiner’s rejection of claims 1–20 under 35 U.S.C. § 101.
C. The § 103 rejection
In rejecting claim 1 as unpatentable over the combination of Reesman
and Allor, the Examiner finds Reesman teaches “detecting, at an electronic
device, a user input, comprising input provided using more than one input
modality” as recited. Final Act. 6 (citing Reesman ¶ 69) (particularly finding
Reesman’s disclosure of “user input obtained from a user input interface 210
that receives user input from a user input device or devices” teaches those
limitations).
Appellant argues the Examiner errs in this finding, because “[w]hile
Reesman lists different types of input devices that may be used by a user,
Reesman does not even imply that the system can receive a user input that
comprises ‘input provided using more than one input modality,’ [as
recited].” Appeal Br. 36. Appellant contends that “using more than one input
modality,” as recited, requires using “a combination of input modalities,”
e.g., “speech and touch.” Id. at 36–37 (citing Spec. ¶¶ 15, 32, 33, and 36).
The Examiner responds that Appellant improperly “import[s] claim
limitations from the [S]pecification” by “arguing from the [S]pecification
that more than one modality means that the user can use speech and touch to
Appeal 2019-000592
Application 14/523,175
18
select an object within an application.” Ans. 15 (citing MPEP § 2111.01).
By contrast, the Examiner interprets “‘more than one input modality’ to
mean more than one mode to input data” and explains that “Reesman
teaches that are different modalities because the user may use a keyboard
and touchscreen interface to enter data.” Id. at 15–16. Appellant replies by
reiterating that “[w]hile Reesman lists different types of input devices that
may be used by a user, Reesman does not even imply that the system can
receive a user input that comprises ‘input provided using more than one
input modality,’” as recited. Reply Br. 36.
Appellant’s argument is persuasive. When construing claim terms
during prosecution before the Office, claims are to be given their broadest
reasonable interpretation consistent with the Specification, reading claim
language in light of the Specification as it would be interpreted by one of
ordinary skill in the art. In re Am. Acad. of Sci. Tech Ctr., 367 F.3d 1359,
1364 (Fed. Cir. 2004). However, the broadest reasonable interpretation
differs from the broadest possible interpretation. In re Smith Int’l, Inc., 871
F.3d 1375, 1383 (Fed. Cir. 2017). The correct inquiry in giving a claim term
its broadest reasonable interpretation in light of the Specification is “an
interpretation that corresponds with what and how the inventor describes his
invention in the specification, i.e., an interpretation that is ‘consistent with
the specification.’” Smith, 871 F.3d at 1382–83 (quoting In re Morris, 127
F.3d 1048, 1054 (Fed. Cir. 1997)).
Here, the Examiner’s claim construction is inconsistent with the plain
language of the claim and with the examples in the Specification. The plain
language of claim 1 supports Appellant’s position by reciting not just that a
user may provide input using different input modalities, but that a user input
Appeal 2019-000592
Application 14/523,175
19
is provided using more than one input modality, and that input selects an
object within the open application. The Specification describes embodiments
of the recited user input as employing “combined modalities,” such as
touching an image (or clicking on a word) within a web browser and also
stating “copy this.” Spec. ¶¶ 15, 32; see also id. ¶¶ 33, 36.
Accordingly, we agree with Appellant that the Examiner errs in
finding Reesman teaches the disputed limitation. At most, Reesman teaches
performing a first user input that is provided using a first input modality and
that selects a first object, and performing a separate, second user input that is
provided using a second modality and that selects a second object. See, e.g.,
Reesman ¶ 69. The cited disclosures of Reesman do not, however, teach or
suggest detecting “a” user input that is provided using two different input
modalities (i.e., “combined modalities”) that selects “an” object. Further, the
Examiner does not provide any persuasive evidence that Allor teaches or
suggests the disputed limitation. Nor does the Examiner provide sufficient
explanation to explain how or why the cited references suggest the use of
combined input modalities, as recited.
For the reasons discussed supra, and constrained by the evidence of
record before us, we do not sustain the Examiner’s § 103 rejection of
independent claim 1. For the same reason, we also do not sustain the § 103
rejection of independent claims 11 and 20, which recite similar limitations
and stand rejected on the same basis as claim 1. We also, accordingly, do not
sustain the § 103 rejections of dependent claims 2–10 and 12–19.
CONCLUSION
We reverse the rejection of claims 1–20 under 35 U.S.C. § 112(a).
Appeal 2019-000592
Application 14/523,175
20
We reverse the rejection of claims 1–20 under 35 U.S.C. § 112(b).
We reverse the rejection of claims 1–20 under 35 U.S.C. § 101.
We reverse the rejection of claims 1–20 under 35 U.S.C. § 103.
In summary:
Claims
Rejected 35 U.S.C. Basis Affirmed Reversed
1–20 § 112(a) Written Description 1–20
1–20 § 112(b) Indefiniteness 1–20
1–20 § 101 Eligibility 1–20
1–20 § 103 Reesman, Allor 1–20
Overall
Outcome 1–20
REVERSED
Notice of References Cited
Application/Control No.
14/523,175
Applicant(s)/Patent Under Patent
Appeal No. 2019-000592
Examiner Art Unit
2194 Page 1 of 1
U.S. PATENT DOCUMENTS
* Document NumberCountry Code-Number-Kind Code DateMM-YYYY Name CPC Classification US Classification
A US-
B US-
C US-
D US-
E US-
F US-
G US-
H US-
I US-
J US-
K US-
L US-
M US-
FOREIGN PATENT DOCUMENTS
* Document NumberCountry Code-Number-Kind Code DateMM-YYYY Country Name CPC Classification
N
O
P
Q
R
S
T
NON-PATENT DOCUMENTS
* Include as applicable: Author, Title Date, Publisher, Edition or Volume, Pertinent Pages)
U
V
W
X
*A copy of this reference is not being furnished with this Office action. (See MPEP § 707.05(a).)
Dates in MM-YYYY format are publication dates. Classifications may be US or foreign.
U.S. Patent and Trademark Office
PTO-892 (Rev. 01-2001) Notice of References Cited Part of Paper No. 20170303
Nicholas Kassem and the Enterprise Team, Designing Enterprise Applications with the JavaTM 2 Platform,
Enterprise Edition (Ver. 1.0.1) 59–60 (Sun Microsystems 2000)
Matthew Scarpino et al., SWT/JFace in Action 280–83 (Manning Publ. Co. 2005)
Microsoft Computer Dictionary (5th ed. 2002).
Designing Enterprise Applications
with the JavaTM 2 Platform, Enterprise Edition
Nicholas Kassem and the Enterprise Team
Version 1.0.1
Final Release
October 3, 2000
Copyright 2000 Sun Microsystems, Inc. 901 San Antonio Road, Palo Alto, CA 94303, U.S.A. All rights reserved.
This product or document is protected by copyright and distributed under licenses restricting its use, copying,
distribution, and decompilation. No part of this product or documentation may be reproduced in any form by any
means without prior written authorization of Sun and its licensors, if any.
Third party software, including font technology, is copyrighted and licensed from Sun suppliers.
Sun, Sun Microsystems, the Sun Logo, Java, JavaServer Pages, Enterprise JavaBeans, Java Compatible, JDK, JDBC,
J2EE, J2SE, EJB, JavaBeans, JavaMail, Write Once, Run Anywhere, and Java Naming and Directory Interface are
trademarks or registered trademarks of Sun Microsystems, Inc in the U.S. and other countries.
UNIX is a registered trademark in the United States and other countries, exclusively licensed through X/Open
Company, Ltd.
DOCUMENTATION IS PROVIDED "AS IS" AND ALL EXPRESS OR IMPLIED CONDITIONS,
REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE
EXTENT THAT SUCH DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
-----------------------------------------------------------------------------------------------------------------------------------------------------
Copyright 2000 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, CA 94303, Etats-Unis. Tous droits
réservés.
Ce produit ou document est protégé par un copyright et distribué avec des licences qui en restreignent l’utilisation,
la copie, la distribution, et la décompilation. Aucune partie de ce produit ou de sa documentation associée ne peut
être reproduite sous aucune forme, par quelque moyen que ce soit, sans l’autorisation préalable et écrite de Sun et
de ses bailleurs de licence, s’il y en a.
Le logiciel détenu par des tiers, et qui comprend la technologie relative aux polices de caractères, est protégé par
un copyright et licencié par des fournisseurs de Sun.
Sun, Sun Microsystems, le logo Sun Logo, Java, JavaServer Pages, Enterprise JavaBeans, Java Compatible, JDK,
JDBC, J2EE, J2SE, EJB, JavaBeans, JavaMail, Write Once, Run Anywhere, et Java Naming and Directory Interface
sont des marques de fabrique ou des marques déposées de Sun Microsystems, Inc. aux Etats-Unis et dans d’autres
pays.
UNIX est une marque enregistree aux Etats-Unis et dans d’autres pays et licenciée exclusivement par X/Open
Company Ltd.
LA DOCUMENTATION EST FOURNIE "EN L’ETAT" ET TOUTES AUTRES CONDITIONS, DECLARATIONS ET
GARANTIES EXPRESSES OU TACITES SONT FORMELLEMENT EXCLUES, DANS LA MESURE AUTORISEE
PAR LA LOI APPLICABLE, Y COMPRIS NOTAMMENT TOUTE GARANTIE IMPLICITE RELATIVE A LA
QUALITE MARCHANDE, A L’APTITUDE A UNE UTILISATION PARTICULIERE OU A L’ABSENCE DE CON-
TREFACON.
Contents
v
Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xiii
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .xvii
1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1
1.1 Challenges of Enterprise Application Development. . . . . . . . . . . . . . 3
1.1.1 Programming Productivity . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.1.2 Response to Demand . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.3 Integration with Existing Systems. . . . . . . . . . . . . . . . . . . . . 5
1.1.4 Freedom to Choose . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1.5 Maintaining Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 The Platform for Enterprise Solutions . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.1 J2EE Platform Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2.2 J2EE Platform Benefits . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.3 J2EE Application Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3.1 Multitier Application Scenario . . . . . . . . . . . . . . . . . . . . . . 16
1.3.2 Stand-Alone Client Scenario . . . . . . . . . . . . . . . . . . . . . . . . 18
1.3.3 Web-Centric Application Scenario . . . . . . . . . . . . . . . . . . . 19
1.3.4 Business-to-Business Scenario . . . . . . . . . . . . . . . . . . . . . . 20
1.3.5 A Note on the MVC Architecture . . . . . . . . . . . . . . . . . . . . 21
1.4 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2 J2EE Platform Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .25
2.1 Component Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.1.1 Applets and Application Clients . . . . . . . . . . . . . . . . . . . . . 26
2.1.2 Web Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.1.3 Enterprise JavaBeans Components . . . . . . . . . . . . . . . . . . . 28
2.1.4 Components, Containers, and Services . . . . . . . . . . . . . . . . 29
2.2 Platform Roles. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
2.2.1 J2EE Product Provider . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
2.2.2 Application Component Provider . . . . . . . . . . . . . . . . . . . . 31
2.2.3 Application Assembler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
CONTENTSvi
2.2.4 Deployer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.5 System Administrator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.2.6 Tool Provider. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
2.3 Platform Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.1 Naming Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.2 Deployment Services. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2.3.3 Transaction Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
2.3.4 Security Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
2.4 Service Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
2.4.1 JDBC API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
2.4.2 Java Transaction API and Service. . . . . . . . . . . . . . . . . . . . 40
2.4.3 Java Naming and Directory Interface . . . . . . . . . . . . . . . . . 40
2.4.4 Connector Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.5 Communication Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
2.5.1 Internet Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
2.5.2 Remote Method Invocation Protocols. . . . . . . . . . . . . . . . . 42
2.5.3 Object Management Group Protocols . . . . . . . . . . . . . . . . . 43
2.5.4 Messaging Technologies . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
2.5.5 Data Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3 The Client Tier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .49
3.1 Requirements and Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.1.1 Operating Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
3.1.2 Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.1.3 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
3.2 Overview of Client Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.3 Web Clients. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.3.1 Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3.2 Content Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
3.3.3 Types of Web Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4 EJB Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.4.1 Protocols and Facilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
3.4.2 Strengths and Weaknesses . . . . . . . . . . . . . . . . . . . . . . . . . 63
3.4.3 Types of EJB Clients. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.5 Enterprise Information System Clients. . . . . . . . . . . . . . . . . . . . . . . 67
3.6 Designing for Multiple Types of Client . . . . . . . . . . . . . . . . . . . . . . 68
3.6.1 Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
3.6.2 View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
CONTENTS vii
3.6.3 Controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
3.7 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
4 The Web Tier. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75
4.1 Web Applications and Web Containers . . . . . . . . . . . . . . . . . . . . . . 75
4.2 Dynamic Content Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
4.2.1 Common Gateway Interface . . . . . . . . . . . . . . . . . . . . . . . . 76
4.2.2 Servlets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
4.2.3 JavaServer Pages Technology . . . . . . . . . . . . . . . . . . . . . . . 78
4.3 Servlets and JSP Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.3.1 Web Component Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.3.2 Servlets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4.3.3 JSP Pages Versus Servlets. . . . . . . . . . . . . . . . . . . . . . . . . . 85
4.4 JSP Page Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
4.4.1 JavaBeans Components . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
4.4.2 Custom Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
4.4.3 Using Scriptlets and Expressions . . . . . . . . . . . . . . . . . . . . 88
4.5 Internationalization and Localization . . . . . . . . . . . . . . . . . . . . . . . . 88
4.5.1 Internationalization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.5.2 Localization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
4.6 Application Designs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
4.6.1 Applications with Basic JSP Pages and Servlets. . . . . . . . . 97
4.6.2 Applications with Modular Components. . . . . . . . . . . . . . . 98
4.6.3 EJB-Centric Applications . . . . . . . . . . . . . . . . . . . . . . . . . 103
4.7 Application Migration. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
4.7.1 Migrating a Web-Centric Application to Use
Enterprise Beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
4.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
5 The Enterprise JavaBeans Tier. . . . . . . . . . . . . . . . . . . . . . . . . . . . .113
5.1 Business Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
5.1.1 Common Requirements of Business Objects . . . . . . . . . . 115
5.2 Enterprise Beans as J2EE Business Objects . . . . . . . . . . . . . . . . . . 117
5.2.1 Enterprise Beans and EJB Containers . . . . . . . . . . . . . . . . 118
5.3 Entity Beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
5.3.1 Guidelines for Using Entity Beans . . . . . . . . . . . . . . . . . . 122
5.3.2 Persistence in Entity Beans . . . . . . . . . . . . . . . . . . . . . . . . 124
5.4 Session Beans . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
5.4.1 Stateful Session Beans. . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
CONTENTSviii
5.4.2 Stateless Session Beans. . . . . . . . . . . . . . . . . . . . . . . . . . . 128
5.5 Design Guidelines. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
5.5.1 Data Access Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
5.5.2 Value Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
5.5.3 Session Beans as a Facade to Entity Beans. . . . . . . . . . . . 135
5.5.4 Master-Detail Modeling Using Enterprise Beans . . . . . . . 136
5.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
6 The Enterprise Information System Tier . . . . . . . . . . . . . . . . . . . .141
6.1 Enterprise Information System Capabilities and Limitations. . . . . 142
6.2 Enterprise Information System Integration Scenarios . . . . . . . . . . 143
6.2.1 An Internet E-Store Application . . . . . . . . . . . . . . . . . . . . 143
6.2.2 An Intranet Human Resources Application . . . . . . . . . . . 144
6.2.3 A Distributed Purchasing Application . . . . . . . . . . . . . . . 145
6.3 Relational Database Management System Access . . . . . . . . . . . . . 146
6.4 Other Enterprise Information System Access. . . . . . . . . . . . . . . . . 146
6.5 Application Component Provider Tasks. . . . . . . . . . . . . . . . . . . . . 147
6.6 Application Programming Model . . . . . . . . . . . . . . . . . . . . . . . . . . 148
6.7 Programming Access to Data and Functions . . . . . . . . . . . . . . . . . 149
6.7.1 Client API for Enterprise Information System Access . . . 149
6.7.2 Tools for Application Development . . . . . . . . . . . . . . . . . 150
6.7.3 Access Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
6.8 Connections. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
6.8.1 Establishing a Connection. . . . . . . . . . . . . . . . . . . . . . . . . 154
6.8.2 Guidelines for Connection Management. . . . . . . . . . . . . . 155
6.9 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.9.1 Security Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
6.9.2 Application Programming Model . . . . . . . . . . . . . . . . . . . 158
6.9.3 Resource Signon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
6.10 J2EE Connector Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
6.11 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
7 Packaging and Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .165
7.1 Roles and Tasks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
7.2 Packaging J2EE Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
7.2.1 EJB Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
7.2.2 Packaging Components Into EJB Modules . . . . . . . . . . . . 170
7.2.3 Web Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
7.2.4 Packaging Components Into Web Modules . . . . . . . . . . . 173
CONTENTS ix
7.2.5 Application Client Modules . . . . . . . . . . . . . . . . . . . . . . . 174
7.3 Deployment Descriptors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
7.3.1 Specifying Deployment Descriptor Elements . . . . . . . . . . 176
7.4 Deployment Tools. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
7.4.1 Deployment Tool Actions . . . . . . . . . . . . . . . . . . . . . . . . . 187
7.4.2 Deployment Tool Requirements . . . . . . . . . . . . . . . . . . . . 189
7.5 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
8 Transaction Management. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .197
8.1 Properties of Transactions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
8.2 J2EE Platform Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
8.3 Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
8.3.1 Accessing Multiple Databases. . . . . . . . . . . . . . . . . . . . . . 199
8.3.2 Accessing Multiple Enterprise Information Systems
From Multiple EJB Servers . . . . . . . . . . . . . . . . . . . . . . . . 200
8.4 JTA Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200
8.4.1 JTA and JTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
8.5 Transactions in Applets and Application Clients . . . . . . . . . . . . . . 202
8.6 Transactions in Web Components . . . . . . . . . . . . . . . . . . . . . . . . . 202
8.7 Transactions in Enterprise Beans . . . . . . . . . . . . . . . . . . . . . . . . . . 203
8.7.1 Bean-Managed Transaction Demarcation . . . . . . . . . . . . . 204
8.7.2 Container-Managed Transaction Demarcation . . . . . . . . . 204
8.7.3 Transaction Guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . 207
8.8 Transactions in Enterprise Information Systems . . . . . . . . . . . . . . 208
8.8.1 JTA Transactions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208
8.8.2 Resource Manager Local Transactions . . . . . . . . . . . . . . . 209
8.8.3 Choosing Between JTA and Local Transactions. . . . . . . . 209
8.8.4 Compensating Transactions. . . . . . . . . . . . . . . . . . . . . . . . 210
8.8.5 Isolation Level . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212
8.9 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
9 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .215
9.1 Security Threats and Mechanisms . . . . . . . . . . . . . . . . . . . . . . . . . 215
9.2 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216
9.2.1 Protection Domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217
9.2.2 Authentication Mechanisms . . . . . . . . . . . . . . . . . . . . . . . 220
9.2.3 Authentication Call Patterns . . . . . . . . . . . . . . . . . . . . . . . 223
9.2.4 Auto-Registration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
9.2.5 Exposing Authentication Boundaries with References . . . 225
CONTENTSx
9.3 Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225
9.3.1 Declarative Authorization . . . . . . . . . . . . . . . . . . . . . . . . . 226
9.3.2 Programmatic Authorization . . . . . . . . . . . . . . . . . . . . . . . 227
9.3.3 Declarative Versus Programmatic Authorization . . . . . . . 228
9.3.4 Isolation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228
9.3.5 Identity Selection. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
9.3.6 Encapsulation for Access Control . . . . . . . . . . . . . . . . . . . 229
9.3.7 Controlling Access to J2EE Resources . . . . . . . . . . . . . . . 230
9.3.8 Example. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
9.4 Protecting Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9.4.1 Integrity Mechanisms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234
9.4.2 Confidentiality Mechanisms . . . . . . . . . . . . . . . . . . . . . . . 235
9.4.3 Identifying Sensitive Components . . . . . . . . . . . . . . . . . . 236
9.4.4 Ensuring Confidentiality of Web Resources . . . . . . . . . . . 236
9.5 Auditing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237
9.6 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238
10 The Sample Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .241
10.1 Application Functionality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
10.1.1 Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 242
10.1.2 Functional Specification . . . . . . . . . . . . . . . . . . . . . . . . . . 247
10.2 Application Architecture. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
10.2.1 Application Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 248
10.2.2 Application Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
10.3 The View. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 255
10.3.1 Shopping Interaction Interface . . . . . . . . . . . . . . . . . . . . . 256
10.3.2 JSP Pages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 259
10.3.3 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266
10.4 The Model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 273
10.4.1 State in the J2EE Platform . . . . . . . . . . . . . . . . . . . . . . . . 273
10.4.2 Persistent Data. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
10.5 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
10.6 The Controller. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
10.6.1 Main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
10.6.2 RequestProcessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 284
10.6.3 RequestToEventTranslator . . . . . . . . . . . . . . . . . . . . . . . . 285
10.6.4 ShoppingClientControllerWebImpl . . . . . . . . . . . . . . . . . 287
10.6.5 ShoppingClientController . . . . . . . . . . . . . . . . . . . . . . . . . 288
10.6.6 StateMachine. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
CONTENTS xi
10.6.7 ScreenFlowManager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 293
10.6.8 Model-View Synchronization . . . . . . . . . . . . . . . . . . . . . . 294
10.7 MVC Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 296
10.8 Stateless Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
10.8.1 Example: A Mailer Bean . . . . . . . . . . . . . . . . . . . . . . . . . . 298
10.9 Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
10.10 Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300
10.11 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
10.11.1 Requirements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301
10.11.2 Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 303
10.12 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 312
Afterword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .313
Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .315
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .333
xiii
Foreword
THE JavaTM platform was conceived to connect door knobs to light switches—
smart door knobs to smart light switches, certainly, but door knobs to light switches
nonetheless. And yet it is now widely used for building large server-side applica-
tions which run on some of the largest computers in the world. It is the fate of great
inventions to be used in ways unimagined by their creators even when the cre-
ators—like James Gosling, creator of the Java programming language—see a
horizon the rest of us do not glimpse. This is part of what makes an invention great.
In retrospect, the phenomenal success of the Java platform on servers might
seem inevitable. After all, the platform provides exactly what is needed to trans-
form the Internet from a publishing medium to a transactional one. The Java plat-
form is available on all of the many different servers where Internet applications
run. “Write Once, Run AnywhereTM” works so the programs can be quickly tested
and deployed. Engineers are several times more productive when they write to the
Java platform. But being the right thing at the right time isn’t the whole story. Two
more elements were needed: Technical leaders who were looking in a different
direction than most of us were, and business leaders who were eager to work
together in new ways so the ideas could become reality. The result was the devel-
opment of consistent products across the computer industry in a surprisingly short
period of time.
I joined the JavaSoft Division of Sun Microsystems in late 1995, recruited by
Eric Schmidt and Bill Joy, to lead the then tiny band of engineers and marketers.
We grew as fast as we could, barely keeping up with the early success of the Java
platform and the industry alliances we’d made around it. Even then, when the
focus was on applets running in browsers, when version 1.0 had not yet shipped,
there were two brilliant engineers with a different idea—Rick Cattell and Graham
Hamilton. They were thinking about the Java runtime environment on servers, and
even mainframes. Because of them, the now ubiquitous JDBCTM technology was
the first significant addition to the Java platform. Many excellent engineers have
followed Rick and Graham. But they started it. I’m pleased that I was clever
enough to listen to them as we expanded the group and the vision for the platform.
Until recently, “rocket scientists” have been needed to build the applications
the industry clamored for—applications that create new ways to do business over
the Internet while drawing on the resources already in place, such as databases,
FOREWORDxiv
transaction systems, inventory systems, invoicing systems, and credit systems.
These applications need to scale to thousands, even millions, of users. They must
interact with a wide array of legacy technologies that can’t be replaced, and they
have to be built in a hurry. The engineers who can build them are few—the rocket
scientists of our industry. But Rick and Graham saw a way to make the process a
lot easier by building the rocket science into the Java platform, bringing portabil-
ity and consistency through industry standardization, enabling quick adoption by
adapting to the systems already in place, and making development much easier by
automating most of the complicated details of server programming. These ideas
became the underpinnings of the Java 2 Platform, Enterprise Edition.
JDBC was a huge hit. As soon as the Java community released it, drivers for
all the important databases materialized in the market. Applications using JDBC
rapidly appeared in large numbers. The success of JDBC lead to a parade of other
middleware and database adapter projects—the Java Naming and Directory Inter-
faceTM API for uniform access to naming and directory services, the Java Message
Service for asynchronous exchange of data and events, the Java Transaction API
and Java Transaction Service for transactions, JavaServer PagesTM technology for
building dynamic Web pages, Java XML for developing XML-oriented applica-
tions, and the Enterprise JavaBeansTM architecture, a component model for server
applications. All of these were developed in collaboration with industry partners
in a process created by Rick and Graham and later refined and formalized as the
Java Community Process.
The seminal offering of JDBC in 1996 soon grew into an amazing array of
facilities, each with its own acronym and release plan. For those who didn’t live
with the various “J*’s” (and for some of us who did) it could be confusing. When
vendors announced support for Enterprise JavaBeansTM 1.0 before the specifica-
tion had been completed, we realized it was time to make this now very successful
portfolio a little easier to understand and manage.
The Java 2 Platform, Enterprise Edition (J2EETM platform) brings all of these
pieces together. The J2EE platform is defined by four key pieces: the specifica-
tion, the reference implementation, the compatibility test suite, and the J2EE
Blueprints design guidelines. The specification defines how the J2EE platform
works, whether it is included in an application server, a database, or anywhere
else. The reference implementation is useful for experimenting with the J2EE
platform and it offers a working standard for comparison. The compatibility test
suite ensures that J2EE vendors implement fully compliant versions of the plat-
form to ensure “Write Once, Run Anywhere” portability, and these design guide-
lines show developers how the pieces fit together to make up complete
FOREWORD xv
applications. The key J2EE specifications are published in Java 2 Platform, Enter-
prise Edition : Platform and Components Specifications (also from Addison-Wes-
ley), while supplemental specifications are available at http://java.sun.com/
j2ee. The reference implementation used to create the examples in this book is
available on the Sun Microsystems Java Software Web site at http://
java.sun.com/j2ee/download.html.
Many people contributed to the Java 2 Platform, Enterprise Edition. Mala
Chandra joined the group to lead the server efforts and quickly became the chief
crusader. Her passion and determination carried the project around, over, or
through many obstacles. Jeff Jackson, Connie Weiss, Karen Tegan, and Tom
Kincaid provided exceptional engineering management. Technical leadership
came from many, including Mark Hapner, Vlada Matena, Bill Shannon, Shel
Finkelstein, Eduardo Pelegri-Llopart, Larry Cable, and Nick Kassem. Bill Roth,
Gina Centoni, George Paolini, and Kathy Knutsen kept the Sun crew connected to
the industry.
A staggering list of companies helped build this new server platform—a
“Who’s Who” of the industry; big, small, old and new. BEA Systems, IBM,
Oracle and Sun Microsystems stand out as the companies who worked on nearly
every piece, but they were never alone. Many companies sent their most senior
architects and engineers and their most experienced managers to quickly build a
common platform that set a new standard for ease of development, scalability, and
applicability. They put these new Java platform technologies in their products,
both old and new. The most widely deployed databases and the newest develop-
ment tools from Silicon Valley startups now share the same interfaces. We are all
the beneficiaries of their foresight and commitment.
In many ways, this book represents the culmination of these collective efforts.
Designing Enterprise Applications with the Java 2 Platform, Enterprise Edition
effectively demonstrates how this new platform simplifies and streamlines the
design, development, and deployment of a new generation of enterprise applica-
tions.
Jon Kannegaard
Vice President and Deputy Director
Sun Microsystems Laboratories
Mountain View, California
March 20, 2000
xvii
Preface
THIS book describes a standard approach to designing multitier enterprise appli-
cations with the Java™ 2 Platform, Enterprise Edition. The book does not contain
information on how to use individual J2EE™ technologies to develop applica-
tions, but rather focuses on guidelines for distributing application functionality
across tiers and choosing among design options within each tier.
The book describes the principles and technologies employed in building J2EE
applications and the specific approach adopted by a sample application. Striking a
balance between specificity on the one hand, and articulating broader principles
on the other, is never easy. The hope is that the principles presented are both con-
sistent with and complement the sample application documented in the book.
This book is most relevant to IT managers, system architects, and enterprise
application developers considering a transition to or intending to use the J2EE plat-
form or vendors providing J2EE products.
How This Book Is Organized
This book contains the following chapters:
• Chapter 1, “Introduction,” discusses challenges in building enterprise appli-
cations and describes how the J2EE platform addresses those challenges. The
chapter also discusses application scenarios that the J2EE platform supports.
• Chapter 2, “J2EE Platform Technologies,” provides an overview of the
component, service, and communication technologies supported by the J2EE
platform.
• Chapter 3, “The Client Tier,” presents implementation options for J2EE cli-
ents and provides guidelines for choosing among these options.
• Chapter 4, “The Web Tier,” describes technologies available for supporting
development in the Web tier. It includes guidelines and techniques for using
J2EE Web components and describes several Web application architectures.
• Chapter 5, “The Enterprise JavaBeans Tier,” describes the capabilities of
PREFACExviii
the EJB tier of the J2EE platform and discusses design choices for implement-
ing business logic.
• Chapter 6, “The Enterprise Information System Tier,” describes recom-
mended approaches for accessing enterprise information systems and how J2EE
components must be configured to access them.
• Chapter 7, “Packaging and Deployment,” describes the capabilities provid-
ed by the J2EE platform for packaging and deploying J2EE applications, pro-
vides heuristics and practical tips on how to use these capabilities, and
provides recommendations to the vendors who provide deployment tools.
• Chapter 8, “Transaction Management,” describes the transaction services
provided by the J2EE platform and provides recommendations on how to best
use those services.
• Chapter 9, “Security,” describes the mapping of the J2EE security model to
enterprise computing environments and infrastructures.
• Chapter 10, “The Sample Application,” illustrates the J2EE programming
model in the context of an in-depth description of a multitier J2EE application.
• “Glossary,” is a list of words and phrases found in this book and their defini-
tions.
Obtaining the Sample Application
You can download the sample application described in this book from:
http://java.sun.com/j2ee/download.html
The sample application requires a J2EE v1.2 compliant platform on which to
run. From the sample application download page you can also download Sun’s
J2EE SDK, a freely available implementation of the J2EE v1.2 platform.
Related Information
Pointers to J2EE documentation can be found at:
http://java.sun.com/j2ee/docs.html
PREFACE xix
For information on how to use the J2EE SDK to construct multitier enterprise appli-
cations refer to the J2EE Developer’s Guide, available at:
http://java.sun.com/j2ee/j2sdkee/techdocs/index.html
The J2EE technologies cited in this book are described in their specifications:
• Java™ 2 Platform, Enterprise Edition Specification, Version 1.2 (J2EE spec-
ification). Copyright 1999, Sun Microsystems, Inc. Available at http://ja-
va.sun.com/j2ee/download.html.
• Java™ 2 Platform, Standard Edition, Version 1.2.2 (J2SE specification).
Copyright 1993-99, Sun Microsystems, Inc. Available at http://ja-
va.sun.com/products/jdk/1.2/docs/api/index.html.
• Java™ Servlet Specification, Version 2.2 (Servlet specification). Copyright
1998, 1999, Sun Microsystems, Inc. Available at http://java.sun.com/prod-
ucts/servlet.
• JavaServer Pages™ Specification, Version 1.1 (JSP specification). Copyright
1998, 1999, Sun Microsystems, Inc. Available at http://java.sun.com/prod-
ucts/jsp.
• Enterprise JavaBeans™ Specification, Version 1.1 (EJB specification). Copy-
right 1998, 1999, Sun Microsystems, Inc. Available at http://java.sun.com/
products/ejb.
• JDBC™ 2.0 API (JDBC specification). Copyright 1998, 1999, Sun Microsys-
tems, Inc. Available at http://java.sun.com/products/jdbc.
• JDBC™ 2.0 Standard Extension API (JDBC extension specification). Copy-
right 1998, 1999, Sun Microsystems, Inc. Available at http://java.sun.com/
products/jdbc.
• Java™ Transaction API, Version 1.0.1 (JTA specification). Copyright 1998,
1999, Sun Microsystems, Inc. Available at http://java.sun.com/products/
jta.
• Java™ Transaction Service, Version 0.95 (JTS specification). Copyright
1997-1999, Sun Microsystems, Inc. Available at http://java.sun.com/prod-
ucts/jts.
• Java Naming and Directory Interface™, Version 1.2 (JNDI specification).
PREFACExx
Copyright 1998, 1999, Sun Microsystems, Inc. Available at http://ja-
va.sun.com/products/jndi.
• Java IDL. Copyright 1993-99, Sun Microsystems, Inc. Available at http://
java.sun.com/products/jdk/1.2/docs/guide/idl/index.html.
• RMI over IIOP 1.0.1. Available at http://java.sun.com/products/rmi-iiop.
• Java™ Message Service, Version 1.0.2 (JMS specification). Copyright 1998,
Sun Microsystems, Inc. Available at http://java.sun.com/products/jms.
• JavaMail™ API Design Specification, Version 1.1 (JavaMail specification).
Copyright 1998, Sun Microsystems, Inc. Available at http://java.sun.com/
products/javamail.
• JavaBeans™ Activation Framework Specification, Version 1.0.1 (JAF speci-
fication). Copyright 1998, Sun Microsystems, Inc. Available at http://ja-
va.sun.com/beans/glasgow/jaf.html.
Typographic Conventions
Table 1 describes the typographic conventions used in this book.
Table 1 Typographic Conventions
Typeface or
Symbol Meaning Example
AaBbCc123 The names of commands, files,
and directories; interface, class,
method, and deployment
descriptor element names;
programming language
keywords
Edit the file Main.jsp.
How to retrieve a UserTransaction
object.
Specify the resource-ref element.
AaBbCc123 Variable name The files are named XYZfile.
AaBbCc123 Book titles, new words or terms,
or words to be emphasized
Read Chapter 6 in User’s Guide. These
are called class options. You must be
root to do this.
PREFACE xxi
Acknowledgments
This book is the result of many people’s efforts.
Each Enterprise Team member had primary responsibility for one chapter and
made significant contributions to other chapters. In addition, Danny Coward wrote
the initial draft of the deployment chapter.
The authors of the J2EE specifications and the developers of the reference
implementation provided useful input at various points during the development of
the J2EE programming model.
We are indebted to Rick Cattell, Bill Shannon, Mark Hapner, John Crupi,
Sean Brydon, and many other reviewers who provided feedback on early versions
of the manuscript.
Jim Inscore and Stephanie Bodoff provided editorial oversight of this project.
About the Author
NICHOLAS KASSEM is a Senior Staff Engineer with Sun Microsystems and has
influenced and had responsibility for a number of technologies and initiatives within
Java Software including the Java Web Server, Java Embedded Server, the Servlet API,
JavaServer Pages, Java Message Queuing, and the J2EE programming model. He is cur-
rently leading the XML Messaging initiative.
Nicholas has over twenty years industry experience and has held senior engineer-
ing and management positions at Philips (Data Systems) and the Santa Cruz Opera-
tion. He has had direct responsibility for a wide variety of engineering projects
including the development of Data Communications Gateway Hardware (DISOSS),
Novell and Lan Manager protocol stacks, and an implementation of OSF DCE on
SCO UNIX. He is an Engineering Graduate of Birmingham University in the UK.
1
C H A P T E R 1
Introduction
by Nicholas Kassem
THE Internet and World Wide Web represent a foundation on which enterprises
are working to build an information economy. In this economy, information takes on
as much value as goods and services, and becomes a vital part of the market. The
information economy challenges today’s enterprises to radically re-think the way
they do business.
Predictions about the future of this economy range from glowing scenarios of
dynamic new business, industrial, and financial environments capable of unlim-
ited expansion, to gloom and doom prophecies of overinflated expectations and
unsustainable hypergrowth. Whatever the predictions, the reality is that enter-
prises have always tried to gain a competitive advantage by any reasonable means
at their disposal, including the latest technologies. This is a natural survival
instinct: all viable enterprises, including for-profit, non-profit, and government
institutions, continuously look for ways to keep pace by adopting such changes.
Complacent organizations routinely fall by the wayside, while the innovators
work to transform new challenges into business success.
In the information economy, information assets take on far-reaching strategic
value to an organization. The ability to capitalize on this value is key to success.
Organizations that succeed will do so by increasing their productivity in moving
information into the marketplace.
While these may appear to be new challenges, in many ways the Internet and
World Wide Web only intensify a challenge that has long faced information tech-
nology professionals: the demand for responsive management of information
assets. The initial response to this demand was to ensure that all critical business
functions were effectively managed by computerized systems. More recently, the
response has been to strive for greater integration among these systems, and
CHAPTER 1 INTRODUCTION2
increased ability to correlate data from disparate sources into information that
serves specific strategic needs. Corporate mergers, acquisitions, and partnerships
have provided additional incentive for organizations to integrate such information.
Distributed custom applications are the packages in which an organization
delivers information as a commodity. Custom applications add value to and
extract value from the information assets of an organization. They allow IT orga-
nizations to target specific functionality to specific user needs. By making infor-
mation available within an organization, they add strategic value to the
management and planning processes. By selectively projecting information assets
outside the organization, they enable exchanges that are mutually valuable to cus-
tomers, suppliers, and the organization itself.
In the competitive environment of the information economy, response time is
key to the value of custom applications to the enterprise. Organizations need to
quickly develop and deploy custom applications, and to easily refine and enhance
them to improve their value. They need ways to simply and efficiently integrate
these applications with existing enterprise information systems, and to scale them
effortlessly to meet changing demands. All these factors affect an organization’s
ability to respond quickly to changes in the competitive environment.
The goal of the JavaTM 2 Platform, Enterprise Edition (J2EETM platform) is to
define a standard of functionality that helps meet these challenges and thus
increases the competitiveness of enterprises in the information economy. The
J2EE platform supports distributed applications that take advantage of a wide
range of new and evolving technologies, while simplifying development through a
component-based application model. The J2EE model supports applications
ranging from traditional client-server applications delivered over corporate intra-
nets to e-commerce Web sites on the Internet.
In presenting the J2EETM Blueprints programming model, this book hopes to
provide enterprise application developers with a strategic perspective on the chal-
lenges of the information economy, and a methodical exploration of ways the
J2EE platform supports custom applications to meet a reasonably broad range of
application requirements. The underlying theme of this discussion is that the J2EE
platform provides a single, unified standard that enhances the opportunity for
enterprises to project their business information systems beyond their historical
borders, while avoiding risks inherent in the task.
This book approaches the J2EE Blueprints programming model by taking a
logical view of enterprise platforms and suggesting ways to partition application
functionality to use the technologies provided by the J2EE platform most effec-
tively. The intent is to divide the problem of architecting and developing multitier
CHALLENGES OF ENTERPRISE APPLICATION DEVELOPMENT 3
applications with J2EE into manageable portions, then apply appropriate technol-
ogies to the portions, leading to more maintainable and scalable solutions. In the
process, certain simplifying assumptions are made, not to trivialize certain factors,
but to focus on the essential J2EE theme. Note that none of the statements in this
book should be interpreted as mandates or requirements, but rather as advice, sug-
gestions, and simple recommendations.
1.1 Challenges of Enterprise Application Development
While timing has always been a critical factor to adopting new technologies, the
accelerated pace inherent in a virtual, information-driven business model has put
even greater emphasis on response times. To leverage Internet economics, it’s
imperative not only to project enterprise systems into various client channels, but to
do so repeatedly and in a timely manner, with frequent updates to both information
and services. The principal challenge is therefore one of keeping up with the Inter-
net’s hyper-competitive pace while maintaining and leveraging the value of existing
business systems. In this environment, timeliness is absolutely critical in gaining
and maintaining a competitive edge. A number of factors can enhance or impede an
organization’s ability to deliver custom enterprise applications quickly, and to maxi-
mize their value over their lifetime.
1.1.1 Programming Productivity
The ability to develop and deploy applications is key to success in the information
economy. Applications need to go quickly from prototype to production, and to con-
tinue evolving even after they are deployed.
Productivity is thus vital to responsive application development. Providing
application development teams with standard means to access the services
required by multitier applications, and standard ways to support a variety of cli-
ents, can contribute to both responsiveness and flexibility.
One destabilizing factor in Internet and other distributed computing applica-
tions is the current divergence of technologies and programming models. Histori-
cally (in Web terms), technologies such as HTML and CGI have provided a
mechanism for distributing dynamic content, while backend systems such as
transaction processors and database management systems have provided con-
trolled access to the data to be presented and manipulated. These technologies
present a diversity of programming models, some based on well-defined stan-
CHAPTER 1 INTRODUCTION4
dards, others on more ad-hoc standards, and others still on proprietary architec-
tures.
With no single application model, it can be difficult for teams to communicate
application requirements effectively and productively. As a result, the process of
architecting applications becomes more complex. What’s more, the skill sets
required to integrate these technologies aren’t well organized for effective division
of labor. For example, CGI development requires coders to define both content
and layout to appear on a dynamic Web page.
Another complicating factor in application development time is the choice of
clients. While many applications can be distributed to Web browser clients
through static or dynamically generated HTML, others may need to support a spe-
cific type of client, or to support several types of clients simultaneously. The pro-
gramming model needs to support a variety of client configurations, with
minimum effect on basic application architecture or the core business logic of the
application.
1.1.2 Response to Demand
Imagine a brick-and-mortar business trying to increase its customer base by a scale
of 10. How much time and effort would they expend on remodelling storefronts,
building new warehouses, and so on, to keep up? The fact is, the constant rework
would drastically impact their ability to serve the customers they’re trying to attract.
This holds for businesses in the information economy as well. The ability for
applications to scale easily and automatically to accommodate anticipated—or
unexpected—growth is key to achieving the goals. Systems that require any
restructuring or redeployment to scale will impede growth and diminish the com-
pany’s expected performance.
In order to scale effectively, systems need to be designed to handle multiple
client interactions with ease. They need mechanisms for efficient management of
system resources and services such as database connections and transactions.
They need to have access to features such as automatic load balancing without any
effort on the part of the application developer. Applications should be able to run
on any server appropriate to anticipated client volumes, and to easily switch server
configurations when the need arises.
CHALLENGES OF ENTERPRISE APPLICATION DEVELOPMENT 5
1.1.3 Integration with Existing Systems
Much of the data of value to organizations has been collected over the years by
existing information systems. Much of the programming investment resides in
applications on those same systems. The challenge for developers of enterprise
applications is how to reuse and commoditize this value.
To achieve this goal, application developers needs standard ways to access
middle-tier and backend services such as database management systems and
transaction monitors. They also need systems that provide these services consis-
tently, so that new programming models or styles aren’t required as integration
expands to encompass various systems within an enterprise.
1.1.4 Freedom to Choose
Application development responsiveness requires the ability to mix and match solu-
tions to come up with the optimum configuration for the task at hand. Freedom of
choice in enterprise application development should extend from servers to tools to
components.
Choices among server products gives an organization the ability to select con-
figurations tailored to their application requirements. It also provides the ability to
move quickly and easily from one configuration to another as internal and external
demand requires.
Access to the appropriate tools for the job is another important choice. Devel-
opment teams should be able to adopt new tools as new needs arise, including
tools from server vendors and third-party tool developers. What’s more, each
member of a development team should have access to tools most appropriate to
their skill set and contribution.
Finally, developers should be able to choose from a ready market of off-the-
shelf application components to take advantage of external expertise and to
enhance development productivity.
1.1.5 Maintaining Security
Somewhat ironically, projecting information assets to extract their value can jeopar-
dize that very value. Traditionally, IT departments have been able to maintain a rela-
tively high level of control over the environment of both servers and clients. When
information assets are projected into less-protected environments, it becomes
increasingly important to maintain tight security over the most sensitive assets,
while allowing seemingly unencumbered access to others.
CHAPTER 1 INTRODUCTION6
One of the difficulties in integrating disparate systems is providing a unified
security model. Single signon across internal application and asset boundaries is
important to creating a positive user experience with the applications. Security
needs to be compatible with existing mechanisms. In cases where customers need
to access secure information, the mechanisms need to maintain high security (and
user confidence) while remaining as unobtrusive and transparent as possible.
1.2 The Platform for Enterprise Solutions
The J2EE platform represents a single standard for implementing and deploying
enterprise applications. The J2EE platform has been designed through an open pro-
cess, engaging a range of enterprise computing vendors, to ensure that it meets the
widest possible range of enterprise application requirements. As a result, the J2EE
platform addresses the core issues that impede organizations’ efforts to maintain a
competitive pace in the information economy.
1.2.1 J2EE Platform Overview
The J2EE platform is designed to provide server-side and client-side support for
developing enterprise, multitier applications. Such applications are typically config-
ured as a client tier to provide the user interface, one or more middle-tier modules
that provide client services and business logic for an application, and backend enter-
prise information systems providing data management. Figure 1.1 illustrates the
various components and services that make up a typical J2EE environment.
1.2.1.1 Multitier Model
As illustrated, the J2EE platform provides a multitier distributed application model.
This means that the various parts of an application can run on different devices. The
J2EE architecture defines a client tier, a middle tier (consisting of one or more sub-
tiers), and a backend tier providing services of existing information systems. The
client tier supports a variety of client types, both outside and inside of corporate fire-
walls. The middle tier supports client services through Web containers in the Web
tier and supports business logic component services through Enterprise JavaBeansTM
(EJBTM) containers in the EJB tier. The enterprise information system (EIS) tier sup-
ports access to existing information systems by means of standard APIs.
THE PLATFORM FOR ENTERPRISE SOLUTIONS 7
Figure 1.1 J2EE Environment
1.2.1.2 Container-Based Component Management
Central to the J2EE component-based development model is the notion of contain-
ers. Containers are standardized runtime environments that provide specific compo-
nent services. Components can expect these services to be available on any J2EE
platform from any vendor. For example, all J2EE Web containers provide runtime
support for responding to client requests, performing request time processing (such
as invoking JSP or servlet behavior), and returning results to the client. All EJB con-
tainers provide automated support for transaction and life cycle management of EJB
components, as well as bean lookup and other services. Containers also provide
standardized access to enterprise information systems; for example, providing
RDBMS access through the JDBC API.
In addition, containers provide a mechanism for selecting application behav-
iors at assembly or deployment time. Through the use of deployment descriptors
(text files that specify component behavior in terms of well-defined XML tags),
CHAPTER 1 INTRODUCTION8
components can be configured to a specific container’s environment when
deployed, rather than in component code. Features that can be configured at
deployment time include security checks, transaction control, and other manage-
ment responsibilities.
While the J2EE specification defines the component containers that must be
supported, it doesn’t specify or restrict the configuration of these containers. Thus,
both container types can run on a single platform, Web containers can live on one
platform and EJB containers on another, or a J2EE platform can be made up of
multiple containers on multiple platforms.
1.2.1.3 Support for Client Components
The J2EE client tier provides support for a variety of client types, both within the
enterprise firewall and outside. Clients can be offered through Web browsers by
using plain HTML pages, dynamic HTML generated with JavaServer PagesTM
(JSPTM) technology, or Java applets. Clients can also be offered as stand-alone Java
language applications. J2EE clients are assumed to access the middle tier primarily
using Web standards, namely HTTP, HTML, and XML.
To support more complex user interactions, it may be necessary to provide
functionality directly in the client tier. This functionality is typically implemented
as JavaBeansTM components that interact with the service in the middle tier via
servlets. Client-tier JavaBeans components would typically be provided by the
service as an applet that is downloaded automatically into a user’s browser. To
eliminate problems caused by old or non-standard versions of the Java virtual
machine in a user’s browser, the J2EE application model provides special support
for automatically downloading and installing the Java Plug-in.
Client-tier beans can also be contained in a stand-alone application client
written in the Java programming language. In this case, the enterprise would typi-
cally make operating system specific installation programs for the client available
for users to download via their browsers. Users execute the installation file and are
then ready to access the service. Since Java technology programs are portable
across all environments, the service need only maintain a single version of the
client program. Although the client program itself is portable, installation of the
Java technology client typically requires OS-specific code. There are several com-
mercial tools that automate the generation of these OS-specific installation pro-
grams.
If desired, non-Java clients such as Visual Basic programs can present J2EE
services to users. Since the service is presented by servlets in the middle tier to
THE PLATFORM FOR ENTERPRISE SOLUTIONS 9
first-tier clients using the standard HTTP protocol, it is easy to access it from
practically any program running on any operating system.
1.2.1.4 Support for Business Logic Components
In the J2EE platform, middle-tier business logic is implemented in the middle tier as
Enterprise JavaBeans components (also referred to as enterprise beans). Enterprise
beans allow the component or application developer to concentrate on the business
logic while the complexities of delivering a reliable, scalable service are handled by
the EJB server.
The J2EE platform and EJB architecture have complementary goals. The EJB
component model is the backbone of the J2EE programming model. The J2EE plat-
form complements the EJB specification by:
• Fully specifying the APIs that an enterprise bean developer can use to imple-
ment enterprise beans.
• Defining the larger, distributed programming environment in which enterprise
beans are used as business logic components.
1.2.1.5 Support for the J2EE Standard
The J2EE standard is defined through a set of related specifications, key among
these the J2EE specification, the EJB specification, the Servlet specification, and the
JSP specification. Together, these specifications define the architecture described in
this discussion. In addition to the specifications, several other offerings are available
to support the J2EE standard, including the J2EE Compatibility Test Suite and the
J2EE SDK.
The J2EE Compatibility Test Suite (CTS) helps maximize the portability of
applications by validating the specification compliance of a J2EE platform product.
This test suite begins where the basic Java Conformance Kit (JCK) leaves off. The
CTS tests conformance to the Java standard extension API’s not covered by the
JCK. In addition, it tests a J2EE platform’s ability to run standard end-to-end
applications.
The J2EE SDK is intended to achieve several goals. First, it provides an opera-
tional definition of the J2EE platform, used by vendors as the “gold standard” to
determine what their product must do under a particular set of application circum-
stances. It can be used by developers to verify the portability of an application. And
it is used as the standard platform for running the J2EE Compatibility Test Suite.
CHAPTER 1 INTRODUCTION10
Another important role for the J2EE SDK is to provide the developer commu-
nity with a freely available implementation of the J2EE platform to help expedite
adoption of the J2EE standard. Although it is not a commercial product and its
licensing terms prohibit its commercial use, the J2EE SDK is freely available in
binary form to use in developing application demos and prototypes. The J2EE
SDK is also available in source form.
One more word on J2EE standards and portability. The J2EE specifications
have, by design, set the platform-compatibility-bar at a level that’s relatively easy to
clear. Owing to the collaborative way in which the platform specifications have been
developed, it was deemed important to give platform vendors plenty of opportunity
to supply implementations of the J2EE platform. Obvious and unreasonable imple-
mentation hurdles were avoided. For example, there are no restrictions on vendors
adding value to J2EE products by supporting services not defined in the specifica-
tions.
It should therefore not be surprising that J2EE component portability is prima-
rily a function of the dependency a component has on the underlying container.
Components using a vendor-specific feature, that falls outside of the J2EE require-
ments, may have limitations in the area of portability. The J2EE specifications do
however spell out a base set of capabilities that a component can count on. Hence,
there is a minimum cross-container portability that an application should be able to
achieve. Needless to say, an application developer expecting to deploy on a specific
vendor implementation of the J2EE platform, should be able to do so across a wide
range of operating systems and hardware architectures.
1.2.2 J2EE Platform Benefits
With a set of features designed specifically to expedite the process of distributed
application development, the J2EE platform offers several benefits:
• Simplified architecture and development
• Scalability to meet demand variations
• Integration with existing information systems
• Choices of servers, tools, components
• Flexible security model
THE PLATFORM FOR ENTERPRISE SOLUTIONS 11
1.2.2.1 Simplified Architecture and Development
The J2EE platform supports a simplified, component-based development model.
Because it’s based on the Java programming language and the Java 2 Platform, Stan-
dard Edition (J2SETM platform), this model offers Write Once, Run Anywhere port-
ability, supported by any server product that conforms to the J2EE standard.
The component-based J2EE development model can enhance application
development productivity in a number of ways.
Maps easily to application functionality: Component-based application
models map easily and flexibly to the functionality desired from an application.
As the examples presented throughout this book illustrate, the J2EE platform pro-
vides a variety of ways to configure the architecture of an application, depending
on such things as client types required, level of access required to data sources,
and other considerations. Component-based design also simplifies application
maintenance, since components can be updated and replaced independently—new
functionality can be shimmed into existing applications simply by updating
selected components.
Enables assembly- and deploy-time behaviors: Components can expect the
availability of standard services in the runtime environment, and can be dynami-
cally connected to other components providing well-defined interfaces. As a
result, many application behaviors can be configured at the time of application
assembly or deployment, without any recoding required. Component developers
can communicate their requirements to application deployers through specific set-
tings. Tools can automate this process to further expedite development.
Supports division of labor: Components help divide the labor of application
development among specific skill sets, enabling each member of a development
team to focus on his or her ability. Thus, JSP templates can be created by graphic
designers, their behavior by Java programming language coders, business logic by
domain experts, and application assembly and deployment by the appropriate
team members. This division of labor also helps expedite application mainte-
nance. For example, the user interface is the most dynamic part of many applica-
tions, particularly on the Web. With the J2EE platform, graphic designers can
tweak the look and feel of JSP-based user interface components without the need
for programmer intervention.
A number of generic roles are discussed in the J2EE specifications, including
Application Component Provider, Application Assembler, and Application
Deployer. On some development teams, one or two people may perform all these
CHAPTER 1 INTRODUCTION12
roles, while on others, these tasks may be further subdivided into more specific
skill sets (such as user interface designers, programmers, and so on).
1.2.2.2 Scales Easily
J2EE containers provide a mechanism that supports simplified scaling of distributed
applications, without requiring any effort on the part of the application development
team.
Because J2EE containers provide components with transaction support, data-
base connections, life cycle management, and other features that influence perfor-
mance, they can be designed to provide scalability in these areas. For example, by
providing database connection pooling, containers can ensure that clients will
have access to data quickly.
Because the J2EE specifications allow server providers freedom to configure
containers to run on multiple systems, Web containers can be implemented to
perform automatic load balancing as the demand for a particular application fluc-
tuates.
1.2.2.3 Integrating Existing Enterprise Information Systems
The J2EE platform, together with the J2SE platform, includes a number of industry
standard APIs for access to existing enterprise information systems. Basic access to
these systems is provided by the following APIs:
• JDBCTM is the API for accessing relational data from Java.
• The Java Transaction API (JTA) is the API for managing and coordinating
transactions across heterogeneous enterprise information systems.
• The Java Naming and Directory InterfaceTM (JNDI) is the API for accessing in-
formation in enterprise name and directory services.
• The Java Message Service (JMS) is the API for sending and receiving messag-
es via enterprise messaging systems like IBM MQ Series and TIBCO Rendez-
vous.
• JavaMailTM is the API for sending and receiving email.
• Java IDL is the API for calling CORBA services.
THE PLATFORM FOR ENTERPRISE SOLUTIONS 13
In addition, specialized access to enterprise resource planning and mainframe
systems such as IBM’s CICS and IMS will be provided in future versions of J2EE
through the Connector architecture. Since each of these systems is highly complex
and specialized, they each require unique tools and support to ensure utmost sim-
plicity to application developers. As J2EE evolves, enterprise beans will be able to
combine the use of connector access objects and service APIs with middle-tier
business logic to accomplish their business functions.
1.2.2.4 Choice of Servers, Tools, and Components
The J2EE standard and J2EE brand are central to creating a marketplace for servers,
tools, and components. The J2EE brand on a server product ensures the kind of
ubiquity that’s fundamental to the goals of the J2EE platform. In addition, J2EE
standards ensure a lively marketplace for tools and components.
A range of server choices: Application development organizations can
expect J2EE branded platforms from a variety of vendors, providing a range of
choices in hardware platforms, operating systems, and server configurations. This
ensures that businesses get a choice of servers appropriate to the strategic purpose
of the applications they need.
Designed for tool support: Both EJB and JSP components are designed to be
manipulated by graphical development tools, and to allow automating many of the
application development tasks traditionally requiring the ability to write and
debug code. Both J2EE server providers and third-party tool developers can
develop tools that conform to J2EE standards and support various application
development tasks and styles. Application developers get a choice of tools to
manipulate and assemble components, and individual team members may choose
tools that suit their specific requirements best.
A marketplace for components: Component-based design ensures that
many types of behavior can be standardized, packaged, and reused by any J2EE
application. Component vendors will provide a variety of off-the-shelf component
solutions, including accounting beans, user interface templates, and even vertical
market functionality of interest in specific industries. Application architects get a
choice of standardized components to handle common or specialized tasks.
The J2EE standard and associated branding programming ensure that solu-
tions are compatible. By setting the stage for freedom of choice, J2EE makes it
possible to develop with confidence that the value of your investment will be pro-
tected.
CHAPTER 1 INTRODUCTION14
1.2.2.5 Simplified, Unified Security Model
The J2EE security model is designed to support single signon access to application
services. Component developers can specify the security requirements of a compo-
nent at the method level, to ensure that only users with appropriate permissions can
access specific data operations. While the EJB and Java Servlet APIs both provide
mechanisms for building security checks into code, the basic mechanism for match-
ing users with roles (groups of users having specific permissions) is performed
entirely at application deployment time. This provides both greater flexibility and
better security control.
1.3 J2EE Application Scenarios
The following sections present a number of application scenarios, setting the stage
for a detailed discussion of the sample application. In reviewing the J2EE specifica-
tions, a large number of application scenarios could be considered. Indeed, the spec-
ifications tend to embrace and encourage diversity. The J2EE specifications and
technologies, can by definition, make few assumptions about how precisely the
APIs are going to be used to deliver application-level functionality. The application-
level decisions and choices are ultimately a trade-off, between functional richness
and complexity.
The J2EE programming model needs to embrace application scenarios that
treat the Web container, and the EJB container as optional logical entities. Figure
1.2 reflects some key scenarios, including those where either the Web container or
the EJB container, and potentially both, are bypassed.
J2EE APPLICATION SCENARIOS 15
Figure 1.2 J2EE Application Scenarios
The sample application reflects a multitier application model. This decision
assumes the presence of both a Web container and an EJB container. The follow-
ing enterprise requirements heavily influenced the choices made:
• The need to make rapid and frequent changes to the “look” of the application.
• The need to partition the application along the lines of presentation and busi-
ness logic so as to increase modularity.
• The need to simplify the process of assigning suitably trained human resources
to accomplish the development task such that work can proceed along relative-
ly independent but cooperating tracks.
• The need to have developers familiar with back-office applications unbur-
dened from GUI and graphic design work, for which they may not be ideally
qualified.
• The need to have the necessary vocabulary to communicate the business logic
to teams concerned with human factors and the aesthetics of the application.
• The ability to assemble back-office applications using components from a va-
riety of sources, including off-the-shelf business logic components.
CHAPTER 1 INTRODUCTION16
• The ability to deploy transactional components across multiple hardware and
software platforms independently of the underlying database technology.
• The ability to externalize internal data without having to make many assump-
tions about the consumer of the data and to accomplish this in a loosely cou-
pled manner.
Clearly relaxing any or all of these requirements would influence some of the
application-level decisions and choices that a designer would make. The J2EE
programming model takes the approach that it is highly desirable to engineer a
3-tier application such that the migration to a future multitier architecture is sim-
plified through component reusability. Although it is reasonable to speak of
“throw-away” presentation logic (that is, applications with a look and feel that
ages rapidly), there is still significant inertia associated with business logic. This
is even more true in the case of database schemas and data in general. It is fair to
say that as one moves further away from the EIS resources the volatility of the
application code increases dramatically; that is, the application “shelf-life” drops
significantly.
In summary, the J2EE programming model promotes a model that anticipates
growth, encourages component-oriented code reusability, and leverages the
strengths of inter-tier communication. It is the tier integration that lies at the heart
of the J2EE programming model.
Figure 1.2 illustrates a number of application scenarios that a J2EE product
should be capable of supporting. From a J2EE perspective, there is no implicit
bias favoring one application scenario over another. However, a J2EE product
should not preclude supporting any and all of these scenarios. It is worth consider-
ing the scenarios individually and elaborating on the technologies and protocols
relevant to an application developer.
1.3.1 Multitier Application Scenario
Figure 1.3 illustrates an application scenario in which the Web container hosts Web
components that are almost exclusively dedicated to handling a given application’s
presentation logic. The delivery of dynamic Web content to the client is the respon-
sibility of JSP pages (supported by servlets). The EJB container hosts application
components that, on the one hand, respond to requests from the Web tier, and on the
other hand, access the EIS resources. The ability to decouple the accessing of data
from issues surrounding end-user interactions is a strength of this particular sce-
nario. For one, the application is implicitly scalable. But more importantly, the
J2EE APPLICATION SCENARIOS 17
application back-office functionality is relatively isolated from the end-user look
and feel.
Figure 1.3 Multitier Application
It is worth noting that XML is included as an integral part of this scenario.
The role of XML data messaging will be expanded on in subsequent chapters, but
the ability to both produce and consume XML data messages in the Web container
is viewed as an extremely flexible way of embracing a diverse set of client plat-
forms. These platforms may range from general purpose XML-enabled browsers
to specialized XML rendering engines targeting vertical solutions. Irrespective of
the specific application area, it is assumed that XML data messages will utilize
HTTP as their communication transport. The term XML data messaging is being
used to denote a programming model where XML is being used to exchange
information as opposed to promoting an object model orthogonal to the Java
object model. The relationship of XML to Java is therefore viewed as highly com-
plementary.
At the Web tier, the question of whether to use JSP pages or servlets comes up
repeatedly. The J2EE programming model promotes JSP technology as the pre-
ferred programming facility within the Web container. JSP pages rely on the
servlet functionality but the J2EE programming model takes the position that JSP
pages are a more natural fit for Web engineers. The Web container is therefore
optimized for the creation of dynamic content destined for Web clients and that
use of JSP technology should be viewed as the norm while the use of servlets will
most likely be the exception.
CHAPTER 1 INTRODUCTION18
1.3.2 Stand-Alone Client Scenario
Figure 1.4 illustrates a stand-alone client scenario.
Figure 1.4 Stand-Alone Clients
From a J2EE programming model perspective, we need to consider three
types of stand-alone clients:
• EJB clients interacting directly with an EJB server, that is enterprise beans
hosted on an EJB container. Such a scenario is illustrated in Figure 1.5. It is
assumed that RMI-IIOP will be used in this scenario and that the EJB server
will access the EIS resources using JDBC (connectors in the future).
Figure 1.5 EJB-Centric Java Client
J2EE APPLICATION SCENARIOS 19
• Stand-alone Java application clients accessing enterprise information system
resources directly using JDBC and potentially even connectors in the future. In
this scenario, presentation and business logic are by definition co-located on
the client platform and may in fact be tightly integrated into a single applica-
tion. This scenario collapses the middle tier into the client platform, and is es-
sentially a client-server application scenario with the associated application
distribution, maintenance, and scalability issues.
• Visual Basic clients consuming dynamic Web content, most likely in the form
of XML data messages. In this scenario, the Web container is essentially han-
dling XML transformations and providing Web connectivity to clients. Presen-
tation logic is assumed to be handled on the client tier. The Web tier can be
designated to handle business logic and directly access the enterprise informa-
tion system resources. Ideally, the business logic is pushed back onto the EJB
server, where the rich component model can be fully leveraged.
1.3.3 Web-Centric Application Scenario
Figure 1.6 illustrates a 3-tier Web-centric application scenario.
Figure 1.6 Web-Centric Application Scenario
There are numerous examples that one could concoct where an EJB server (at
least initially) could be deemed to be an overkill given the problem being tackled.
This is the sledge-hammer-to-crack-a-nut problem. In essence, the J2EE specifica-
tion does not mandate a 2, 3, or multitier application model, nor realistically could
it do so. The point is that it is important to use appropriate tools for a given
problem space.
CHAPTER 1 INTRODUCTION20
The 3-tier Web-centric application scenario is currently in widespread use.
The Web container is essentially hosting both presentation and business logic, and
it is assumed that JDBC (and connectors in the future) will be used to access the
EIS resources.
Figure 1.7 provides a closer look at the Web container in a Web application
scenario.
Figure 1.7 Web Container in a 3-Tier Scenario
It is important to keep in mind that the term Web container is being used here
in a very precise way. For example, if a given J2EE product chooses to implement,
a J2EE server, such that the Web container and the EJB container are co-located
(this assumes that the inter-container communication is optimized in some fashion
and that the implementation details are private), then the J2EE programming
model treats the application deployed on such a platform as essentially a multitier
scenario.
1.3.4 Business-to-Business Scenario
Figure 1.8 illustrates a business-to-business scenario.
This scenario focuses on peer-level interactions between both Web and EJB
containers. The J2EE programming model promotes the use of XML data messag-
ing over HTTP as the primary means of establishing loosely coupled communica-
J2EE APPLICATION SCENARIOS 21
tions between Web containers. This is a natural fit for the development and
deployment of Web-based commerce solutions.
Figure 1.8 Business-to-Business Scenario
The peer-level communications between EJB containers is currently a more
tightly coupled solution most suitable for intranet environments. With the immi-
nent integration of JMS into the J2EE platform, the development of loosely-
coupled intranet solutions will become increasingly practical.
1.3.5 A Note on the MVC Architecture
A brief aside here regarding the subsequent discussions of application scenarios.
Throughout the remainder of this book, the Model-View-Controller (MVC) applica-
tion architecture is used to analyze features of distributed applications. This abstrac-
tion helps in the process of breaking an application up into logical components that
can be architected more easily. This section explores the general features of MVC.
The MVC architecture is a way to divide functionality among objects
involved in maintaining and presenting data so as to minimize the degree of cou-
pling between the objects. The MVC architecture was originally developed to map
the traditional input, processing, and output tasks to the graphical user interaction
model. However, it is straightforward to map these concepts into the domain of
multitier Web-based enterprise applications.
In the MVC architecture, the Model represents application data and the busi-
ness rules that govern access and modification of this data. Often the model serves
CHAPTER 1 INTRODUCTION22
as a software approximation to a real world process and simple real world model-
ing techniques apply when defining the model.
The model notifies views when it changes and provides the ability for the
view to query the model about its state. It also provides the ability for the control-
ler to access application functionality encapsulated by the model.
A View renders the contents of a model. It accesses data from the model and
specifies how that data should be presented. When the model changes, it is the
view’s responsibility to maintain consistency in its presentation. The view for-
wards user gestures to the controller.
A Controller defines application behavior; it interprets user gestures and maps
them into actions to be performed by the model. In a stand-alone GUI client, these
user gestures could be button clicks or menu selections. In a Web application, they
appear as GET and POST HTTP requests to the Web tier. The actions performed by
the model include activating business processes or changing the state of the
model. Based on the user gesture and the outcome of the model commands, the
controller selects a view to be rendered as part of the response to this user request.
There is usually one controller for each set of related functionality. For exam-
ple, human resources applications typically have a controller for managing
employee interactions and a controller for human resources personnel.
Figure 1.9 depicts the relationships between the model, view, and controller
portions of an MVC application.
1.4 Summary
The challenge to IT professionals today is to efficiently develop and deploy distrib-
uted applications for use on both corporate intranets and over the Internet. Compa-
nies that can do this effectively will gain strategic advantage in the information
economy.
The Java 2 Platform, Enterprise Edition is a standard set of Java technologies
that streamline the development, deployment, and management of enterprise
applications. The J2EE platform is functionally complete in the sense that it is
possible to develop a large class of enterprise applications using only the J2EE
technologies. Applications written for the J2EE platform will run on any J2EE-
compatible server. The J2EE platform provides a number of benefits for organiza-
tions developing such applications, including a simplified development model,
SUMMARY 23
industrial-strength scalability, support for existing information systems, choices in
servers, tools, and components, and a simple, flexible security model.
Figure 1.9 Relationships Between MVC Participants
By providing the ability to deploy component-oriented enterprise applications
across multiple computing tiers in a platform-neutral manner, J2EE can give fast-
moving enterprises a significant and measurable competitive edge.
About the Author
STEPHANIE BODOFF is a staff writer at Sun Microsystems. She has been involved
with object-oriented enterprise software since graduating from Columbia University
with an M.S. in electrical engineering. For several years she worked as a software engi-
neer on distributed computing and telecommunications systems and object-oriented
software development methods. During that period she co-authored Object-Oriented
Software Development: The Fusion Method, Prentice Hall. For the past 4 years
Stephanie has concentrated on technical writing, documenting object-oriented data-
bases, application servers, and enterprise application development methods.
25
C H A P T E R 2
J2EE Platform Technologies
by Stephanie Bodoff
THE J2EE platform specifies technologies to support multitier enterprise applica-
tions. These technologies fall into three categories: component, service, and com-
munication.
The component technologies are those used by developers to create the essen-
tial parts of the enterprise application, namely the user interface and the business
logic. The component technologies allow the development of modules that can be
reused by multiple enterprise applications. The component technologies are sup-
ported by J2EE platform system-level services which simplify application program-
ming and allow components to be customized to use resources available in the
environment in which they are deployed.
Since most enterprise applications require access to existing enterprise informa-
tion systems, the J2EE platform supports APIs that provide access to database,
transaction, naming and directory, and messaging services. Finally, the J2EE plat-
form provides technologies that enable communication between clients and
servers and between collaborating objects hosted by different servers.
This chapter will provide an overview of the J2EE platform technologies.
2.1 Component Technologies
A component is an application-level software unit. In addition to JavaBeans compo-
nents, which are part of the J2SE platform, the J2EE platform supports the follow-
ing types of components: applets, application clients, Enterprise JavaBeansTM
components, and Web components. Applets and application clients run on a client
platform and EJB and Web components run on a server platform.
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES26
All J2EE components depend on the runtime support of a system-level entity
called a container. Containers provide components with services such as life cycle
management, security, deployment, and threading. Because containers manage
these services, many component behaviors can be declaratively customized when
the component is deployed in the container. For example, an Application Compo-
nent Provider can specify an abstract name for a database that an Enterprise Java-
Beans component needs to access and a Deployer will link that name with the
information (such as a user name and password) needed to access the database in
a given environment.
The following sections provide overviews of the different types of J2EE com-
ponents and containers.
2.1.1 Applets and Application Clients
Applets and application clients are client components that execute in their own Java
virtual machine. An applet container includes support for the applet programming
model. A J2EE client may make use of the Java Plug-in to provide the required
applet execution environment. An application client container provides access to
the J2EE service (see Section 2.3 on page 33) and communication (see Section 2.5
on page 41) APIs. Applets and application clients are covered in Chapter 3.
2.1.2 Web Components
A Web component is a software entity that provides a response to a request. A Web
component typically generates the user interface for a Web-based application. The
J2EE platform specifies two types of Web components: servlets and JavaServer
PagesTM (JSP) pages. The following sections give an overview of Web components.
Web components are discussed in detail in Chapter 4.
2.1.2.1 Servlets
A servlet is a program that extends the functionality of a Web server. Servlets
receive a request from a client, dynamically generate the response (possibly que-
rying databases to fulfill the request), and then send the response containing an
HTML or XML document to the client.
COMPONENT TECHNOLOGIES 27
A servlet developer uses the servlet API to:
• Initialize and finalize a servlet
• Access a servlet’s environment
• Receive requests and send responses
• Maintain session information on behalf of a client
• Interact with other servlets and other components
2.1.2.2 JavaServer Pages Technology
The JavaServer Pages (JSP) technology provides an extensible way to generate
dynamic content for a Web client. A JSP page is a text-based document that
describes how to process a request to create a response. A JSP page contains:
• Template data to format the Web document. Typically the template data uses
HTML or XML elements. Document designers can edit and work with these
elements on the JSP page without affecting the dynamic content. This ap-
proach simplifies development because it separates presentation from dynamic
content generation.
• JSP elements and scriptlets to generate the dynamic content in the Web docu-
ment. Most JSP pages use JavaBeans and/or Enterprise JavaBeans components
to perform the more complex processing required of the application. Standard
JSP actions can access and instantiate beans, set or retrieve bean attributes, and
download applets. JSP is extensible through the development of custom ac-
tions, which are encapsulated in tag libraries.
2.1.2.3 Web Component Containers
Web components are hosted by servlet containers, JSP containers, and Web con-
tainers. In addition to standard container services, a servlet container provides
network services (by which requests and responses are sent), decodes requests, and
formats responses. All servlet containers must support HTTP as a protocol for
requests and responses, but may also support additional request-response protocols
such as HTTPS. A JSP container provides the same services as a servlet container
and an engine that interprets and processes a JSP page into a servlet. A Web con-
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES28
tainer provides the same services as a JSP container and access to the J2EE service
and communication APIs.
2.1.3 Enterprise JavaBeans Components
The Enterprise JavaBeans (EJB) architecture is a server-side technology for devel-
oping and deploying components containing the business logic of an enterprise
application. Enterprise JavaBeans components, termed enterprise beans, are scal-
able, transactional, and multi-user secure. There are two types of enterprise beans:
session beans and entity beans. The following sections give an overview of enter-
prise beans. Enterprise beans are discussed in detail in Chapter 5.
2.1.3.1 Session Beans
A session bean is created to provide some service on behalf of a client and usually
exists only for the duration of a single client-server session. A session bean per-
forms operations such as calculations or accessing a database for the client. While a
session bean may be transactional, it is not recoverable should its container crash.
Session beans can be stateless or can maintain conversational state across
methods and transactions. If they do maintain state, the EJB container manages
this state if the object must be removed from memory. However, the session bean
object itself must manage its own persistent data.
2.1.3.2 Entity Beans
An entity bean is a persistent object that represents data maintained in a data store;
its focus is data-centric. An entity bean can manage its own persistence or it can del-
egate this function to its container. An entity bean can live as long as the data it rep-
resents.
An entity bean is identified by a primary key. If the container in which an
entity bean is hosted crashes, the entity bean, its primary key, and any remote ref-
erences survive the crash.
2.1.3.3 EJB Component Containers
Enterprise beans are hosted by an EJB container. In addition to standard container
services, an EJB container provides a range of transaction and persistence services
and access to the J2EE service and communication APIs.
COMPONENT TECHNOLOGIES 29
2.1.4 Components, Containers, and Services
The J2EE component types and their containers are illustrated in Figure 2.1.
Figure 2.1 J2EE Components and Containers
Containers provide all application components with the J2SE platform APIs,
which include the Java IDL and JDBC 2.0 core enterprise APIs. Table 2.1 lists the
Standard Extension APIs that are available in each type of container. The J2EE
platform APIs are described in Section 2.4 on page 39 and Section 2.5 on page 41.
Table 2.1 J2EE Required Standard Extension APIs
API Applet
Application
Client Web EJB
JDBC 2.0 Extension N Y Y Y
JTA 1.0 N N Y Y
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES30
2.2 Platform Roles
The J2EE platform defines several distinct roles in the application development and
deployment life cycle: J2EE Product Provider, Application Component Provider,
Application Assembler, Deployer, System Administrator, Tool Provider. In general,
the roles are defined to aid in identifying the tasks performed by various parties
during the development, deployment, and running of a J2EE application. However,
while some of these roles, such as System Administrator and Tool Provider, perform
tasks that are common to non-J2EE platforms, other roles have a meaning specific to
the J2EE platform, because the tasks those roles perform are specific to J2EE tech-
nology. In particular, Application Component Providers, Application Assemblers,
and Deployers must configure J2EE components and applications to use J2EE plat-
form services (described in Section 2.3 on page 33).
The roles can be fulfilled by whatever personnel match an organization’s
actual application development and deployment workflow. Thus, each J2EE role
may be performed by a different party or a single party may perform several roles.
For example, a programmer may perform the roles of Application Component
Provider and Application Assembler.
JNDI 1.2 N Y Y Y
Servlet 2.2 N N Y N
JSP 1.1 N N Y N
EJB 1.1 N Ya Yb Y
RMI-IIOP 1.0 N Y Y Y
JMS 1.0 N Y Y Y
JavaMail 1.1 N N Y Y
JAF 1.0 N N Y Y
a Application clients can only make use of the enterprise bean client APIs.
b Servlets and JSP pages can only make use of the enterprise bean client
APIs.
Table 2.1 J2EE Required Standard Extension APIs (continued)
API Applet
Application
Client Web EJB
PLATFORM ROLES 31
The following sections define the J2EE platform roles. Subsets of some of
these roles are defined in the EJB (Enterprise Bean Provider, EJB Container Pro-
vider, EJB Server Provider), JSP (JSP Container Provider), and Servlet (Applica-
tion Developer, Servlet Container Provider, Web Container Provider, Web Server
Provider) specifications.
2.2.1 J2EE Product Provider
A J2EE Product Provider, typically an operating system vendor, database system
vendor, application server vendor, or a Web server vendor, implements a J2EE
product providing the component containers, J2EE platform APIs, and other fea-
tures defined in the J2EE specification. A J2EE product is free to implement the
interfaces that are not specified by the J2EE specification in an implementation-spe-
cific way.
A J2EE Product Provider provides application deployment and management
tools. Deployment tools enable a Deployer (described in Section 2.2.4 on page 32)
to deploy components on the J2EE product. Management tools allow a System
Administrator (described in Section 2.2.5 on page 32) to manage the J2EE
product and the applications deployed on the J2EE product. The form of these
tools is not prescribed by the J2EE specification.
2.2.2 Application Component Provider
Application Component Providers produce the building blocks of a J2EE applica-
tion. They typically have expertise in developing reusable components as well as
sufficient business domain knowledge. Application Component Providers need
not know anything about the operational environment in which their components
will be used. There are multiple roles for Application Component Providers, includ-
ing HTML document designers, document programmers, enterprise bean develop-
ers, and so on. These roles use tools provided by a Tool Provider (described in
Section 2.2.6 on page 32) to produce J2EE components and applications.
2.2.3 Application Assembler
An Application Assembler takes a set of components developed by Application
Component Providers and assembles them into a complete J2EE application. Their
expertise lies in providing solutions for a specific problem domain, for example,
the financial industry. Application Assemblers may not be familiar with the
source code of the components that they use, but they use declarative descriptors
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES32
for the components in order to know how to build applications from them. Like
Application Component Providers, they need not know anything about the opera-
tional environment in which their applications will be used. An Application
Assembler will generally use GUI tools provided by either a Product Provider or
Tool Provider. An Application Assembler is responsible for providing assembly
instructions describing external dependencies of the application that the Deployer
must resolve in the deployment process.
2.2.4 Deployer
A Deployer, an expert in a specific operational environment, is responsible for
deploying J2EE components and applications into that environment. A Deployer
uses tools supplied by the J2EE Product Provider to perform deployment tasks. A
Deployer installs components and applications into a J2EE server and configures
components and applications so as to resolve all the external dependencies
declared by the Application Component Provider and Application Assembler.
2.2.5 System Administrator
A System Administrator is responsible for the configuration and administration of
an enterprise’s computing and networking infrastructure. A System Administrator is
also responsible for overseeing the runtime well-being of the deployed J2EE appli-
cations. The System Administrator typically uses runtime monitoring and manage-
ment tools provided by the J2EE Product Provider to accomplish these tasks.
2.2.6 Tool Provider
A Tool Provider provides tools used for the development and packaging of applica-
tion components. A variety of tools are anticipated, corresponding to the many com-
ponent types supported by the J2EE platform. Platform independent tools can be
used for all phases of development up to the deployment of an application. Platform
dependent tools are used for deployment, management, and monitoring of applica-
tions. Future versions of the J2EE specification may define more interfaces that
allow such tools to be platform independent.
PLATFORM SERVICES 33
2.3 Platform Services
J2EE platform services simplify application programming and allow components
and applications to be customized at deployment time to use resources available in
the deployment environment. This section gives a brief overview of the J2EE plat-
form naming, deployment, transaction, and security services.
2.3.1 Naming Services
J2EE naming services provide application clients, enterprise beans, and Web com-
ponents with access to a JNDI (described in Section 2.4.3 on page 40) naming envi-
ronment. A naming environment allows a component to be customized without the
need to access or change the component’s source code. A container implements the
component’s environment, and provides it to the component as a JNDI naming con-
text.
A J2EE component locates its environment naming context using JNDI inter-
faces. A component creates a javax.naming.InitialContext object and looks up
the environment naming context in InitialContext under the name
java:comp/env. A component’s naming environment is stored directly in the envi-
ronment naming context, or in any of its direct or indirect subcontexts.
A J2EE component can access named system-provided and user-defined
objects. The names of system-provided objects, such as JTA UserTransaction
objects, are stored in the environment naming context, java:comp/env. The J2EE
platform allows a component to name user-defined objects, such as enterprise
beans, environment entries, JDBC DataSource objects, and message connections.
An object should be named within a subcontext of the naming environment
according to the type of the object. For example, enterprise beans are named
within the subcontext java:comp/env/ejb and JDBC DataSource references in the
subcontext java:comp/env/jdbc.
2.3.2 Deployment Services
J2EE deployment services allow components and applications to be customized at
the time they are packaged and deployed.
J2EE applications are deployed as a set of nested units. Each unit contains a
deployment descriptor, an XML-based text file whose elements declaratively
describe how to assemble and deploy the unit into a specific environment. Deploy-
ment descriptors contain many elements related to customizing J2EE platform
services such as transactions and security.
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES34
The following sections give an overview of J2EE platform deployment ser-
vices. Deployment services are discussed in detail in Chapter 7.
2.3.2.1 Deployment Units
A J2EE application consists of one or more J2EE modules and one J2EE applica-
tion deployment descriptor. An application deployment descriptor contains a list of
the applications’s modules and information on how to customize the application. A
J2EE application is packaged as a Java Archive (JAR) file with an .ear (Enterprise
ARchive) extension.
A J2EE module consists of one or more J2EE components for the same con-
tainer type and one component deployment descriptor of that type. A component
deployment descriptor contains declarative data to customize the components in
the module. A J2EE module without an application deployment descriptor can be
deployed as a stand-alone J2EE module.
The three types of J2EE modules are:
• Enterprise JavaBeans modules contain class files for enterprise beans and an
EJB deployment descriptor. EJB modules are packaged as JAR files with a .jar
extension.
• Web modules contain JSP files, class files for servlets, GIF and HTML files,
and a Web deployment descriptor. Web modules are packaged as JAR files
with a .war (Web ARchive) extension.
• Application client modules contain class files and an application client deploy-
ment descriptor. Application client modules are packaged as JAR files with a
.jar extension.
2.3.2.2 Platform Roles in the Deployment Process
Each J2EE platform role performs specific activities related to deployment. An
Application Component Provider specifies component deployment descriptor ele-
ments and packages components into modules. An Application Assembler
resolves references between modules and assembles modules into a single deploy-
ment unit. A Deployer creates links between entities referred to by the application
and entities in the deployment environment.
PLATFORM SERVICES 35
2.3.3 Transaction Services
Transactions divide an application into a series of indivisible or “atomic” units of
work. A system that supports transactions ensures that each unit fully completes
without interference from other processes. If the unit can be completed in its
entirety, it is committed. Otherwise, the system completely undoes (rolls back)
whatever work the unit had performed. Transactions simplify application develop-
ment because they free the Application Component Provider from the complex
issues of failure recovery and multi-user programming.
Transactions, as provided by the J2EE platform, have the following character-
istics:
• J2EE transactions are flat. A flat transaction cannot have any child (nested)
transactions.
• The J2EE platform implicitly handles many transaction details, such as propa-
gating information specific to a particular transaction instance, and coordinat-
ing among multiple transaction managers.
The following sections give an overview of J2EE platform transaction services.
Transaction services are discussed in detail in Chapter 8.
2.3.3.1 Accessing Transactions
A JTA transaction is a transaction that can span multiple components and
resource managers. A resource manager local transaction is a transaction that is
specific to a particular enterprise information system connection.
JTA transactions are created and managed using the javax.transac-
tion.UserTransaction interface. Different types of components access User-
Transaction objects in different ways:
• Enterprise beans provide a mechanism for JTA transactions to be started auto-
matically by their containers. Enterprise beans that use bean-managed transac-
tions (described in Section 2.3.3.3 on page 36) use the method
EJBContext.getUserTransaction to look up the UserTransaction object.
• Applets and application clients may or may not be able to directly access a
UserTransaction object depending on the capabilities provided by the con-
tainer. However, they can always invoke enterprise beans that use a User-
Transaction object.
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES36
• Web components use JNDI to look up the UserTransaction object.
A resource manager local transaction is created and managed in a manner spe-
cific to a particular connection. For example, each SQL statement executed on a
JDBC connection has its own transaction.
2.3.3.2 Web Component Transactions
Web components (JSP pages and servlets) are not designed to be transactional.
Because of this, Application Component Providers should only perform transac-
tional work directly in Web components on a very limited basis. Preferably, an
Application Component Provider should delegate transactional work to the appro-
priate enterprise beans. When an enterprise bean is used to perform transactional
work, the enterprise bean or container takes care of properly setting up the transac-
tion.
Nevertheless, there are times when a Web component may need to directly
demarcate transactions. It can do so using the javax.transaction.UserTransac-
tion interface. You should however, be aware of limitations in transaction propa-
gation and state isolation, as described in the following discussions.
Transaction Propagation
Transactions are propagated from a Web component to an enterprise bean only
when the Web component starts the transaction using the UserTransaction inter-
face. Since Web components are server-side components, Web browsers and other
clients don’t have direct access to transactions and so a transaction initiated by a
Web component cannot be propagated from the client of the component or between
Web components and transactional resources such as JDBC connections.
State Isolation
A Web component can keep state for the lifetime of a client session or component.
However, because Web components are not transactional components, their state
cannot be isolated based on transactions. For example, separate servlets will see the
same state of a client session even if they each start their own transaction.
2.3.3.3 Enterprise Bean Transactions
The J2EE platform provides two styles of transaction demarcation for enterprise
beans: bean-managed and container-managed.
PLATFORM SERVICES 37
With bean-managed transaction demarcation, the enterprise bean is required
to manage all aspects of a transaction. This entails operations such as:
• Creating the transaction object
• Explicitly starting the transaction
• Completing the transaction. There are two basic ways of completing a transac-
tion:
■ Committing the transaction when all updates are completed.
■ Rolling back the transaction if an error occurred.
With container-managed transaction demarcation, the EJB container handles
transaction management. The container performs the transaction demarcation
based on the Application Assembler’s deployment instructions; it handles starting
and ending the transaction, plus it maintains the transaction context throughout
the life of the transaction object. This greatly simplifies an Application Compo-
nent Provider’s responsibilities and tasks, especially for transactions in distributed
environments.
Session beans, both stateful and stateless varieties, can use either container- or
bean-managed transactions. However, a bean cannot use both types of transaction
at the same time. The Application Component Provider decides the type of trans-
action demarcation that a session bean will use and must declare the transaction
style via attributes in the enterprise bean’s deployment descriptor. The attributes
indicate whether the bean or container will manage the bean’s transactions and, if
the latter, how the container will manage the transactions. Entity beans can only
use container-managed transaction demarcation.
2.3.4 Security Services
The J2EE platform security services are designed to ensure that resources are
accessed only by users authorized to use them. Access control involves two steps:
1. Authentication—An entity must establish its identity through authentication.
It typically does so by providing authentication data (such as a name and pass-
word). An entity that can be authenticated is called a principal. A principal can
be a user or another program. Users are typically authenticated by logging in.
2. Authorization—When an authenticated principal tries to access a resource, the
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES38
system determines whether the principal is authorized to do so based on the se-
curity policies in force in the application’s security policy domain.
The following sections give an overview of J2EE platform security services.
Security services are discussed in detail in Chapter 9.
2.3.4.1 Security Methodologies
Containers provide two security methodologies: declarative and programmatic.
Declarative security refers to the means of specifying an application’s security
structure in a form external to the application. An Application Component Provider
specifies declarative security in a component’s deployment descriptor. Program-
matic security refers to security mechanisms accessed within a program. An Appli-
cation Component Provider accesses programmatic security for EJB and Web
components with J2EE platform security APIs.
2.3.4.2 Authentication
The J2EE platform allows an Application Component Provider to choose how a
principal is authenticated. A Web client can provide authentication data to a Web
container using HTTP basic authentication, digest authentication, form-based
authentication, or certificate authentication.
With basic authentication, the Web server authenticates a principal using the
user name and password obtained from the Web client. Like basic authentication,
digest authentication authenticates a user based on a user name and a password.
However, the authentication is performed by transmitting the password in an
encrypted form, which is much more secure than the simple base64 encoding used
by basic authentication. With form-based authentication, the Web container can
provide an application-specific form for logging in. With certificate authentica-
tion, the client uses a public key certificate to establish its identity and maintains
its own security context.
There is no way to authenticate to an EJB container. However, authentication
data is also often required when an enterprise bean accesses an external resource.
An enterprise bean can provide authentication data to a resource directly, or it can
request the container to perform this service for it. If the Application Component
Provider specifies that the container should propagate authentication data, the
Deployer specifies the authentication data for each resource factory reference
SERVICE TECHNOLOGIES 39
declared by the enterprise bean, and the container uses the authentication data
when obtaining a connection to the resource.
2.3.4.3 Authorization
J2EE platform authorization is based on the concept of security roles. A security
role is a logical grouping of users that is defined by an Application Component Pro-
vider or Application Assembler. Each security role is mapped by a Deployer to prin-
cipals in the deployment environment. A security role can be used with declarative
security and/or programmatic security.
An Application Component Provider or Application Assembler can control
access to an enterprise bean’s methods by specifying the method-permission
element in the enterprise bean’s deployment descriptor. The method-permission
element contains a list of methods that can be accessed by a given security role. If
a principal is in a security role allowed access to a method, the principal may
execute the method. Similarly, a principal is allowed access to a Web component
only if the principal is in the appropriate security role. An Application Component
Provider controls access programmatically by using the EJBContext.isCallerIn-
Role or HttpServletRequest.isRemoteUserInRole methods.
For example, suppose a payroll application specifies two security roles:
employee and administrator. Salary update operations are executable only by a
principal acting in the role of administrator, but salary read operations are exe-
cutable by both roles. When the payroll application is deployed, the Deployer pro-
vides a mapping between the set of administrator and employee principals (or
groups) and their respective roles. When the salary update method is executed, the
enterprise bean’s container can check whether the principal or group propagated
from the Web server is in a role that can execute that method. Alternatively, the
method itself could use one of the security APIs to perform the check.
2.4 Service Technologies
The J2EE platform service technologies allow applications to access a wide range of
services in a uniform manner. This section describes technologies that provide
access to databases, transactions, naming and directory services, and enterprise
information systems.
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES40
2.4.1 JDBC API
The JDBC™ API provides database-independent connectivity between the J2EE
platform and a wide range of tabular data sources. JDBC technology allows an
Application Component Provider to:
• Perform connection and authentication to a database server
• Manage transactions
• Move SQL statements to a database engine for preprocessing and execution
• Execute stored procedures
• Inspect and modify the results from Select statements
The J2EE platform requires both the JDBC 2.0 Core API (included in the
J2SE platform), and the JDBC 2.0 Extension API, which provides row sets, con-
nection naming via JNDI, connection pooling, and distributed transaction support.
The connection pooling and distributed transaction features are intended for use
by JDBC drivers to coordinate with a J2EE server. Access to databases and enter-
prise information systems is covered in detail in Chapter 6.
2.4.2 Java Transaction API and Service
The Java Transaction API (JTA) allows applications to access transactions in a
manner that is independent of specific implementations. JTA specifies standard Java
interfaces between a transaction manager and the parties involved in a distributed
transaction system: the transactional application, the J2EE server, and the manager
that controls access to the shared resources affected by the transactions.
The Java Transaction Service (JTS) specifies the implementation of a transac-
tion manager that supports JTA and implements the Java mapping of the Object
Management Group Object Transaction Service 1.1 specification. A JTS transac-
tion manager provides the services and management functions required to support
transaction demarcation, transactional resource management, synchronization,
and propagation of information that is specific to a particular transaction instance.
2.4.3 Java Naming and Directory Interface
The Java Naming and Directory Interface™ (JNDI) API provides naming and direc-
tory functionality. It provides applications with methods for performing standard
COMMUNICATION TECHNOLOGIES 41
directory operations, such as associating attributes with objects and searching for
objects using their attributes. Using JNDI, an application can store and retrieve any
type of named Java object.
Because JNDI is independent of any specific implementations, applications
can use JNDI to access multiple naming and directory services, including existing
naming and directory services such as LDAP, NDS, DNS, and NIS. This allows
applications to coexist with legacy applications and systems.
2.4.4 Connector Architecture
A future version of the J2EE platform will support the Connector architecture, a
standard API for connecting the J2EE platform to enterprise information systems,
such as enterprise resource planning, mainframe transaction processing, and data-
base systems. The architecture defines a set of scalable, secure, and transactional
mechanisms that describe the integration of enterprise information systems with an
EJB server and enterprise applications.
To use the Connector architecture, an enterprise information system vendor
provides a standard connector for its enterprise information system. The connec-
tor has the capability to plug in to any EJB server that supports the Connector
architecture. Similarly, an EJB server vendor extends its system once to support
this Connector architecture and is then assured of a seamless connectivity to mul-
tiple enterprise information systems.
2.5 Communication Technologies
Communication technologies provide mechanisms for communication between
clients and servers and between collaborating objects hosted by different servers.
The J2EE specification requires support for the following types of communication
technologies:
• Internet protocols
• Remote method invocation protocols
• Object Management Group protocols
• Messaging technologies
• Data formats
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES42
The following sections give an overview of J2EE platform communication tech-
nologies. How these communication technologies are used by clients is discussed
in Chapter 3.
2.5.1 Internet Protocols
Internet protocols define the standards by which the different pieces of the J2EE
platform communicate with each other and with remote entities. The J2EE platform
supports the following Internet protocols:
• TCP/IP—Transport Control Protocol over Internet Protocol. These two proto-
cols provide for the reliable delivery of streams of data from one host to anoth-
er. Internet Protocol (IP), the basic protocol of the Internet, enables the
unreliable delivery of individual packets from one host to another. IP makes no
guarantees about whether or not the packet will be delivered, how long it will
take, or if multiple packets will arrive in the order they were sent. The Trans-
port Control Protocol (TCP) adds the notions of connection and reliability.
• HTTP 1.0—Hypertext Transfer Protocol. The Internet protocol used to fetch
hypertext objects from remote hosts. HTTP messages consist of requests from
client to server and responses from server to client.
• SSL 3.0—Secure Socket Layer. A security protocol that provides privacy over
the Internet. The protocol allows client-server applications to communicate in
a way that cannot be eavesdropped or tampered with. Servers are always au-
thenticated and clients are optionally authenticated.
2.5.2 Remote Method Invocation Protocols
Remote Method Invocation (RMI) is a set of APIs that allow developers to build dis-
tributed applications in the Java programming language. RMI uses Java language
interfaces to define remote objects and a combination of Java serialization technol-
ogy and the Java Remote Method Protocol (JRMP) to turn local method invocations
into remote method invocations. The J2EE platform supports the JRMP protocol,
the transport mechanism for communication between objects in the Java language in
different address spaces.
COMMUNICATION TECHNOLOGIES 43
2.5.3 Object Management Group Protocols
Object Management Group (OMG) protocols allow objects hosted by the J2EE plat-
form to access remote objects developed using the OMG’s Common Object Request
Broker Architecture (CORBA) technologies and vice versa. CORBA objects are
defined using the Interface Definition Language (IDL). An Application Component
Provider defines the interface of a remote object in IDL and then uses an IDL com-
piler to generate client and server stubs that connect object implementations to an
Object Request Broker (ORB), a library that enables CORBA objects to locate and
communicate with one another. ORBs communicate with each other using the Inter-
net Inter-ORB Protocol (IIOP). The OMG technologies required by the J2EE plat-
form are: Java IDL and RMI-IIOP.
2.5.3.1 Java IDL
Java IDL allows Java clients to invoke operations on CORBA objects that have been
defined using IDL and implemented in any language with a CORBA mapping. Java
IDL is part of the J2SE platform. It consists of a CORBA API and ORB. An Appli-
cation Component Provider uses the idlj IDL compiler to generate a Java client
stub for a CORBA object defined in IDL. The Java client is linked with the stub and
uses the CORBA API to access the CORBA object.
2.5.3.2 RMI-IIOP
RMI-IIOP is an implementation of the RMI API over IIOP. RMI-IIOP allows
Application Component Providers to write remote interfaces in the Java program-
ming language. The remote interface can be converted to IDL and implemented in
any other language that is supported by an OMG mapping and an ORB for that lan-
guage. Clients and servers can be written in any language using IDL derived from
the RMI interfaces. When remote interfaces are defined as Java RMI interfaces,
RMI over IIOP provides interoperability with CORBA objects implemented in any
language. RMI-IIOP contains:
• The rmic compiler, which generates:
■ Client and server stubs that work with any ORB.
■ An IDL file compatible with the RMI interface. To create a C++ server ob-
ject, an Application Component Provider would use an IDL compiler to pro-
duce the server stub and skeleton for the server object.
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES44
• A CORBA API and ORB
Application clients must use RMI-IIOP to communicate with enterprise
beans.
2.5.4 Messaging Technologies
Messaging technologies provide a way to asynchronously send and receive mes-
sages. The Java Message Service provides an interface for handling asynchronous
requests, reports, or events that are consumed by enterprise applications. JMS mes-
sages are used to coordinate these applications. The JavaMail API provides an inter-
face for sending and receiving messages intended for users. Although either API can
be used for asynchronous notification, JMS is preferred when speed and reliability
are a primary requirement.
2.5.4.1 Java Message Service
The Java Message Service (JMS) is an API for using enterprise messaging systems
such as IBM MQ Series and TIBCO Rendezvous. JMS messages contain well-
defined information that describe specific business actions. Through the exchange of
these messages, applications track the progress of the enterprise. The JMS supports
both point-to-point and publish-subscribe styles of messaging.
In point-to-point messaging, a client sends a message to the message queue of
another client. Often a client will have all its messages delivered to a single queue.
Most queues are created administratively and are treated as static resources by
their clients.
In publish-subscribe messaging, clients publish messages to, and subscribe to
messages from, well-known nodes in a content-based hierarchy called topics. A
topic can be thought of as a message broker that gathers and distributes messages
addressed to it. By relying on the topic as an intermediary, message publishers are
independent of subscribers and vice versa. The topic automatically adapts as both
publishers and subscribers come and go. Publishers and subscribers are active
when the objects that represent them exist. JMS also supports the optional dura-
bility of subscribers that “remember” the existence of the subscribers while they
are inactive.
The JMS API definitions must be included in a J2EE product, but a product is
not required to include an implementation of the JMS ConnectionFactory and
Destination objects. These are the objects used by an application to access a JMS
COMMUNICATION TECHNOLOGIES 45
service provider. A future version of the J2EE platform will require that a J2EE
product provide support for both JMS point-to-point and publish-subscribe mes-
saging, and thus must make those facilities available using the ConnectionFac-
tory and Destination APIs.
2.5.4.2 JavaMail
The JavaMailTM API provides a set of abstract classes and interfaces that comprise
an electronic mail system. The abstract classes and interfaces support many different
implementations of message stores, formats, and transports. Many simple applica-
tions will only need to interact with the messaging system through these base
classes and interfaces.
The abstract classes in JavaMail can be subclassed to provide new protocols and
add functionality when necessary. In addition, JavaMail includes concrete sub-
classes that implement widely used Internet mail protocols and conform to speci-
fications RFC822 and RFC2045. They are ready to be used in application
development. Developers can subclass JavaMail classes to provide the implemen-
tations of particular messaging systems, such as IMAP4, POP3, and SMTP.
JavaBeans Activation Framework
The JavaBeans Activation Framework (JAF) integrates support for MIME data
types into the Java platform. JavaBeans components can be specified for operating
on MIME data, such as viewing or editing the data. The JAF also provides a mecha-
nism to map filename extensions to MIME types.
The JAF is used by JavaMail to handle the data included in email messages;
typical applications will not need to use the JAF directly, although applications
making sophisticated use of email may need it.
2.5.5 Data Formats
Data formats define the types of data that can be exchanged between components.
The J2EE platform requires support for the following data formats:
• HTML 3.2: The markup language used to define hypertext documents acces-
sible over the Internet. HTML enables the embedding of images, sounds, video
streams, form fields, references to other HTML documents and basic text for-
matting. HTML documents have a globally unique location and can link to one
CHAPTER 2 J2EE PLATFORM TECHNOLOGIES46
another.
• Image files: The J2EE platform supports two formats for image files: GIF
(Graphics Interchange Format), a protocol for the online transmission and in-
terchange of raster graphic data, and JPEG (Joint Photographic Experts
Group), a standard for compressing gray-scale or color still images.
• JAR file: A platform-independent file format that permits many files to be ag-
gregated into one file.
• Class file: The format of a compiled Java file as specified in the Java Virtual
Machine specification. Each class file contains one Java language type—either
a class or an interface—and consists of a stream of 8-bit bytes.
• XML: A text-based markup language that allows you to define the markup
needed to identify the data and text in XML documents. XML will be support-
ed in a future version of the J2EE specification. As with HTML, you identify
data using tags. But unlike HTML, XML tags describe the data, rather than the
format for displaying it. In the same way that you define the field names for a
data structure, you are free to use any XML tags that make sense for a given
application. When multiple applications use the same XML data, they have to
agree on the tag names they intend to use.
2.6 Summary
The primary focus of the Java 2 Platform, Enterprise Edition is a set of component
technologies (Enterprise JavaBeansTM, JavaServer PagesTM, and servlets) that sim-
plify the process of developing enterprise applications. The J2EE platform provides
a number of system-level services that simplify application programming and allow
components to be customized to use resources available in the environment in which
they are deployed. In conjunction with the component technologies, the J2EE plat-
form provides APIs that enable components to access a variety of remote services,
and mechanisms for communication between clients and servers and between col-
laborating objects hosted by different servers.
About the Author
ABHISHEK CHAUHAN has been working on the design of scalable network services
and distributed programs. At Sun Microsystems, Abhishek was involved in the evolution
of the J2EE programming model from its inception. He pioneered work on Web access
optimization techniques and implementation of the Java Web Server. He worked on the
JavaServer Pages specification and Sun’s JavaServer Pages implementations.
Abhishek was one of the founders and a lead architect at Vxtreme, where he
worked on the design of its streaming server. Vxtreme was acquired by Microsoft in
1997. In a former life, Abhishek worked at Microsoft on the Office Visual Basic
scripting engine. He has an M.S. from the University of Wisconsin, Madison and a
Bachelor’s degree from the Indian Institute of Technology at Delhi.
49
C H A P T E R 3
The Client Tier
by Abhishek Chauhan
A user’s perception of an enterprise application is often closely tied to the behav-
ior of the application’s client tier. A client makes requests to the server on behalf of
the user, and presents the outcomes of those requests to the user. Therefore, it’s
important to choose a client configuration that best addresses the requirements of
the application and empowers the user with a rich interface.
The J2EE platform supports many types of clients. A J2EE client can connect
across the World Wide Web, or inside an enterprise’s intranet. Clients can run on
hardware ranging from powerful desktop machines to tiny wearable assistants.
They can provide a browser-based or stand-alone interface. A client can commu-
nicate with, and use the services provided by, one or more tiers of the enterprise
application. Clients can also be written in a number of languages and use a variety
of development environments.
Since client software executes on user systems, it can be hard to control
aspects of the client environment such as hardware, operating system platform,
and browser version. In any distributed application, there are trade-offs to be made
in partitioning application responsibility between server and client. The more
functionality you keep on the client (closer to the user), the better perceived
quality of service the user gets. The more you provide on the server, the easier it is
to distribute, deploy, and manage the application.
This chapter presents considerations for J2EE client design and provides
guidelines for choosing among the available options. First, it discusses the
requirements to consider before deciding on a client type. Then it presents a clas-
sification of clients based on the differences in the implementation model, and
provide rules for translating client requirements into a choice of a client imple-
mentation.
CHAPTER 3 THE CLIENT TIER50
3.1 Requirements and Constraints
For every application, there are requirements and expectations that the client must
meet, constrained by the environment in which the client needs to operate. Some of
the considerations guiding our choice of client are: Is the client intended to be used
over the Internet, or within a company intranet? Will it present its user interface
through a Web browser or a stand-alone application? What host platforms must the
client work on? This section identifies the constraints to consider when choosing a
client. For each specific enterprise application, some constraints are more important
than others. There are also a number of choices rather than constraints the developer
needs to keep in mind. This section considers the effect of various operating envi-
ronment, deployment, and implementation constraints.
3.1.1 Operating Environment
Whether the client will be deployed inside a company intranet or in the Internet
determines many aspects of the client.
Intranets are usually managed environments, with higher quality network
service and less variance than the Internet. Virtual private networks (VPNs) and
extranets have characteristics that are a hybrid of Internet and intranet characteris-
tics. A VPN is comparable to an intranet in terms of confidentiality and firewall
concerns, but it is like the Internet when it comes to quality of network service.
Applications designed for the Internet typically take a lowest-common-
denominator approach to the client. In other words, the client must work accept-
ably over the slowest link and assume only a minimal set of platform capabilities.
Clients intended to be deployed on a company intranet may differ significantly
from those destined for the Internet. Within an intranet, it is possible to force stan-
dardization to some extent. This means less variance and possibly a higher
common denominator.
This section considers the effect of operating environment on the level of
network service, and security requirements and constraints.
3.1.1.1 Network Service
Clients working across local area networks in a company’s intranet typically enjoy a
high level of network service. Bandwidths of the order of multiple megabits/sec. are
available, and latency is negligible, often less than 25 milliseconds. On the other
hand, clients on the Internet can expect lower levels of service. Moreover, there is a
wide variance in network quality of service across Internet clients. While some
REQUIREMENTS AND CONSTRAINTS 51
clients are connected across dialup telephone lines, others could be connected over
cable modems, DSL, or better services.
Network service plays an important role in the design of any distributed appli-
cation. Let’s look at two key network characteristics—bandwidth and latency—
and see how they affect the choice of what type of client to use.
Highly interactive applications place greater demands on network bandwidth
and well as latency. Low bandwidth requires settling for a less interactive inter-
face. Or, it may be necessary to move portions of the presentation responsibilities
to the client; this, coupled with some form of caching of the data, could yield
acceptable response times. Clients such as applets and application clients that can
take over presentation responsibilities, may be better adapted to work in low band-
width situations.
Consider a browser-based client that displays a hierarchy of information as a
tree, for example, a navigational menu or a list of mail folders. If the network is
fast, it may be acceptable to make a request to the server every time the user
selects a node to see a list of the node’s children. The server then dynamically
generates a new screen reflecting the expanded node. However, if the network is
slow, a better approach might be to have the client cache the node hierarchy.
3.1.1.2 Security and Firewalls
The Internet and intranets have different security constraints.
Clients that work within the intranet usually do not have to worry about fire-
walls between the client and the server. However, clients that need to connect over
the Internet must be designed to be able to talk to servers that are often behind
firewalls. The presence of a firewall limits the possible choices for protocols that
the client can use. With the prevalence of the World Wide Web, most firewalls are
configured to allow HTTP and HTTPS protocols to pass across. Firewalls config-
ured to allow IIOP communications are not widespread. And even when a corpo-
ration allows IIOP to pass through, the details of configuring firewalls for this
purpose may not be widely understood.1
Within an intranet, the client and server may be in the same security domain,
and can integrate with the environment better in terms of security. For instance, it
may be possible to have single signon clients within an enterprise. Over the Inter-
net, clients and the server are typically in different security domains. Another
aspect of security is confidentiality. While confidentiality is not a concern for a
1 It is possible to configure most firewalls to pass IIOP. However, because this is an excep-
tion rather than the rule, most firewall administrators may be wary of doing so.
CHAPTER 3 THE CLIENT TIER52
large category of enterprise information within the corporate intranet, confidenti-
ality must be ensured if the communication occurs over the Internet. In this case,
its necessary to use a protocol that can ensure confidentiality, such as HTTPS.2
3.1.2 Deployment
The deployment mechanisms available affect the choice of client type. A developer
needs to consider:
• The delivery vehicle for the client software
• The roll-out and upgrade strategy
• How often the client needs to be upgraded
The bandwidth available to the client plays a role in deciding the client
deployment model. For example, some clients such as applets must be down-
loaded every time the user establishes a session with the server. In this case, the
download must complete in an acceptable amount of time. Thus, when applets are
used as part of the client framework, keeping the size of the client small is impor-
tant unless the network can be expected to support a large bandwidth.
Web-based clients usually have very little that requires explicit deployment.
They therefore work well when the client is changed or upgraded often. By
keeping most of the functionality on the server, an application can also use older
versions of supporting software on the client.
3.1.3 Implementation
This section considers constraints on the client based on the platform and program-
ming language.
3.1.3.1 Platform
The first constraint to consider is whether the client presents its interface in a spe-
cific platform, a browser or as a stand-alone Java application, or does the client need
to run on multiple hardware and/or software platforms. In the latter case, an enter-
prise application developer could take one of two approaches: choose a browser-
based client, where the browser software handles platform differences,3 or a Java
2 IIOP can be made to work over SSL connections, although such configurations are not in
widespread use.
OVERVIEW OF CLIENT OPTIONS 53
technology-based solution, where the Java runtime environment insulates the client
software from the platform.
The computation that can be done on the clients limits some client options.
For example, if the client executes in a cell-phone or pager, the server should
perform as much computation and data processing as possible and the client
should only display the results. Conversely, powerful client platforms may be
leveraged for distributed problem-solving. For example, when a financial analysis
system runs on a powerful desktop platform, it might make sense to off-load
complex financial-projection computation to the client.
3.1.3.2 Programming Language
The choice of implementation language is usually governed by non-technical
factors such as the availability of expertise and the desire to integrate with other
legacy application clients. If you already have a client that integrates services from
several enterprise applications that you are extending to add this new service you
might use a language, such as Visual Basic, C++, or another language, that does not
integrate with the J2EE platform as seamlessly as Java.
3.2 Overview of Client Options
Choices such as which tier or tiers of the application that clients interact with, the
protocols used for this communication, and the implementation language used for
the client are dependent on several factors. Different tiers expose different levels of
detail and complexity.
The Web tier presents a simplified functional facade to the application. It
takes care of presentation issues for the client. The EJB tier presents an interface
to access and manipulate the business objects according to the business rules set in
the application, leaving presentation issues to the client connecting to it. The
enterprise information system tier presents a raw view of the data, delegating the
responsibility of enforcing the business rules, as well as presenting the data to the
client.
The protocols used for communication have different strengths and limita-
tions. The Web tier typically uses HTTP-based protocols. HTML over HTTP is
suitable for handling the presentation needs of the client, while XML over HTTP
3 Recently, browsers act much like platforms. In such cases, the application will still have
to deal with differences in browser “platforms.”
CHAPTER 3 THE CLIENT TIER54
is better suited for interchange of data to be presented by the client. The EJB tier
uses the RMI-IIOP protocol. As a full-scale distributed computing protocol, it
gives the client direct access to the services of the EJB tier. A client can use busi-
ness objects hosted by the EJB server and can participate in transactions.
For clients of the J2EE platform, the Java programming language is the imple-
mentation language of choice because Java technology-based implementations
can take advantage of services provided by the platform. Other languages, such as
C++ and Visual Basic, can be used, albeit with some limitations.
Many aspects of the client are determined by the tier of the enterprise applica-
tion the client connects to. This discussion classifies clients into three broad cate-
gories based on the tiers that they interact with:
• Web clients connect to the Web tier. They execute on a desktop or other brows-
er host usually inside a Web browser or a browser plug-in. The presentation
logic as well as the business logic of the application can run on the server or
the client.
• EJB clients connect to the EJB tier. These are typically GUI programs that ex-
ecute on a desktop computer. EJB clients have access to all of the facilities of
the J2EE EJB tier. The presentation logic of the application runs on the EJB
client, while the business logic runs on the server.
• Enterprise information system clients interface directly to an enterprise infor-
mation system resource. Typically these programs serve administrative and
management functions for the back-end system. Both presentation and busi-
ness logic are contained in the client.
3.3 Web Clients
Web clients usually run inside a browser and use the services of the browser to
render content provided by the Web tier. In these clients, the user interface is gener-
ated on the server side by the Web tier and communicated via HTML. Applets and
JavaScript can be used to enhance the browsing interface. On the client side, a
browser or equivalent program renders this user interface and carries out interac-
tions with the user. Data interchange is facilitated through XML.
WEB CLIENTS 55
3.3.1 Protocols
Web clients use HTTP or HTTPS as the transport protocol. These protocols have
several advantages:
• They are widely deployed. Almost every computer now has a browser that can
communicate over HTTP. Thus the deployment of the application is simpli-
fied.
• They are robust and simple. The protocol is simple and well understood. Good
implementations of HTTP servers and clients are widely available.
• They go through firewalls. Due to the extensive use of HTTP, firewalls are typ-
ically set up to pass HTTP through. This makes it the protocol of choice on the
Internet where the server and the client are separated by a firewall.
At the same time, the simplicity of the protocols presents a couple of minor
disadvantages that can largely be overcome:
• They are sessionless. HTTP is a request-response protocol, with no built-in
concept of a session. Therefore, individual requests are treated independently.
Moreover, there are simple ways to provide session semantics, so in practice
this is not an issue.
• They are non-transactional. HTTP is a networking protocol, not designed for
general purpose distributed computing. As a result, it has no concept of trans-
action or security contexts. However, this is not a problem in practice because
transactions and security are commonly handled on the server.
3.3.2 Content Format
The content served over the HTTP protocol is typically the result of an action per-
formed on the server in response to a client request. This result can be formatted
using HTML or XML.
3.3.2.1 HTML
HTML content is widely supported by browsers and operating systems. Along with
HTML, a server may also provide JavaScript code in the response to enrich the user
interface.
CHAPTER 3 THE CLIENT TIER56
This content type is best suited when presentation of the response is generated
on the server side and communicated to the browser for display. It should be used
as a markup language that instructs the browser how to present the results.
HTML is a good means of encoding static documents. However, presenting
complex documents consistently is difficult using HTML. Style sheets and
dynamic HTML (DHTML) allow more complex documents to be displayed.
However, the various commonly used browsers do not handle style sheets and
DHTML consistently, so it is necessary to design different versions of each page
or to include browser-specific markup in the pages.
HTML’s strength is its wide support in many applications on many platforms.
HTML documents that do not rely on browser-specific tags should be similar in
appearance on the most commonly used browsers. The combination of HTTP and
HTML ensures that a document can be widely viewed on many platforms.
3.3.2.2 XML
The XML (eXtensible Markup Language) standard provides a mechanism for struc-
turing content and data. XML allows applications to transfer both page content and
information on how the content is structured.
The structure of the data contained within an XML document is described in a
Data Type Definition (DTD). Applications that support XML can communicate
and exchange data without any prior knowledge of each other, as long as they
share or are capable of interpreting the DTD. For example, the interoperability
portion of the sample application sends a list of orders to a Microsoft Excel
spreadsheet using XML over HTTP. J2EE servers may also transfer information
to other J2EE servers or applications using XML over HTTP. This is not possible
with HTML, because of the limited number of tags it provides to identify data.
While DTDs are useful to validate XML documents, they suffer from a
number of shortcomings, many of which stem from the fact that a DTD specifica-
tion is not hierarchical. This affects the ability to name elements relative to one
another and the ability to scope comments to sections of a document. Finally,
DTDs do not allow you to formally specify field-validation criteria, such as a lim-
itation on the size and content of a zip code field. To remedy these shortcomings, a
number of proposals have been made for future versions of XML to provide data-
base-like hierarchical schemas that specify data validation criteria.
XML also allows dynamic data presentation. That is, the same data can be
presented differently depending on the style sheet used. Fortunately, the XSL
(eXtensible Style Sheet) standard, which provides a standard approach to XML
WEB CLIENTS 57
presentation, will be completed and accepted in the near future. Most of the com-
monly used Web browsers support now, or will soon support, XML. However,
since XML is evolving, support by browsers is not as uniform as HTML. This
means that an applet, plug-in, or other application component, that handles XML
responses might be necessary. In the case of Java applets, this can happen auto-
matically at request time.
Use XML for your responses when:
• The client needs to get data from the server and process it before displaying it
to the user.
• The client needs to show multiple views of the same data. When the client
downloads XML data from the server, it can generate views on the client side
depending on local settings. This saves a round-trip to the server and reduces
load on the server by reducing the number of client requests.
For example, consider a stock quote system, where the client wants to see
a chart of the last hour’s trades, as well as a table of the same data. The client
could download the quote data from the server just once, then render that data
as either a chart or a table (or both), at the user’s requests without resending a
request to the server.
• The client can pass XML in requests. The HTTP protocol allows for POST data,
in any content type, in a request. An XML-aware application component run-
ning on the client could use POST requests with XML data to exchange objects
with the server.
3.3.3 Types of Web Clients
Most Web clients run inside of or in conjunction with a Web browser. The browser
can handle details of HTTP communication and HTML rendering, while an applica-
tion component can focus on interactions that cannot be expressed in HTML. In
fact, a Web browser without any other application component is the simplest, most
widespread J2EE Web client. Additional application components such as Java
applets, browser plug-ins, or ActiveX components can make the client user interface
richer and more featureful. Finally, Web clients can be implemented as stand-alone
programs.
CHAPTER 3 THE CLIENT TIER58
3.3.3.1 Web Browsers
The Web browser is the simplest J2EE client. It serves to render HTML content
delivered by the Web tier. With more and more browsers supporting JavaScript and
DHTML, powerful user interfaces can be created using just a Web browser.
A stand-alone Web browser is the Web client of choice on the Internet. It is
widely available, users are familiar with using it, and there are no issues with
deployment. Additionally, since Web browsers can be used wherever an Internet
connection is available, support for roaming users is possible.
3.3.3.2 Java Applets
Applets are GUI components that typically execute in a Web browser, although they
can execute in a variety of other applications or devices that support the applet pro-
gramming model. Applets can be used to provide a powerful user interface for J2EE
applications.
Since applets are Java-based components, they have access to all the features
and advantages of the Java platform technology. In a heterogeneous Web environ-
ment, it is especially important that client-side components be portable. For the
protection of the client machine, it is important to be able to place security restric-
tion on these components and detect security violations. Java applets serve both
these needs.
Browser-based applet clients communicate over HTTP. Applets can also com-
municate over a network using serialized objects or some other type of proprietary
protocol.
One advantage of applets is that they provide application with rich GUIs that
can be managed at a single location. The main disadvantage with browser-based
applets is that they can be difficult to deploy, particularly when the client browsers
run a diverse set of embedded Java virtual machines. For this reason, applets may
be more successfully deployed where the browser environment is controlled (such
as an intranet).
Deployment
Applets are delivered through applet tags embedded in HTML. The Web browser
downloads the code for the applet at request time and executes it in a Java virtual
machine on the client machine.
WEB CLIENTS 59
When JSP pages are used to generate HTML, an Application Component Pro-
vider can use the jsp:plugin tag to ensure the availability of a specific JVM on
the client.
Security
The Java applet programming model protects the user from security violations. All
downloaded code is considered untrusted and strict limitations are placed on it. For
users to be more comfortable with executing application code downloaded from
another computer, vendors should use signed applets. Signed applets provide a
secure way to identify the applet’s distributor. A signed applet can also request addi-
tional permissions from the client machine if it needs access to additional function-
ality.
Session Management
When applets communicate with servlets or JSP pages over HTTP they need to
manage some details of the HTTP protocol to participate in a session. Sessions over
HTTP are managed using HTTP cookies. The server sets the cookie at the begin-
ning of the session; the client then sends the cookie back to the server each time it
makes another request. When the applet makes a request, it needs to explicitly make
sure that it sends the cookie as part of the request.
3.3.3.3 Browser Plug-ins
In addition to applets, Web browsers often support other embedded components,
such as plug-ins in the Netscape browser and ActiveX components in Microsoft’s
Internet Explorer. These can be used just like applets to enhance the user experience.
There are some things to keep in mind when planning to use these component types
in a J2EE client:
• Plug-ins are usually written for a particular architecture and operating system.
On the Internet, multiple versions of these plug-ins need to be implemented for
each kind of client. If the clients run on a homogeneous intranet environment,
this is less of an issue.
• Since plug-ins run natively on the browser’s platform, security is harder to en-
force, which could expose your clients to an unacceptable risk.
CHAPTER 3 THE CLIENT TIER60
3.3.3.4 Stand-Alone Web Clients
The discussion so far has considered Web clients with the application component
embedded in a browser. Sometimes, though, it might be desirable to invert this
model by embedding the browser in an application client. This type of client is
referred to as a stand-alone Web client.
In this configuration, the application client creates a top level window and
user interface, then uses a browser-like component to render HTML responses
from the server.
This is desirable where the client needs to look like a native application, and
provide a more interactive and customized GUI to the user. These clients often use
XML over HTTP to communicate with JSP pages or servlets and render the data
interchanged in their customized GUI.
A stand-alone Web client suffers from the same drawbacks as other stand-
alone applications:
• The client must be explicitly deployed on each user desktop. Client upgrades
are also harder for the same reason.
• Implementing the client is more work since the client must be coded to create
the bulk of the user interface.
With the availability of tools, some of this work can be automated. However,
deploying a stand-alone client remains a complex process.
Java Clients and the Swing API
The user interface of a stand-alone Web client is typically written using the Swing
API from the J2SE platform. The Swing API provides a comprehensive set of GUI
components (tables, trees, and so on) that can be used to provide a more interactive
experience than the typical HTML page. Additionally, Swing supports HTML text
components that can be used to display responses from a server. Swing APIs can be
used for both applets and stand-alone Java applications.
EJB CLIENTS 61
Non-Java Clients
Stand-alone Web clients can also be written in C++ or in automation languages such
as Visual Basic.4 These clients can use their own HTML renderers or third-party
browser components to present responses from the server.
Non-Java clients may be desirable where specialized services are made avail-
able by the development environment. For example, a chart plotting application
might find it useful to take advantage of this fact. If Microsoft Excel is available
on the client desktops throughout an enterprise, it might be desirable to use it for
rendering charts. A Visual Basic client embedded in Microsoft Excel could com-
municate with a JSP page and download the chart data using XML. The client
could then use specialized services in Excel to render this chart.
3.4 EJB Clients
EJB clients are application clients that interact with the J2EE EJB tier. EJB clients
are GUI programs that typically execute on a desktop computer; they manage their
own GUI and offer a user experience similar to that of native applications. Here we
discuss how to develop and deploy EJB clients.
3.4.1 Protocols and Facilities
EJB clients interact with the J2EE EJB tier using the RMI-IIOP protocol. A variety
of middle-tier services are available to an application client:5 JNDI for directory
lookups, JMS for messaging, and JDBC for relational database access.
An EJB client depends on a client container to provide some system services.
Such a container is typically very lightweight compared to other J2EE containers
and usually provides security and deployment services.
3.4.1.1 The Client Container
A client container is usually a library that is distributed along with the client. It is
specific to the J2EE EJB container,6 and is often provided by the same vendor. The
container manages details of RMI-IIOP communication. It also handles security,
4 Using the scripting engine on a Windows platform, a developer could use other scripting
languages such as JavaScript or Perl. The component model remains COM.
5 These services are only available if the application client is implemented using Java.
6 The IIOP protocol does not completely specify details of the security and transaction con-
texts, thus different implementations of the protocol may not be compatible.
CHAPTER 3 THE CLIENT TIER62
transaction, and deployment issues. The following discussion assumes a Java client
container. The J2EE specification doesn’t define service requirements for applica-
tions implemented in other languages. However, a similar set of services should be
provided by containers for such clients.
3.4.1.2 Deployment
EJB application clients are packaged in JAR files that include a deployment descrip-
tor similar to other J2EE application components. The deployment descriptor
describes the enterprise beans and external resources referenced by the application.
As with other J2EE application components, access to resources is configured at
deployment time, names are assigned for enterprise beans and resources, and so on.
The J2EE platform does not specify tools to deploy an application client, or
mechanisms to install it. Very sophisticated J2EE products might allow the appli-
cation client to be deployed on a J2EE server and automatically made available to
some set of (usually intranet) clients. Other J2EE products might require the J2EE
application bundle containing the application client to be manually deployed and
installed on each client machine. Another approach would be for the deployment
tool on the J2EE server to produce an installation package that could be taken to
each host to install the application client.
3.4.1.3 Transactions
Since client containers aren’t required to provide direct access to transaction facili-
ties, EJB clients should use enterprise beans to start transactions. They can also use
transaction facilities of JDBC. However, doing so may be risky since the J2EE plat-
form doesn’t define a mechanism for propagating the transaction context to the EJB
server.
3.4.1.4 Security
The client application must be authenticated to access the J2EE middle tier. Tech-
niques for authentication are provided by the client container, and are not under the
control of the application client. The container can integrate with the platform’s
authentication system, authenticate when the application is started, or use some
other lazy authentication policy. The container takes responsibility for gathering
authentication data from the user, by presenting a login window to the user.
EJB CLIENTS 63
EJB clients in the Java programming language execute in an environment with
a security manager installed. They have similar security permission requirements
as servlets.
3.4.2 Strengths and Weaknesses
EJB clients have a number of strengths, including:
• Provide a more flexible user interface
Application clients can be made to look and feel more like native applica-
tions on the client machine. Since these clients implement their own user
interface, they can provide a richer, more natural interface to the application
tasks.
• Distribute the workload
An application client can share some of the computational expense by
doing the task on the client desktop, and thereby reducing load on the server.
In particular, the work of generating the user interface is performed by each
client. This is useful for applications with specific graphical display capabili-
ties.
• Handle complex data models
Sometimes the data associated with an application is sufficiently complex
and the manipulation interface rich enough, that a Web-based interface to
manage the interaction is not enough. In such cases, you want direct access to
the underlying object model on the client and to manipulate it directly.
For example, in a financial analysis system, it might make sense to off-
load some of the complex financial-projection number crunching to the client.
Or consider an application that allows manipulation of CAD schemas such as
a design of a circuit board (PCB). An application client, with direct access to
the objects of the CAD system, can redraw views of the layout more easily
than a Web-based interface, and with better performance. The server should
be delegated to background tasks such as converting a PCB layout to a plot of
the PCB traces.
• Are transaction-capable
Since EJB clients communicate using RMI-IIOP, they are capable of par-
CHAPTER 3 THE CLIENT TIER64
ticipating in client-demarcated transactions through JTA APIs.
• Provide integrated security
Application client containers can integrate with the security of the under-
lying operating system where the client is executed, thereby providing a more
transparent and manageable security infrastructure.
For example, in an enterprise intranet, where the client and the server
belong to the same security domain, an application client container might
simply forward the credentials of the user already logged into the client desk-
top operating system, thereby effecting single signon. A Web client, on the
other hand, would require explicit sign on and security management.
The disadvantages of EJB clients are that they:
• Require explicit deployment
EJB clients need to be distributed and installed on the client desktops. In
an intranet, where desktops can be standardized, this is less of an issue. How-
ever, on the Internet, distribution becomes a serious consideration. Further-
more, upgrades and fixes to the client need to be distributed as well, and the
server has to deal with multiple versions of the client programs.
• Require firewall reconfiguration
The RMI-IIOP protocol does not usually go through firewalls without
additional setup on the firewall host. This makes use of EJB clients on the
Internet very limited.
• Tend to be more complex
Since the application client needs to manage its own user interface, its
implementation is more complex. Furthermore, it communicates with the
J2EE server at a much lower level than browser-based Web clients and needs
to handle the complexity introduced as a result.
3.4.3 Types of EJB Clients
EJB clients can be implemented using either the Java programming language, or
languages such as Visual Basic or C++. When a language other than Java is used,
depending on the implementation on the client container, some of the facilities of
the J2EE platform may not be available.
EJB CLIENTS 65
3.4.3.1 Java Technology Clients
Java clients execute in their own Java virtual machine. Following the model for Java
applications, they are invoked at their main method and run until the virtual machine
is terminated. Security and deployment services are provided through the use of a
client container.
The Java programming language should be used for implementation of EJB
clients. Since the EJB server communicates using RMI-IIOP, the client needs to
support RMI-IIOP. This is most naturally done using services provided by the
standard Java platform.
Some facilities cannot be easily implemented in other languages as a result,
client containers for these languages may not provide the full set of features.
Multitier Clients
Java technology clients are usually stand-alone Java applications. However, when
appropriately signed and trusted, Java applets can also be used as EJB clients.
Applets and applications have essentially the same set of platform service available
to them. Additionally, a Java applet can communicate with the Web tier as well as
the application tier to get its job done. In this sense it is a multitier client.
3.4.3.2 Non-Java Clients
EJB clients can be implemented in programming languages other than Java. Since
the EJB server uses RMI-IIOP, this requires some form of RMI-IIOP support avail-
able to the client.
Accessing Enterprise Beans as COM Objects
Scripting COM objects together into an application is a common client implementa-
tion approach. It is possible for a client container to make enterprise beans appear as
COM objects on the client machine.
When enterprise beans are exposed as COM objects, any scripting languages
supported by the Active Scripting Engine can be used to automate the components
to develop the application client. While Visual Basic is most often used for this
purpose, languages such as JavaScript or Perl can also be used.
The specific approach to developing such clients will be largely dependent on
the J2EE product used and the platform. Client containers will be provided by the
J2EE server.
CHAPTER 3 THE CLIENT TIER66
Here’s an example of how such clients might work:
• Create an RMI-IIOP proxy in the client. This proxy runs in a Java virtual ma-
chine. The client uses RMI-IIOP to communicate with the EJB tier.
• The client container exposes each enterprise bean that is part of the application
as a COM object by generating and a registering type library for each enter-
prise bean. Note that the type libraries must be installed on every client desk-
top. The COM objects that are registered act as enterprise bean proxies.
• When the COM IDispatch interface of the enterprise bean proxy object is used
to make a method invocation, it communicates with the RMI-IIOP proxy using
Java Native Interface, or some other proprietary mechanism. The RMI-IIOP
proxy communicates with the EJB tier just like a Java application client and
forwards the invocation.
Limitations
Translating between one distributed computing architecture and another is not
straightforward. There are some limitations when using Visual Basic clients that
access the EJB tier:
• Security: It is hard to propagate security contexts between the J2EE platform
and Visual Basic clients. The RMI-IIOP proxy to the EJB server appears to be
the application client. The proxy thus needs to somehow authenticate the user
on behalf of the Visual Basic client. Integration with the native security system
is harder.
• Transactions: Transaction contexts cannot be propagated from a non-Java cli-
ent to the EJB tier. Although availability of JTA or propagation of contexts is
not required by the J2EE platform, it is often available in Java client contain-
ers. However, this is not possible when using the COM.
• Deployment: The type libraries that need to be generated for each enterprise
bean are application-specific and need to be distributed and installed for each
Visual Basic application client.
When to Use COM Clients
The decision to use Visual Basic clients is largely non-technical. It depends on the
expertise available, as well as the desire to integrate with existing EJB clients. When
ENTERPRISE INFORMATION SYSTEM CLIENTS 67
legacy issues are not a concern, EJB clients should be developed using Java technol-
ogy.
Active Server Pages
There is one interesting case where a COM-based scripting client might interact
with an EJB server. This is the scripting present in Microsoft IIS Active Server
Pages (ASP). ASPs are server-side scripting components that use Visual Basic script
to produce dynamic content. An ASP developer that wishes to use the J2EE plat-
form for its middle tier needs, can do so using the techniques outlined above.
3.5 Enterprise Information System Clients
Enterprise information system clients access enterprise information system
resources directly and assume responsibility for enforcing the business rules of the
application.
Enterprise information system clients can use the JDBC API to access rela-
tional databases. A future release of the J2EE specification will describe standard
ways to implement enterprise information system clients with connectors to non-
relational resources, such as mainframe or enterprise resource planning systems.
These programs should be implemented with caution, since they access the
database directly. Widely distributing such programs can also cause security prob-
lems.
Enterprise information system clients must both manage their user interface
and enforce business rules. Fully functional applications designed this way tend to
be complex. These programs should be limited to administration or management
tasks, where the user interface is small or nonexistent and the task is simple and
well understood.
For example, a stand-alone enterprise information system client could
perform maintenance on database tables, and be invoked every night through an
external mechanism.
The J2EE programming models doesn’t recommend techniques for imple-
menting these programs.
CHAPTER 3 THE CLIENT TIER68
3.6 Designing for Multiple Types of Client
We have discussed several approaches to building clients for enterprise applications
and how the choice of a client influences service implementation. Often, an enter-
prise application will have more than one type of client accessing its services.
A banking application might expose a simple Web interface for account-
holders to view account balances, as well as provide a richer interface through a
stand-alone client that customers can install on their desktop computers. In this
example both clients have similar functionality although they use different mecha-
nisms to present their interface to the user. A banking application might also
provide a stand-alone client administration interface.
When designing an enterprise application, you should pay attention to han-
dling multiple types of client interactions. The overall application design should
support each new type of client with minimal additional effort. It should also
avoid duplicating code either by sharing the application objects among multiple
clients, or by reusing them through encapsulation, delegation, or inheritance.
This section discusses approaches to designing enterprise applications that
can support multiple types of clients.
Application data and business rules are independent of the clients that access
the application, making it desirable to design these objects to be shared across all
the different clients of the application. When different types of clients present the
same functionality through different interfaces, it is useful to share objects that
encapsulate this functionality or client behavior.
The distinction between objects that can be shared or reused, and objects that
need to be implemented separately for each type of client can be discussed in
terms of the MVC architecture. The follow sections consider the issues that arise
when designing the model, view, and controller to support multiple types of cli-
ents.
3.6.1 Model
The model is a software abstraction of the application data and the business rules
that apply for changing this data. The model can be shared across all clients of the
application. It should be consistent regardless of the type of client accessing the
data. If the model faithfully captures all possible ways that data can be changed,
there is no need to implement different model classes, or develop specific model
objects for each client type.
DESIGNING FOR MULTIPLE TYPES OF CLIENT 69
When each type of client represents a different level of authorization to the
system, it is sometimes desirable to wrap the access to the underlying model into
security mediator objects. This allows the model to be shared across all clients,
while access control restrictions can be enforced more flexibly. Security mediator
objects are described in Section 9.3.6 on page 229.
In situations where the models that two clients of the application work with
are independent of one another, the application can be thought of as being com-
prised of multiple subapplications. In this case the programming model would be
applied to each of these subapplications independently.
3.6.2 View
A view renders the contents of a model. It accesses data from the model and spec-
ifies how that data should be presented. The view changes most significantly across
clients. This makes it hard to share entire view implementations. However, some
code sharing can still be effected at a finer grained level. This is especially true when
clients use the same medium for presentation, but provide different functionality.
For example, the sample application could provide a Web-based shopping
interface and a Web-based administration interface. Although very different in
functionality, they both are Web based. If a showOrder custom JSP tag were used
to render details of a particular order to HTML, the same tag could be used by
both the shopping and the administration clients.
3.6.3 Controller
A controller defines application behavior; it interprets user gestures and maps
them into actions to be performed by the model. Each client that exposes different
functionality requires a separate controller. For example, the sample application
would need separate controllers for shopping and administration clients. There is
always some opportunity to reuse code that is part of the application controller
framework; however, this is independent of the type of clients accessing the applica-
tion.
However, multiple clients that expose similar or identical functionality should
be able to share the controller responsible for the functionality. If the clients
provide only slightly different functionality, it should still be possible to reuse the
controller implementation by using a single class to implement the common
behavior and using subclasses to implement the custom behavior. For example,
the banking application described earlier has a Web-based interface as well as a
CHAPTER 3 THE CLIENT TIER70
stand-alone desktop client. The difference between the clients is how they present
the interface—the view. Therefore they can share the same controller.
Because the controller interacts directly with the view it is not completely
insulated from changes in the view implementation. For example, strongly typed
references to view objects in the controller make it difficult to redeploy. In order to
design the controller to allow a large portion of its implementation to be shared,
we need to examine the interactions between the view and the controller and find
ways to minimize the effect of those interactions on the controller. The interac-
tions are:
• Interpreting user gestures generated through the view
• Selecting the view
3.6.3.1 Interpreting User Gestures
The controller accepts user gestures from the view. These depend on the medium
that the view uses to present the user interface. For example, in a JFC application,
the user gestures could be “button pressed” events or “mouse moved” events, and so
on. In a Web interface, the user gestures appear as GET or POST requests for URLs of
the application. In a messaging environment, the user gestures take the form of
asynchronous messages.
To keep the controller as reusable as possible, the controller must translate
these user gestures as soon as possible and turn them into business events—uni-
form, view-neutral representations of the actions requested by the user.
The sample application uses RequestToEventTranslator for this purpose.
This object takes an HttpServletRequest from the view—a browser in this
case—and translates it into an EStoreEvent business event. RequestToEvent-
Translator is discussed in Section 10.6.3 on page 285. The rest of the controller
implementation deals only with EStoreEvent and can be reused for different
implementations of the view. If we wanted to implement a JFC-based client for
the sample application, we could just add another translator that translates JFC
events into business events.
Code Example 3.1 shows how RequestToEventTranslator takes a request
and translates it into a business event. An object that implements ShoppingCli-
entControllerInterface, which provides the core of the controller responsibili-
ties, invoked using an EStoreEvent, does not need to change when the client
changes.
DESIGNING FOR MULTIPLE TYPES OF CLIENT 71
public class RequestProcessor {
ShoppingClientControllerInterface scc;
RequestToEventTranslator eventTranslator;
public void processRequest(HttpServletRequest req) {
...
// translate view specific event into EStoreEvent
EStoreEvent event = eventTranslator.processRequest(req);
if (event != null) {
// invoke the controller with EStoreEvent, instead of
// using the view specific HttpServletRequest
Collection updatedModelList = scc.handleEvent(event);
mm.notifyListeners(updatedModelList);
}
...
}
}
Code Example 3.1 Translating View-Dependent Gestures into View-Neutral
Business Events
3.6.3.2 Selecting the View
The controller selects which view to display. These depend on the medium that the
view uses to present the user interface. For example, in a JFC application, the user
views are composed of Swing components such as panels, lists, tables, and so on. In
a Web interface, the views are HTML pages that are rendered by a browser.
To keep the controller as reusable as possible the controller needs to express
views in a technology-neutral fashion and translate them to technology-specific ren-
ditions as late as possible. This would require a layered view selection component
that uses objects to represent views (analogous to the business events in the previous
section) which are forwarded to specific types of view generators. For example, a
product list view would contain all the data needed to represent a list of products.
This object could be passed to a view generator, which would render the data in a
specific user interface medium. Note that depending on the medium, the view gener-
ator may reside on the server (HTML) or on the client (JFC).
CHAPTER 3 THE CLIENT TIER72
3.6.3.3 Example: The Sample Application Controller
The sample applications controller is in two parts: the EJB controller, which inter-
acts with enterprise beans and a controller proxy, which interacts with views. In the
current release, the proxy is monolithic and specific to Web clients.
If another type of shopping client interface were required, the EJB controller
could be shared without modification. However, the proxy portion of the control-
ler would have to be rearchitected to support more than one type of view technol-
ogy. For example, a JFC-based view selection component would need to register
event listeners when the view is created. These listeners would then post or propa-
gate the events to the client portion of the controller.
3.7 Summary
This chapter has discussed various types of J2EE clients, as illustrated in Figure 3.1.
Figure 3.1 Client Options
In general, J2EE applications should use Web clients when possible. With the
help of technologies such as DHTML and JavaScript, Web browsers can support
reasonably powerful and fast user interfaces. Additional capabilities can be pro-
vided by using applets. Java applets can be used in conjunction with the browser
using HTML or XML over HTTP for additional enhancements. A Java applet can
also communicate with the middle tier for further control and flexibility. The Web
SUMMARY 73
browser is a truly universal Web client, so for simple user interfaces, and for Inter-
net applications, it is the client of choice.
Application clients should be used when the data model is complex and
cannot be expressed through the Web interaction model. Application clients are
well-suited for intranet enterprise distribution. They can provide a richer user
experience and blend well with the desktop windowing environment. However
due to the increased complexity of such clients, there are reasons to avoid them in
favor of Web-based applications. What’s more, ongoing enhancements to the Web
client speed and functionality will continue to erode the need to deploy stand-
alone clients for all but a handful of cases.
The use of application clients on the open Internet is not straightforward
because of distribution, deployment, security, and firewall issues. These clients are
best suited for the intranets, where they can provide a more featureful user inter-
face to the user and provide integrated security. Implementation of stand-alone
clients requires more effort.
Special purpose application clients can be used for administrative and man-
agement tasks. These clients are not intended to be distributed to every user, and
often have a minimal user interface. They perform specific tasks, perhaps invoked
automatically by the system, through means external to the J2EE specification.
Use of enterprise information system clients should be limited to simple,
well-understood management or administrative tasks.
The Java programming language is preferred for stand-alone clients, although
similar capabilities may be possible with languages other than Java.
About the Author
GREG MURRAY is an engineer in the J2EE programming model team at Sun Micro-
systems. He assisted in the design and implemented much of the Web tier of the portions
of Java Pet Store sample application. Prior to joining the J2EE programming model
team Greg was a member of Global Products Engineering at Sun. Greg graduated with a
B.A. in International Relations with a minor in Japanese from Brigham Young
University.
75
C H A P T E R 4
The Web Tier
by Greg Murray
USERS have benefited significantly from the increasing ability of Web-based
applications to generate dynamic content customized to their needs. JavaServer
Pages (JSP) and servlets are J2EE technologies that support dynamic content gener-
ation in a portable, cross-platform manner. Web-based J2EE applications that use
these technologies can be architected in a number of ways. Simple Web-based J2EE
applications can use basic JSP pages and servlets or JSP pages with modular com-
ponents. More complex transactional J2EE applications use JSP pages and modular
components in conjunction with enterprise beans.
This chapter begins with a description of Web applications and Web contain-
ers. It discusses the use of the Common Gateway Interface, servlets, and JSP tech-
nology for providing dynamic and interactive content. It describes what situations
require the use of servlets and when to use JSP technology and how to design the
interface of a Web-based application with internationalization and localization in
mind. Review of various design patterns for Web application will follow. Finally
we will discuss migration strategies from Web-centric to EJB-centric applications.
4.1 Web Applications and Web Containers
In the J2EE lexicon, a Web application is a collection of HTML/XML documents,
Web components (servlets and JSP pages), and other resources in either a directory
structure or archived format known as a Web ARchive (WAR) file. A Web applica-
tion is located on a central server and provides service to a variety of clients.
CHAPTER 4 THE WEB TIER76
Web applications provide dynamic and interactive content to browser-based
clients. Browser-based Web applications can be used for any type of application:
from secure business-to-business applications to electronic commerce Web sites.
A Web container is a runtime environment for a Web application; a Web
application runs within a Web container of a Web server. A Web container pro-
vides Web components with a naming context and life cycle management. Some
Web servers may also provide more services, such as security, concurrency, trans-
actions, and swapping to secondary storage. A Web server may work with an EJB
server to provide such services. A Web server need not be located on the same
machine as the EJB server. In some cases, a Web container may communicate
with other Web containers.
4.2 Dynamic Content Creation
In the Internet world, the need to deliver dynamically generated content in a main-
tainable fashion is extremely important. This content may be personalized to an
individual. Great care must be taken when designing the user experience of an appli-
cation because it will distinguish one application from another and potentially make
or break a company.
The sample application is an example of a Web application that delivers
dynamically generated content. The underlying data that is used to generate the
content for the sample application can be changed without modifying the sample
application code. This would allow the administrator of the application to add new
products or services which would immediately be available in the application. The
sample application was designed to be general enough to not be tied to any
product or service. With little effort, the sample application could be tailored to
offer different products or services.
In this section we will discuss the technologies used to design a personalized
Web application in which the logic that drives the application is separate from the
content. We will begin by examining the conventional technology used to generate
dynamic content, namely Common Gateway Interface (CGI) scripts. Following the
discussion of CGI we will review the features of Java servlets and JavaServer
Pages technology.
4.2.1 Common Gateway Interface
While the Internet was originally designed to provide static content, the need to
present dynamic content, customized to a user’s needs, has quickly come to drive
DYNAMIC CONTENT CREATION 77
the development of Web technology. The earliest response to this need was the
Common Gateway Interface (CGI). This interface allows Web servers to call scripts
to obtain data from (or send data to) databases, documents, and other programs, and
present that data to viewers via the Web. However, CGI technology has a number of
limitations.
One limitation is that the code within a CGI script that accesses resources,
such as a file system or database, must be specific to the server’s platform. There-
fore most CGI applications will not run on another server platform without modi-
fication. This limits their utility in a distributed environments where Web
applications may need to run on multiple platforms.
Second, because a new process must be created each time a CGI script is
invoked, CGI scripts are often resource intensive and slow and thus tend not to
scale well. Increasing the amount of hardware will allow a CGI application to
scale to a point. However, the extent to which the application will scale is limited
to the hardware and the operating system.
Finally, CGI applications are difficult to maintain because they combine
content and display logic in one code base. As a consequence, two types of exper-
tise are needed to maintain and update CGI scripts.
Many Web server vendors have enhanced CGI for their specific products and
have developed better ways of handling CGI-like functions by providing exten-
sions to their products. These have enabled the development of sophisticated Web
applications based on CGI. However, the root problems still exist: CGI applica-
tions are platform-specific, do not scale well, and are difficult to maintain.
The J2EE platform supports two technologies, servlets and JavaServer Pages,
that provide alternate solutions that overcome these problems.
4.2.2 Servlets
Java servlets are a means of extending the functionality of a Web server. Servlets can
be viewed as applets that run on the server. Servlets are a portable platform- and
Web server-independent means of delivering dynamic content. A browser-based
application that calls servlets need not support the Java programming language
because a servlet’s output can be HTML, XML, or any other content type.
Servlets are written in the Java programming language. This allows servlets to
be supported on any platform that has a Java virtual machine and a Web server
that supports servlets. Servlets can be used on different platforms without recom-
piling. They can use generic APIs such as JDBC to communicate directly with
CHAPTER 4 THE WEB TIER78
existing enterprise resources. This simplifies application development, allowing
Web applications to be developed more rapidly.
Servlets are extensible because they are based on the Java programming lan-
guage. This allows developers to extend the functionalities of a Web application
just as they would a Java application. A good example of this would be a control-
ler servlet that is extended to be a secure controller. All of the functionalities of
the original controller would be provided along with new security features.
Servlets perform better than CGI scripts. A servlet can be loaded into memory
once and then called as many times as needed and scale well without requiring
additional hardware. Once a servlet is loaded into memory it can run on a single
lightweight thread while CGI scripts must be loaded in a different process for
every request. Another benefit of servlets is that, unlike a CGI script, a servlet can
maintain and/or pool connections to databases or other necessary Java objects
which saves time in processing requests.
Servlets eliminate much of the complexity of getting parameters from an
HTTP request; components have direct access to parameters because they are pre-
sented as objects. With CGI-based applications, parameters posted from a form
are converted to environment properties which must then read into a program.
One of their greatest benefits is that servlets provide uniform APIs for main-
taining session data throughout a Web application and for interacting with the user
requests. Session data can be used to overcome the limitations of Web applica-
tions due to the stateless nature of HTTP.
4.2.3 JavaServer Pages Technology
JavaServer Pages (JSP) technology was designed to provide a declarative, presenta-
tion-centric method of developing servlets. Along with all the benefits servlets offer,
JSP technology offers the ability to rapidly develop servlets where content and
display logic are separated, and to reuse code through a component-based architec-
ture.
Both servlets and JSP pages describe how to process a request (from an HTTP
client) to create a response. While servlets are expressed in the Java programming
language, JSP pages are text-based documents that include a combination of
HTML and JSP tags, Java code, and other information. Although both servlets
and JSP pages can be used to solve identical problems, each is intended to accom-
plish specific tasks. Servlet technology was developed as a mechanism to accept
requests from browsers, retrieve enterprise data from application tier or databases,
perform application logic on the data (especially in the case where the servlet
DYNAMIC CONTENT CREATION 79
accessed the database directly), and format that data for presentation in the
browser (usually in HTML). A servlet uses print statements to post HTML data,
both hard-coded tags and dynamic content based on the enterprise data retrieved
from the back-end tiers, back to the user’s browser.
Embedding HTML in print statements causes two problems. First, when
HTML is embedded in the print statements of a servlet, Web designers cannot
preview the look and feel of an HTML page until runtime. Second, when data or
its display format changes, locating the appropriate sections of code in the servlet
is very difficult. In addition, when presentation logic and content are intermixed,
changes in the content require that a servlet be recompiled and reloaded into the
Web server.
JSP pages provide a mechanism to specify the mapping from a JavaBeans
component to the HTML (or XML) presentation format. Since JSP pages are text-
based, a Web designer uses graphical development tools to create and view their
content. The same tools can be used to specify where data from the EJB or enter-
prise information system tiers is displayed. JSP pages use the Java programming
language for scripting complex formatting, such as the creation of dynamically-
sized tables for master-detail forms. Some JSP editing tools may provide
advanced features so that a Web designer can specify the formatting of complex
data without using Java code. Alternatively, Java programmers can provide their
Web designers with a set of JavaBeans components and/or custom tags that handle
complex dynamic formatting of HTML, so that the Web designers do not need to
understand how to code in the Java programming language in order to create a
complex JSP page.
When a Web designer changes a JSP page, the page is automatically recom-
piled and reloaded into the Web server. In addition, all the JSP pages in a Web
application can be compiled prior to deploying the application for greater effi-
ciency.
Thus JSP technology allows content developers and Web application design-
ers to clearly define what is application logic and what is content. Content provid-
ers don’t need to know Java technology to update or maintain content. Instead
they can design interfaces using the JavaBeans components and custom tags pro-
vided by the Web application developer. Web application developers need not be
experts in user interface design to build Web applications. At the same time, a
Web application development and content can easily be performed by a single
person.
Like servlets, JSP technology is an efficient means of providing dynamic
content in a portable platform- or application-independent means. JSP technology
CHAPTER 4 THE WEB TIER80
also supports a reusable component model through the inclusion of JavaBeans
technology and custom tag extensions. Note that the JavaBeans components used
by JSP pages are not the same AWT or JFC JavaBeans components. These Java-
Beans components simply expose properties using get and set methods. custom
tags can be viewed as intelligent JavaBeans components with the exception that
the actions can better interact with the JSP page (see Section 4.4.2 on page 86).
In summary, JSP technology provides an easy way to develop servlet-based
dynamic content, with the additional benefit of separating content and display
logic. In a properly designed JSP page, content and application logic can be inde-
pendently updated by developers with specific expertise in each area.
Currently CGI scripts are widely used to provide dynamic content. Technolo-
gies such as servlets and the JSP technology that are scalable and easy to write
and maintain should be used instead of CGI scripts. This is driven by the need to
provide dynamic content in a platform-independent, scalable way.
4.3 Servlets and JSP Pages
In an environment where only servlet technology is available, servlets can handle
complex logic processing, navigation paths between screens, access to enterprise
data, and formatting the data into an HTML response. In an environment where both
servlet and JSP technology is available, JSP pages should be used to handle almost
all of these tasks.
The Java code used within JSP pages should remain relatively simple. There-
fore, a developer should encapsulate complex tasks within custom tags and Java-
Beans components. A sophisticated Web application can consist solely of JSP
pages, custom tags, and JavaBeans components; servlets are rarely necessary.
In this section we will review the roles that Web components can play, when to
use servlets, when to use JSP pages, and when either technology may be used.
4.3.1 Web Component Roles
Although a common view is that Web components are mainly used to provide an
application’s presentation, in the J2EE application programming model Web com-
ponents can serve two roles: as presentation components and as front components.
Presentation components generate the HTML/XML response that when rendered
determines the user interface. A JSP page acting as a presentation component may
contain reusable custom tags or presentation logic. A presentation component could
also be a servlet that produces binary data, such as an image. Front components
SERVLETS AND JSP PAGES 81
don’t do any presentation, but rather manage other components and handle HTTP
requests or convert the requests into a form that an application can understand. Front
components are useful because they provide a single entry point to an application,
thus making security, application state, and presentation uniform and easier to main-
tain.
Figure 4.1 illustrates the basic mechanism. The front component accepts a
request, then determines the appropriate presentation component to forward it to.
The presentation component then processes the request and returns the response
to the front component, which forwards it to the server for presentation to the user.
Figure 4.1 Web Component Roles
4.3.1.1 Front Components
While the sample application uses a JSP page as its front component, you could also
use a servlet. The JSP page simplifies the initialization of the Web-tier JavaBeans
components used by the sample application. However, a servlet could also perform
this initialization.
CHAPTER 4 THE WEB TIER82
The sample application front component parses all form data posted to the
page and generates the events that result from the posted data. The events gener-
ated by the front component are forwarded to a template presentation component.
Front components perform the function of a controller when used in an MVC
architecture (see Section 4.6.3 on page 103).
4.3.1.2 Presentation Components
Many Web applications have a shopping cart that contains the products that a user
has selected for purchase. In most applications the content of the shopping cart
needs to be displayed repeatedly. JSP technology can be used to iterate through the
list of items maintained in a shopping cart (implemented as a JavaBeans compo-
nent) and display the contents to the user.
The code that generates the shopping cart display should be maintainable by
content providers. Since the shopping cart JavaBeans object and JSP page that
generates the HTML representation of the shopping cart can also be used in more
than one part of an application, the presentation components used to generate the
HTML representation of the shopping cart should also be modular and reusable.
Modular design allows separation of roles. Content providers can specialize in
how content is displayed, and component developers can focus on the logic that is
used in the JavaBeans component to manipulate the shopping cart data, and on the
JSP page that generates the HTML representation of the data. Note that the data
that is presented to the user may be taken from multiple sources.
Other requirements that presentation components must address are creating a
consistent look and feel for an application while providing mechanisms for person-
alizing the user interface. For example, consider a Web site that has a personalized
banner, a navigation menu that displays only information that a user wants to see,
and the content a user wants to see. The next section describes how to design a JSP
page or set of JSP pages that allow for a consistent look and feel throughout an
application.
Presentation Component Templates
Figure 4.2 illustrates an application in which all pages share a common banner,
navigation menu, body, and footer. Each item in the example can be seen as a
component that is used to generate the final look and feel, can contain dynamic
information, and should be customizable. This is the kind of page design that can
benefit from the use of JSP templates.
SERVLETS AND JSP PAGES 83
Figure 4.2 Presentation Components
There are two ways of constructing the page shown in Figure 4.2. Depending
on the granularity that you want your application to have, you could either build
the page using custom tags and JavaBeans components or you could break up
each portion into separate JSP pages each containing the necessary custom tags
and JavaBeans components needed to generate their portions of the content, then
build the whole page from a JSP page that incorporates the others using runtime
includes.
Code Example 4.1 contains the template used to provide the screen compo-
nents depicted in Figure 4.2. The template is constructed of an included JSP page
(ScreenDefinitions.jsp), and the custom tag j2ee:insert. The content and
pages are described in the ScreenDefinitions.jsp file. The template uses the
insert custom tag to do runtime includes of the components needed to build it.
See Section 10.3.2.1 on page 259 for more discussion of the sample application’s
template mechanism.
<%@ taglib uri="Web-INF/tlds/taglib.tld" prefix="j2ee" %>
<%@ include file="ScreenDefinitions.jsp" %>
CHAPTER 4 THE WEB TIER84
<j2ee:insert template="template" parameter="HtmlTitle" />
Code Example 4.1 JSP Page Templating Mechanism
This example illustrates a clean separation between presentation logic, data,
and content. There is no Java code in this page, so it could be managed by a
content provider not familiar with the Java programming language.
We recommend using JavaBeans components or custom tags to do data ren-
dering. These can be created by a developer familiar with the Java programming
language. If JavaBeans components and custom tags are designed in a general
manner, they should be reusable in other portions of the application or in other
applications.
4.3.2 Servlets
Although JSP pages can be used for most purposes, there are some circumstances
where servlets are more appropriate. The following sections describe common uses
of servlets.
4.3.2.1 Generating Binary Data
Servlets are well suited for dynamically generating binary data such as images or a
new content type. Requests for content of that type would be mapped to servlets that
know how to generate the content, but from the Web client’s point of view, it is
merely requesting delivery of an ordinary image. The only assumption that need be
made about the client is that it supports the image format being generated.
One example of this would be a servlet that generates a graph summarizing
stock performance from data retrieved from a database or other source. This
JSP PAGE DESIGN 85
image can be kept in memory and updated every minute or so as needed. Using a
servlet to generate the data, then keeping the data in memory for ready display,
can save time and improve performance in both execution cycles and file access
time.
4.3.2.2 Extending a Web Server’s Functionality
Servlets are a portable mechanism for extending the functionality of a Web server.
For example, if a new data format must be supported, a servlet can be mapped to the
file type for the format.
A good example of a servlet that extends a Web server is the servlet that is
mapped to JSP files. This servlet parses all files that end with a jsp file extension
and compiles the JSP pages into servlets. The resulting servlets are then executed
by the Web container and the resulting response is sent back to the client.
4.3.3 JSP Pages Versus Servlets
Depending on the composition of your development team, time constraints, and
application architecture, your use of JSP pages and servlets will differ. Both technol-
ogies have merits and should be used accordingly. In some cases there is not a single
correct choice of whether to use a servlet or JSP page.
Servlets are a programmatic tool and are best suited for low-level application
functions that don’t require frequent modification.
JSP pages are a presentation-centric, declarative means of binding dynamic
content and logic. JSP pages should be used to handle the HTML representation that
is generated by a page. They are coded in HTML-like pages with structure and
content familiar to Web content providers. However, JSP pages provide far more
power than ordinary HTML pages. JSP pages can handle application logic through
the use of JavaBeans components and custom tags. JSP pages themselves can also
be used as modular, reusable presentation components that can be bound together
using a templating mechanism.
4.4 JSP Page Design
JSP pages are unique in that they can contain both presentation logic and content.
They provide a variety of options for designing applications that are easy to main-
tain and extend. The options available for binding content to logic include Java-
CHAPTER 4 THE WEB TIER86
Beans components, custom tags, and scriptlets. The following sections describe
some of these options and recommend when to use each.
4.4.1 JavaBeans Components
JavaBeans technology is useful for building portable and reusable components that
can used in conjunction with JSP technology. There are many ways to use Java-
Beans components within an application.
One way to use JavaBeans components is as data-centric model objects. If
these beans are created specifically to manipulate and return data, they can be
used by multiple views of an application and by many different clients at one time.
In conjunction with a front component, a JavaBeans component can be used
as a controller. The sample application uses a JavaBeans component to process all
requests received from the front component and pass them along to the appropri-
ate page.
Page-specific JavaBeans components provide the logic to process data and
generate a result for a particular page. The disadvantage of using these types of
beans is that they are more difficult to reuse.
4.4.2 Custom Tags
Custom tags are the mechanism provided by JSP technology for defining custom-
ized, declarative, and modular functionality for use by JSP pages. Custom tags are
delivered as tag libraries and are imported into a JSP page using the taglib direc-
tive. Once imported, a custom tag can be used in the page using the prefix defined by
the directive.
Custom tags provide the same functionality as JavaBeans components. How-
ever, unlike JavaBeans components which must first be declared and then
accessed using get and set methods, custom tags work with a page by obtaining
initialization information through parameters defined when the tag is created.
Custom tags have access to the Web container and all the objects available to JSP
pages. Custom tags can modify the generated response. Custom tags can also be
nested within one another, allowing for complex interactions with a JSP page.
Custom tags are portable and reusable. They are written in the Java program-
ming language which allows them to be used across platforms and Web contain-
ers. If you plan on reusing custom tags, you should take care to design tags that
are not application-specific.
JSP PAGE DESIGN 87
Custom tags are ideal for iterating through data and generating the HTML
code needed to render a page. For example, a custom tag could take the data con-
tained within a shopping cart JavaBeans component and generate the HTML to
render the shopping cart. Proper use of custom tags can reduce, if not eliminates,
the amount of Java language code used in a JSP page to generate dynamic content.
Portions of a page that require logic, such as looping or state display, are also
good places to use custom tags.
The template page in Code Example 4.1 provides a familiar interface to a
designer or HTML authoring tools. The custom tags in the page appear as HTML
tags. In contrast, Java language code can get corrupted by a tool or page designer not
familiar with the Java programming language.
In addition to rendering HTML, custom tags can be used to process data. This
can reduce the amount of Java language code needed within an application and
make portions of an application configurable by a page designer.
Code Example 4.2 shows one such use for custom tags: as a switch statement
for processing user input. The CreateTemplate custom tag creates a Template
object and places it in the request containing the data necessary to render the
current page. The CreateTemplate tag has nested tags that correspond to case
statements in a switch statement. These nested tags include Screen tags which in
turn have Parameter tags nested within them. Depending on the current screen ID
obtained from the ScreenManager, the proper Template object will be created and
the parameters will be set to reflect the appropriate page components. The Tem-
plate object is processed by the JSP templating mechanism illustrated in Code
Example 4.1. Notice that expressions within the tag parameters are used to inter-
act with sample application data.
CHAPTER 4 THE WEB TIER88
Code Example 4.2 Data-Centric Custom Tags
4.4.3 Using Scriptlets and Expressions
When designing a Web site with interactive and dynamic content, it may be neces-
sary to use small portions of code to generate content. Scriptlets are small fragments
of scripting code whose language is defined by the language parameter in the JSP
page directive. Expressions are like scriptlets, except that they are played directly in
the response.
To make code easier to read and maintain, we recommend that JSP pages be
used mainly for presentation. While a major portion of an application could be
developed in JSP technology, placing large amounts of code in JSP pages makes
them more difficult to update and can be confusing to page designers.
We recommend including Java code only when necessary. JavaBeans compo-
nents and custom tags provide a means of adding functionality while avoiding
scriptlets. A developer can use expressions with JavaBeans components or custom
tags to generate dynamic content.
4.5 Internationalization and Localization
Internationalization may sometimes be overlooked when developing a Web applica-
tion targeted at a particular enterprise or localized market. However, it is becoming
increasingly important when developing a Web application that may be used in
more than one country or region that you consider internationalization from the
outset. This section presents approaches to developing an internationalized Web
application.
Internationalization is the process of preparing an application to support
various languages, while localization is the process of adapting an international-
ized application to support a specific language or locale. A locale is a language or
subset of a language that includes both regional and language-specific informa-
tion. Internationalization involves identifying and isolating portions of the appli-
cation that present strings of data to the user so that the strings can be acquired
INTERNATIONALIZATION AND LOCALIZATION 89
from a single source such as a file. Localization involves translating these strings
into a specific language and assembling them in a file that the application can
access. Thus internationalizing an application allows it to be easily adapted to new
languages and markets while localization provides the adaptation of an interna-
tionalized application to a particular country or region. Neither the Web nor EJB
container need be running in the same locale as the client’s Web browser.
Internationalization should not be an afterthought when developing a Web
application. It is easier to design an application that is capable of being internation-
alized than to retrofit an existing application, which can be both costly and time con-
suming. A great deal of time and money can be saved by planning for
internationalization and localization at the outset of a project.
An application written in the Java programming language is not automatically
internationalized and localizable. Though a developer of a Web application can
deal with many different character sets by using the J2SE platform, the platform’s
support for Unicode 2.0 is only as good as the data that is input into the applica-
tion.
With a Web application, the presentation layer is the focus of internationaliza-
tion and localization efforts. This includes the JSP pages and supporting helper
JavaBeans components.
4.5.1 Internationalization
Data handling is one part of a Web application most affected by internationalization,
with impact in three areas: data input, data storage, and locale-independent data pre-
sentation.
4.5.1.1 Data Input
Data is typically input to a Web application by posts from a form on an HTML page.
We assume that the client’s platform will provide a means for inputting the data.
The browser running in the client’s native locale is responsible for encoding
the form parameter data in the HTTP request so that it reaches a Web application
in a readable format. By the time the application receives the data it is in Unicode
format and a developer should not have to worry about character set issues. If you
need to do any type of word breaking or parsing it is recommended that you look
at the BreakIterator class in the java.text package.
CHAPTER 4 THE WEB TIER90
4.5.1.2 Data Storage
Setting your database to a Unicode 2.0 character encoding (such as UTF-8 or UTF-
16), allows data to be saved correctly in many different languages. The content you
are saving must be entered properly from the Web tier and the JDBC drivers must
also support the encoding you choose. Refer to your data storage vendor for the best
means of providing data persistence.
4.5.1.3 Enabling Locale-Independent Data Formatting
An application must be designed to present localized data appropriately for a
target locale. For example, you must ensure that locale-sensitive text such as dates,
times, currency, and numbers are presented in a locale-dependent way. If you design
your text-related classes in a locale-independent way, they can be reused throughout
an application. The following methods are used to format currency in locale-specific
and locale-independent ways.
Code Example 4.3 illustrates how to format currency in a locale-specific
manner. The NumberFormat class obtained will be the default NumberFormat for the
system. Note that the string pattern contains a “$” character. This method will
only display correctly for countries that use dollars. There is not much value with
this approach because it is tied to a specific locale.
public static String formatCurrency(double amount){
NumberFormat nf = NumberFormat.getCurrencyInstance();
DecimalFormat df = (DecimalFormat)nf;
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
df.setDecimalSeparatorAlwaysShown(true);
String pattern = "$###,###.00";
df.applyPattern(pattern);
return df.format(amount);
}
Code Example 4.3 Locale-Specific Currency Formatting
Code Example 4.4 shows how to format currency in a locale-independent
manner. The user can specify any supported locale and the resulting String will
INTERNATIONALIZATION AND LOCALIZATION 91
be formatted for that locale. For best results, the string pattern should be obtained
from a resource bundle.
public static String formatCurrency(double amount, Locale locale){
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
DecimalFormat df = (DecimalFormat)nf;
df.setMinimumFractionDigits(2);
df.setMaximumFractionDigits(2);
df.setDecimalSeparatorAlwaysShown(true);
String pattern = "###,###.00";
return df.format(amount);
}
Code Example 4.4 Locale-Independent Currency Formatting
In a JSP page, the functions described in Code Example 4.3 and Code
Example 4.4 for formatting currency can be used by including the following code:
<%=JSPUtil.formatCurrency(cart.getTotal(), Locale.JAPAN)%>
This expression uses the method formatCurrency which is located in a class
named JSPUtil. The total that is returned from the cart.getTotal method is a
double. Note that when using this code you will need to import the
java.util.Locale and com.sun.estore.util.JSPUtil classes.
4.5.2 Localization
Once an application has been internationalized it can be localized. This section
focuses on techniques for delivering localized content to clients. It also reviews
techniques for delivering localized content through the use of resource bundles and
language-specific JSP files.
4.5.2.1 Delivering Localized Content
Care must be taken to ensure that the application being developed handles data in
code sets other than the default ISO 8859-1 (Latin-1). Many Java virtual machines
CHAPTER 4 THE WEB TIER92
will support code sets other than English. A detailed listing of character sets sup-
ported by Sun’s Java virtual machine can be found at:
http://java.sun.com/products/jdk1.2/docs/guide/
intl/encoding.doc.html
Depending on what content is delivered to the users, localization can be done
in a few different ways. Web applications can be designed to deliver localized
content based on a user preference or to automatically deliver localized content
based on information in the HTTP request.
When an application allows users to select a language, the preferred language
can be stored in the session. The selection can occur through a URL selection or a
form post that sets an application-level language preference. The posted prefer-
ence data can be maintained as part of a user profile as a cookie on the client’s
system using a cookie or in a persistent data store on the server. Giving users the
ability to select a language ensures that the user gets the content that they expect.
Applications can also automatically deliver localized content by using
Accept-Language attribute in header information of the HTTP request and
mapping it to a supported locale. The Accept-Language attribute is set in the
user’s Web browser and differs slightly between browsers. When using automatic
application-level locale selection, it is prudent to also provide a mechanism to let
the user override the automatic selection and select a preferred language. Auto-
matic locale selection also depends on application support for different locales.
Care needs to be taken to ensure that unsupported languages are handled properly.
4.5.2.2 Localized Messages
The Java programming language provides facilities for localization. This section
discusses methods of providing localized data in a Web application.
In some cases an application may need to support multiple languages on the
same JSP page. List resource bundles are also useful when using servlets. Code
Example 4.5 shows how to deliver content from a user-specified locale using a
ListResourceBundle.
public class WebMessages extends java.util.ListResourceBundle{
public Object [][] getContents(){
return contents;
}
static final Object[][] contents = {
INTERNATIONALIZATION AND LOCALIZATION 93
//Messages
{"com.sunw.messages.welcome",
"Welcome to Java(TM) Pet Store Demo"},
{"com.sunw.messages.any_message",
"Untranslated message},
{"com.sunw.messages.come_back_soon", "Come Back Soon"}
}
}
Code Example 4.5 English Resource Bundle
In this example, localized content for messages in each supported language is
contained in separate files. Code Example 4.6 demonstrates a similar resource
bundle file that contains Japanese messages.
public class WebMessages_ja extends java.util.ListResourceBundle{
public Object [][] getContents(){
return contents;
}
static final Object[][] contents = {
//Messages
{"com.sunw.messages.welcome",
"Japanese welcome Java(TM) Pet Store Demo"},
{"com.sunw.messages.come_back_soon",
"Japanese Come Back Soon"}
}
}
Code Example 4.6 Japanese Resource Bundle
Inside a servlet or JSP page, the messages contained in a resource bundle can
be obtained with the code shown in Code Example 4.7.
// set the user's desired locale
session.setValue("preferredLocale", Locale.JAPAN);
// load preferred locale
CHAPTER 4 THE WEB TIER94
ResourceBundle messages = ResourceBundle.getResource("WebMessages",
(Locale)session.getValue("preferredLocale");
Code Example 4.7 Getting Messages From a Resource Bundle
Note that the Japanese resource bundle’s class file name ends with “_ja”.
When loading resources, the Japanese version of the resource bundle file will be
loaded if Locale.JAPAN is specified in the request or the default application is
running in a Japanese locale. Also note that this file contains only the messages
that you want to appear in translation. All messages not defined in this file will be
used from the default file, which has no extension following its name.
This example shows how to specify and store a user’s preferred target lan-
guage and load messages for that language. Once the resource bundle is loaded a
message can be obtained by using the command:
messages.getString("com.sunw.messages.welcome");
In this example, messages refers to the name of the resource bundle and
welcome refers to the message that you would like to load. You need to ensure that
the contentType of the page is set to an encoding that supports multiple languages
(the next section provides details on setting the contentType). UTF-8 encoding
allows you to display multiple languages on a single Web page. Moreover, UTF-8
encoding is supported by the most commonly used Web browsers.
It may be useful to create a JavaBeans component to assist in loading and
managing the messages for an application to save resources. The details of how to
create this type of component aren’t covered in this document.
Resource bundles are useful for providing localized content as long as the
logic for displaying internationalized text is not going to be greatly changed by
the target locale. If the logic changes, it is recommended to use separate JSP files
for the content, as described in the following section.
Localized Content in JSP Pages
Where you need to provide messages that vary depending on the target locale, or
where the content and display logic are drastically different, it is better to use a com-
pletely different JSP file.
Since JSP pages are responsible for the presentation of a Web application’s
user interface, they provide an ideal place to put locale-specific information. It is
INTERNATIONALIZATION AND LOCALIZATION 95
important that the JSP pages and the supporting JavaBeans components and tag
libraries be able to deal with localized content. This section discusses how to
design a localized page and how to integrate this page into a Web application.
The encoding of a JSP page must be specified in order for the Web container
to process it. An Application Component Provider sets the encoding of a JSP page
using the contentType attribute of the page directive. This attribute sets the encod-
ing for both the JSP page and the subsequent output stream. The value of con-
tentType should be “TYPE” or “TYPE;charset=CHARSET” followed by a “;” and a
valid IANA registry value. The default value for TYPE is text/html; the default
value for the character encoding is ISO-8859-1. The IANA registry values can be
found at:
ftp://venera.isi.edu/in-notes/iana/assignments/character-sets
If you are using the contentType attribute of the page directive, the resulting
output stream should not be a problem; otherwise, you will need to ensure the
output stream is set properly. Keep in mind that when using the page directive you
can only set the content type once, because a page directive is set at page compile
time. If it is necessary to change the content type dynamically, you can do so with
a servlet.
When using servlets it is important to set the response encoding correctly. The
ServletResponse interface contains a setLocale method which should be used to
ensure that data is set to the proper locale. The Servlet specification indicates that
the locale should be set before calling the getWriter method. For more details,
refer to the Servlet specification.
To prepare an application for localization, you should follow these steps:
1. Separate the display logic from the content in the presentation layer (JSP) of
the Web application. This makes localizing content easier and prevents inte-
gration errors which could occur if portions of the display logic were localized
by accident.
The J2EE programming model recommends that you deliver locale-spe-
cific files that follow the naming convention used by resource bundles. This
naming convention is the base file name followed by an underscore (_) and the
language variant. A country and a variant can also be used:
a. Language
jsp + _ + language
CHAPTER 4 THE WEB TIER96
b. Language and country
jsp + _ + language + _ + country
c. Language with country and a variant
jsp + _ + language + _ + country + _ + variant
2. Ensure that the character encoding of the localized files is supported by the
Java virtural machine of the system running the Web application. Also, be sure
that the correct encoding is listed in the contentType tag included in the page
directive of the JSP page.
A properly internationalized application can be quickly localized for any
number of languages without any modifications to the code of the Web applica-
tion. It is much easier to internationalize an application the beginning of a devel-
opment cycle when application design is first specified.
4.6 Application Designs
There are many ways to design a Web application. The complexity of an application
depends on various needs and requirements such as limitations on application devel-
opment, capabilities of the development team, longevity of an application, and
dynamism of the content in an application. Even if the original application is not
intended for widespread use, it is always benefical to design an application in such a
way that it can be migrated to a scalable, multitier design as a project’s scope
changes.
Four general types of Web applications can be implemented with the J2EE
platform: basic HTML, HTML with basic JSP pages, JSP pages with JavaBeans
components, and highly-structured applications that use modular components and
enterprise beans. The first three types of applications are considered to be Web-
centric, whereas the last type is EJB-centric. The spectrum of application designs
is presented in Figure 4.3.
APPLICATION DESIGNS 97
Figure 4.3 Application Designs
4.6.1 Applications with Basic JSP Pages and Servlets
Web applications with basic JSP pages and servlets are similar in complexity to con-
ventional HTML and CGI-based applications widely deployed on the Web, except
that the dynamic portions of the pages and user interaction are handled by JSP or
servlets in place of CGI scripts.
HTML applications with basic JSP pages are entry-level Web applications
with much of their logic in servlets or JSP pages. These applications can be devel-
oped quickly, but are more difficult to extend and maintain.
In these simple applications, some pages display static HTML content. Where
necessary to display dynamic content, (for example, content generated using data
from a database), a JSP page or servlet should contain code to connect to the data-
base and retrieve the data.
In these simplest applications, the layout will not change frequently. The
content used for the page layout of the application will be tied to the application.
CHAPTER 4 THE WEB TIER98
This means that changes to dynamic pages can only be made by an engineer or
page designer familiar with the Java programming language.
Figure 4.4 Applications with Basic JSP Pages and Servlets
Including much of the logic in JSP pages or servlets is good for prototyping
an application or for controlled environments, such as intranet sites, where the
application is not expected to be used by a large number of users.
As the complexity of the application increases, a model that allows for more
modularization of components would be useful. The next section describes how to
handle more complex user interaction or dynamic data processing.
4.6.2 Applications with Modular Components
When developing Web applications with dynamic content and a large degree of user
interaction, you should use JSP pages with JavaBeans components, custom tags, and
included JSP pages. These three types of components can be used to generate con-
tent, process requests, and handle the display of personalized content.
Figure 4.5 shows a path that a user might take through a hypothetical, interac-
tive Web application and shows how reusable components can be used at each
step in the process.
APPLICATION DESIGNS 99
Figure 4.5 Process Flow of JSP Pages with Modular Components
Although this example appears simple, a number of components are needed to
take the user through the process. Creating more modular components will allow
for more code reuse and make the application more maintainable.
Let’s look at each of the steps in more detail.
4.6.2.1 Modular Components in a JSP Page
JSP pages can be created using a variety of components. Used consistently, these
components provide a common look and feel throughout an application. This tech-
nique is similar to templates, yet each page can be unique if needed. Figure 4.6
shows how to design a JSP page that contains products obtained from a catalog
implemented as a JavaBeans component.
In this example the file banner.jsp contains a reusable component. Putting
the logic to display the banner for the site in one JSP page means that the banner
code does not need to appear on each page. Instead, the JSP page containing the
banner code is added to each page using a runtime include.
In the center of the page, the body is generated using data from the Catalog
component (and possibly some custom tags for HTML rendering of the data). A
Catalog connects with an external data source using a connection obtained from
the JDBC connection pool JavaBeans component. A Catalog is also responsible
for updating the data or holding data that has been previously entered in the appli-
cation.
CHAPTER 4 THE WEB TIER100
Figure 4.6 Reusable Components in a JSP Page
4.6.2.2 Processing Requests with Modular Components
Processing user requests is another important aspect of Web application behavior
that can be effectively implemented using modular components. Applications that
use modular components for request processing will be easier to develop and
maintain. Figure 4.7 depicts how data from a form can be processed in a Web
application.
In this example, a user submits data from a browser. The data is posted to the
process request bean, which extracts the user data and converts it into account data
maintained by a the account bean JavaBeans component. The account data is
stored in a database using a JDBC connection obtained from the JDBC connection
pool bean, also a JavaBeans component. If the data was entered correctly, the
APPLICATION DESIGNS 101
process request bean forwards the user to the appropriate page confirming the cre-
ation of the account.
Figure 4.7 Processing a Request with Reusable Components
To avoid confusion, JavaBeans components that interact with users and exter-
nal data (in this example, the bean that processes requests) should be separate
from the components that represent that data (the account JavaBeans component).
This separation of content and data enables the components to be reused and the
application as a whole to be migrated to a more complex design as its scope
changes.
4.6.2.3 Displaying Personalized Content
A JSP page that displays the personalized content is similar to the example shown
in Figure 4.6 except that the displayed data is obtained from the account bean.
The data used to generate the content of this page includes data entered by the
user. The page can also include other information personalized to the user’s needs.
After setting up an account, the users can be taken directly to a personalized page
each time they log into the application. Data reflecting a user’s previous visits can
be saved as part of the user account and used to drive the content of the applica-
tion seen by that user.
CHAPTER 4 THE WEB TIER102
Figure 4.8 Displaying Personalized Content in a JSP Page
This type of application can be used in many types of situations. However, as
an application using this design becomes larger, the level of complexity increases.
More of the developer’s time may be for work on the system-level issues such as
managing the connection pool and application state and transaction management.
Migrating to an EJB-centric design will allow the developer to stay focused on the
application design.
A well-designed application using JSP pages with JavaBeans components and
custom tags will have a clean separation of business from display logic. The
content will be easier to modify and the components, if designed well, will be
reusable. The major weakness of this design is the need for developers to provide
connections to legacy applications and transaction support. As an application
APPLICATION DESIGNS 103
becomes more complex and the need for more transactional support and external
resource integration becomes an issue, a more structured approach is required.
4.6.3 EJB-Centric Applications
An EJB-centric application extends the modular, component-based application
described in the previous section, with two main differences. First, this design uses a
front component for a controller. Second, data represented by the JavaBeans compo-
nents is maintained by enterprise beans. This design provides flexibility, manage-
ability, and separation of developer responsibilities.
Flexibility is provided by using a MVC architecture in conjunction with a
front component. The MVC architecture allows for a clean separation of business
logic, data, and presentation logic. This design also enables content providers and
application developers to focus on what they do best. The sample application uses
an MVC architecture to separate business from presentation logic.
Figure 4.9 shows how an MVC architecture can be implemented using JSP
pages, servlets, and JavaBeans components.
Figure 4.9 Model-View-Controller Architecture
As illustrated in the figure, the logic driving the application is separate from
the presentation logic and from data presented to the user. This design is similar to
the design in the previous section, except that a central controller receives all
requests and updates the JavaBeans components that contain view data.
Now let us explore each part of the MVC architecture and consider how a
Web application can benefit from it.
CHAPTER 4 THE WEB TIER104
4.6.3.1 Model
The model represents the data on which an application is based. In an EJB-centric
application, enterprise beans hold the data needed by the application. All modifica-
tions to the data occur thorough events sent to the EJB controller.
4.6.3.2 View
A view presents the data represented by the model in a way that’s targeted at a spe-
cific type of client. Most enterprise applications will support a number of different
views. The same model could have a Visual Basic client view, a Swing view, or a
Web view. The view for a Web application consists of JSP files, which have sole
responsibility for displaying the model data. The JSP files can contain JavaBeans
components, custom tags, or included JSP page components (as described in
Section 4.6.2.1 on page 99).
JSP pages should only contain code related to the display of model data.
Repetitive HTML rendering, such as banners and navigation bars, should be
handled by custom tags or JavaBeans components whenever possible. Miscella-
neous tasks such as locale-specific currency formatting should be handled by
custom tags or by helper classes.
The view can employ a templating mechanism, as described in “Presentation
Component Templates” on page 82, to provide a consistent look and feel for an
application.
In the sample application, the model data maintained by enterprise beans is
mirrored by JavaBeans components that reside in the Web tier. The components in
the Web tier allow the data maintained by the enterprise beans to be easily dis-
played by a JSP page. The JavaBeans view objects are responsible for updating
themselves with the data maintained by the enterprise beans that they mirror.
These JavaBeans components register with the Web controller to listen for model
update events received from the EJB controller. When an update event is received,
JavaBeans components contact the enterprise beans they mirror and refresh the
data they contain. These JavaBeans components contain read-only data, since data
modification is the responsibility of the controller.
4.6.3.3 Controller
To ensure that a Web application runs smoothly with the Model-View-Controller
architecture, a central point of control is necessary. This is provided by using a front
component and some helper classes. This controller maintains the data in the model
APPLICATION DESIGNS 105
and ensures that the data presented by the view is consistent with the corresponding
model.
The controller provides a level of control that isn’t possible by using stati-
cally-linked Web pages. With static pages, there is no guarantee that all users of a
Web site will use the preferred point of entry. Without a single entry point, it is
difficult to ensure that a Web application will be properly initialized to handle a
user’s request. A controller can also provide a way to prevent deep linking to
information within a site.
In designing a controller-centric application, a Web application developer can
use a front component to receive all requests. A front component works with some
JavaBeans components and enterprise beans that act as the controller. The control-
ler components span both the Web tier and the EJB tier. The design of the compo-
nents to create a controller that spans both the Web and EJB tiers is described in
the following section.
Controller Components
The controller is made up of many components responsible for taking data posted in
an HTTP request and converting it into an event to update the model data. The com-
ponents that make up the controller include: front component, request processor,
Web controller, and EJB controller.
Figure 4.10 is a diagram of a controller that converts an HTTP request into an
event that updates the application model data. This figure shows the flow of an
HTTP request from an HTTP client to the controller mechanism. As mentioned
before, all requests from HTTP clients go to a front component. The requests are
then sent to the request processor, which converts them to events and then sends
the events to the Web controller. The Web controller acts as a proxy and sends the
event to the EJB controller, which processes the event and updates the model data
maintained by the enterprise beans accordingly.
All business logic is handled by the EJB controller and enterprise beans. The
EJB controller returns a set of changed models to the Web controller. The Web
controller then sends the model update events to the respective views. The views
then contact the enterprise beans that they mirror and update their data from the
enterprise beans. The JavaBeans components do not change any data; they only
read the model data contained by the enterprise beans when they receive the
model update notification.
CHAPTER 4 THE WEB TIER106
Figure 4.10 Controller Conversion of HTTP Request to Model Change Event
Now that we have described the process of how model data is updated by the
controller mechanism we review each component of the controller.
• Front component
The front component is a component to which all requests for application
URLs are delivered. The front component ensures that the Web components
APPLICATION MIGRATION 107
needed by the application are initialized at the correct time and that all HTTP
requests are sent to the request processor.
• Request processor
The request processor is the link between the Web application and an
HTTP-based client. The request processor is responsible for converting HTTP
requests to events which will be used throughout the application. This compo-
nent allows the application developer to centralize all HTTP-specific process-
ing in one location. This component also allows the EJB portion of the
application to be independent of any single client type.
• Web controller
The Web controller is responsible for forwarding the event(s) generated
by the request processor component to the EJB controller. The Web controller
ensures that the resulting updated models returned from the EJB controller are
propagated to the appropriate Web-tier view JavaBeans components.
• EJB controller
The EJB controller accepts events from the Web controller and makes the
calls on the enterprise beans affected by the event. The EJB controller is also
responsible for maintaining the state of the user session with the application.
After each event is processed, the EJB controller is responsible for returning a
set of updated models to the Web controller.
In general it is best to design the EJB controller so that it is not tied to a
single type of client. This makes the application usable by both application
and Web-centric clients. The EJB controller is the only part of the Web appli-
cation allowed to manipulate the model data. Any less restrictive means of
data modification would be contrary to the MVC architecture and make it dif-
ficult to debug the application.
For more details about controller design, see the discussion of the sample
application’s controller in Section 10.6 on page 280.
4.7 Application Migration
It’s always a good practice to design an application so that it can be extended. If you
follow the Web application design path described in this chapter, this migration can
be a gradual process. However, if you are working with a preexisting application
CHAPTER 4 THE WEB TIER108
that does not resemble any of the application types listed in Figure 4.3, migration
will be more difficult.
When migrating an application it is best to first determine the type of applica-
tion you want to implement. Figure 4.3 shows a generalized migration path that
may be followed for migrating applications of different levels of complexity. The
simpler an application is, the easier it will be to migrate. The sections correspond-
ing to the columns in Figure 4.3 review what can be done to make the components
of a Web application more modular.
When migrating applications that use basic JSP pages and servlets to a more
complex design, the general theme should be to migrate components into reusable
modules. As much as possible, the application and presentation logic should be
separated using custom tags and JavaBeans components.
The most difficult migration will be from a modular, component-based appli-
cation to an EJB-centric application with enterprise beans. The following sections
review some strategies for this migration.
4.7.1 Migrating a Web-Centric Application to Use Enterprise Beans
When migrating a Web-centric application to use enterprise beans apply the follow-
ing steps:
1. Change Web portions of the application to use a front component and MVC
architecture.
2. Create enterprise beans representing model objects.
3. Move application logic to enterprise beans.
4. Move external resource communication from JavaBeans components to enter-
prise beans.
5. Minimize display logic code in JSP pages.
4.7.1.1 Centralize Application Control Using an MVC Architecture
If your Web components do not already use an MVC architecture, you will need to
modify the design. For more details on implementing an MVC architecture with
Web components and enterprise beans, refer to Section 4.6.3 on page 103.
APPLICATION MIGRATION 109
4.7.1.2 Create Enterprise Beans
You will need to create enterprise beans corresponding to the JavaBeans compo-
nents used within your application. For an EJB-centric application, you will also
need to design a controller enterprise bean. The responsibilities of the controller
enterprise bean are described in “Controller Components” on page 105. You may
also want to introduce other enterprise beans to handle other tasks, such as sending
and receiving messages.
4.7.1.3 Move Application Logic to Enterprise Beans
All application logic provided by JavaBeans components in the Web application
will need to be migrated to enterprise beans. This includes code to communicate
with external resources.
Application logic for processing events generated by the Web components
will need to be moved into the EJB controller. The EJB controller will also need
logic for returning model update events to the Web controller.
4.7.1.4 Modify JavaBeans Components
JavaBeans components originally designed to hold the model data will need to be
modified to obtain data from the enterprise beans when they receive model update
events from the EJB controller. In addition, application logic in JavaBeans compo-
nents will need to be moved to the enterprise beans representing the model.
After this modification, the JavaBeans components will become part of the
view to represent the contract between JSP pages and the model. The only other
logic that should remain in the Web container components is that tied to handling
HTTP requests and managing the flow of the application.
4.7.1.5 Minimize Display Logic in JSP Pages
JSP pages should be used to render HTML instructions. To make the JSP pages
more manageable, display logic code should be moved out of the JSP pages into
custom tags and JavaBeans components whenever possible. For more details, refer
back to Section 4.4 on page 85 of this chapter.
CHAPTER 4 THE WEB TIER110
4.8 Summary
As a medium, the Web requires application developers to create user interfaces that
are flexible and easy to maintain. Web applications can be made more flexible and
maintainable through the use of J2EE component technologies such as servlets and
JavaServer Pages which used to generate dynamic content in a portable and scalable
manner.
Enterprise Web applications should be developed using modular components.
These components include servlets, JSP pages, JavaBeans components, and tag
libraries containing custom tags. Depending on the composition of your develop-
ment team, time constraints, and application architecture, the use of JSP pages and
servlets will differ. Both technologies have merits and should be used accordingly.
Internationalization expands the potential user base of a Web application. A
properly internationalized application can be quickly localized for any number of
languages without modifications to the code. It is much easier to internationalize
an application during the design phase at the beginning of a development cycle.
Retrofitting an existing application can be difficult and expensive.
Architectures for Web applications include basic JSP pages and servlets,
Web-centric applications that use JSP pages with modular components, and EJB-
centric applications that use JSP pages with enterprise beans. A Web-centric
application can be migrated to a highly manageable, scalable, modular, EJB-
centric application by using the steps described in this chapter. Gradual migration
to a more complex design is less risky than making large-scale design changes to
an application.
About the Author
VINITA KHANNA is a Member of Technical Staff at Sun Microsystems, where she
works as an enterprise bean developer in the J2EE programming model team. Her major
contributions include best practices and guidelines when developing business solutions
using enterprise beans. Prior to the APM project Vinita was a member of the Enterprise
Software Solutions Group where she was involved in the design and development of
mission critical business applications for Sun. Vinita holds a B.Tech. degree in Electron-
ics from Kamla Nehru Institute of Technology, India and a M.S. degree in Computer
Science from California State University, Hayward.
113
C H A P T E R 5
The Enterprise JavaBeans
Tier
by Vinita Khanna
IN a multitier J2EE application, the Enterprise JavaBeans (EJB) tier hosts applica-
tion-specific business logic and system-level services such as transaction manage-
ment, concurrency control, and security. Enterprise JavaBeans technology provides
a distributed component model that enables developers to focus on solving business
problems while relying on the J2EE platform to handle complex system-level
issues. This separation of concerns allows rapid development of scalable, accessible,
and highly secure applications. In the J2EE programming model, EJB components
are a fundamental link between presentation components hosted by the Web tier and
business-critical data and systems maintained in the enterprise information system
tier.
This chapter examines the nature of business logic and describes the problems
a developer needs to resolve when implementing business logic. It then describes
the component model that the EJB tier of the J2EE platform provides to address
these problems. The chapter then presents recommendations and practices to best
utilize the services provided by the J2EE platform.
5.1 Business Logic
Business logic, in a very broad sense, is the set of guidelines to manage a specific
business function. Taking the object-oriented approach enables the developer to
decompose a business function into a set of components or elements called business
objects. Like other objects, these business objects will have both characteristics
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER114
(state or data) and behavior. For example, an employee object will have data such as
a name, address, social security number, and so on. It will have methods for assign-
ing it to a new department or changing its salary by a certain percentage. To manage
this business problem we must be able to represent how these objects function or
interact to provide the desired functionality. The business-specific rules that help us
identify the structure and behavior of the business objects, along with the pre- and
post-conditions that must be met when an object exposes its behavior to other
objects in the system, is known as business logic.
The following discussion demonstrates how to define the structure and behav-
ior of a business object from the requirements imposed by the business problem it
belongs to. For example, the sample application contains a group of business
objects: a catalog object to show available pets, a shopping cart object to tempo-
rarily hold client’s selection of pets, an account object to keep information about
clients, and an order object to keep track of placed orders. We consider the
requirements on an account object:
1. Each client must have a unique account.
2. Each account should have contact information for a client such as name, street
address, and email address.
3. Clients must be able to create new accounts.
4. Clients must be able to update contact information for their account.
5. Clients must be able to retrieve information for their account.
6. Clients can retrieve and update only their own account information.
7. The account information must be maintained in persistent storage.
8. Multiple clients must be able to access their account information at the same
time.
9. Multiple clients cannot update the same account concurrently.
The first two requirements specify the structural attributes of the account
object. Following these rules, the account object should have a field to hold
account identification and several other fields to hold address, phone, and other
contact information.
The behavior of the account object is described in requirements three, four,
and five. For example, accounts should have methods to create a new account,
update contact information, and to get the account information.
BUSINESS LOGIC 115
The last four requirements specify general conditions that must be met when
realizing the behavior of the account object. For example, when a client updates
an account, the client should be authorized to access that particular account,
updated account information should be written to persistent storage, and concur-
rent access to the account information to multiple clients should be prohibited.
Similar analysis and requirement definitions could be performed for other
objects. For example, an order object will have a set of general conditions on its
behavior that have a significant correlation to the behavior of an account object.
That is, a client needs to be authorized before updating or reading the status of an
order, order details need to be written to a persistent storage, and so on.
If you examine business objects in similar applications you will see that even
though the actual structure and behavior of the object is tied closely to the busi-
ness problem it is going to solve, many services that these business objects
provide follow specific patterns that are quite generic in nature.
5.1.1 Common Requirements of Business Objects
This section describes common requirements of business objects.
5.1.1.1 Maintain State
A business object often needs to maintain the state represented in its instance vari-
ables between the method invocations. The state can be either conversational or per-
sistent.
Consider a shopping cart object. The state of the shopping cart object repre-
sents the items and quantities of the items purchased by the client. The cart is ini-
tially empty and gains meaningful state when a user adds an item to the cart.
When a user adds another item to the cart, the cart should have both the items in it.
Similarly, when a user deletes an item from the cart, the cart should reflect the
change in its state. When a user exits the application, the cart object needs to be
reinitialized. When the object gains, maintains, and loses its state as a result of
repeated interactions with the same client we say the object maintains conversa-
tional state.
To understand persistent state, consider an account object. When a user
creates an account, the account information needs to be stored permanently so that
when the user exits the application and re-enters the application, the account
information can be presented to the user again. The state of an account object
needs to be maintained in persistent storage such as a database. Typically, the
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER116
business objects that operate on session-neutral data exhibit persistent state main-
tenance.
5.1.1.2 Operate on Shared Data
Another common characteristic of business objects is that they often operate on
shared data. In this case, measures must be taken to provide concurrency control and
appropriate levels of isolation of the shared data. An example of such a scenario
would be multiple users updating the same account information. If two users try to
update the same account at the same time, the business object should provide a
mechanism to keep the data in a consistent state.
5.1.1.3 Participate in Transactions
A transaction can be described as a set of tasks that need to be completed as a unit. If
one of the tasks fail, all the tasks in the unit will be rolled back. If all of them suc-
ceed, the transaction is said to be committed.
Business objects often need to participate in transactions. For example, order
placement needs to be transactional because of the set of tasks required to com-
plete an order—decrementing the quantity of the purchased item in the item
inventory, storing the order details, and sending an order confirmation to the user.
For the transaction to be completed, all of these tasks must succeed. If any one of
these tasks fail, work done by other tasks needs to be undone.
In many business operations, transactions may span more than one remote
data source. Such transactions—called distributed transactions—require special
protocols to ensure data integrity. In the sample application, order placement is a
distributed transaction because the inventory table and the order table reside in
different data sources.
5.1.1.4 Service a Large Number of Clients
A business object should be able to provide its services to a large number of clients
at the same time. This translates into a requirement for instance management algo-
rithms that give each client an impression that a dedicated business object is avail-
able to service its request. Without such a mechanism, the system will eventually
run out of resources and will not be able to service any more clients.
ENTERPRISE BEANS AS J2EE BUSINESS OBJECTS 117
5.1.1.5 Provide Remote Access to Data
A client should be able to remotely access the services offered by a business object.
This means that the business object should have some type of infrastructure to
support servicing clients over the network. This in turn implies that a business object
should be part of a distributed computing environment that takes care of fundamen-
tal issues in distributed systems such as location and failure transparency.
5.1.1.6 Control Access
The services offered by business objects often require some type of client authenti-
cation and authorization mechanism to allow only a certain set of clients to access
protected services. For example, an account business object needs to validate the
authenticity of the client before allowing it to update its account information. In
many enterprise scenarios, different levels of access control are needed. For exam-
ple, employees are allowed to view only their own salary objects, while a payroll
administrator can view as well as modify all salary objects.
5.1.1.7 Reusable
A common requirement of business objects is that they be reusable by different
components of the same application and/or by different applications. For example,
an application used by the payroll department to keep track of employees’ salary
may have two business objects: employee and salary. A salary business object may
use the services of an employee business object to get the grade level of an
employee. An application that tracks the employee vacation allowances may want to
use this employee object to get the name of the employee through the employee
number. In order for business objects to be able to be used by inter- and intra-appli-
cation components, they need to be developed in a standard way and run in an envi-
ronment that abides by these standards. If these standards are widely adopted by the
vendor community, an application can be assembled from off-the-shelf components
from different vendors. In addition to enabling rapid application development, this
approach helps developers avoid vendor lock-in.
5.2 Enterprise Beans as J2EE Business Objects
As we discussed in the previous section, business objects need to provide some
generic services to clients, such as support for transactions, security, and remote
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER118
access, These common services are very complex in nature and are outside the
domain of the business logic required to implement an application. To simplify
development, enterprise applications need a standard server-side infrastructure that
can provide such services.
The EJB tier of the J2EE platform provides a standard server-side distributed
component model that greatly simplifies the task of writing business logic. In the
EJB architecture, system experts provide the framework for delivering system-
level services and application domain experts provide the components that hold
only business-specific knowledge. The J2EE platform enables enterprise develop-
ers to concentrate on solving the problems of the enterprise instead of struggling
with system-level issues.
To use the services provided by the J2EE platform, business objects are
implemented by EJB components, or enterprise beans. There are two primary
kinds of enterprise beans: entity beans and session beans. Session beans are
intended to be private resources used only by the client that created them. For this
reason, session beans, from the client’s perspective, appear anonymous. In con-
trast, every entity bean has a unique identity which is exposed as a primary key.
Later sections in this chapter discuss each type of enterprise bean in detail.
In addition to components, the EJB architecture defines three other entities:
servers, containers, and clients. Enterprise beans live inside EJB containers, which
provide life cycle management and a variety of other services. An EJB container
is part of an EJB server, which provides naming and directory services, email ser-
vices, and so on. When a client invokes an operation on an enterprise bean the call
is intercepted by its container. By interceding between clients and components at
the method call level, containers can manage services that propagate across calls
and components, and even across containers running on different servers and dif-
ferent machines. This mechanism simplifies development of both components and
clients.
5.2.1 Enterprise Beans and EJB Containers
The EJB architecture endows enterprise beans and EJB containers with a number of
unique features that enable portability and reusability:
• Enterprise bean instances are created and managed at runtime by a container.
If an enterprise bean uses only the services defined by the EJB specification,
the enterprise bean can be deployed in any compliant EJB container. Special-
ized containers can provide additional services beyond those defined by the
ENTERPRISE BEANS AS J2EE BUSINESS OBJECTS 119
EJB specification. An enterprise bean that depends on such a service can be de-
ployed only in a container that supports that service.
• The behavior of enterprise beans is not wholly contained in its implementation.
Service information, including transaction (described in Chapter 8) and secu-
rity (described in Chapter 9) information, is separate from the enterprise bean
implementation. This allows the service information to be customized during
application assembly and deployment. The behavior of an enterprise bean is
customized at deployment time by editing its deployment descriptor entries
(described in Chapter 7). This makes it possible to include an enterprise bean
in an assembled application without requiring source code changes or recom-
pilation.
• The Bean Provider defines a client view of an enterprise bean. The client view
is unaffected by the container and server in which the bean is deployed. This
ensures that both the beans and their clients can be deployed in multiple exe-
cution environments without changes or recompilation. The client view of an
enterprise bean is provided through two interfaces. These interfaces are imple-
mented by classes constructed by the container when a bean is deployed, based
on information provided by the bean. It is by implementing these interfaces
that the container can intercede in client operations on a bean and offer the cli-
ent a simplified view of the component. The following sections describe these
interfaces and classes: the home and remote interfaces, and enterprise bean
class.
5.2.1.1 Home Interface
The home interface provides methods for creating and removing enterprise beans.
This interface must extend javax.EJB.EJBHome. The enterprise bean’s home inter-
face allows a client to do the following:
• Create new enterprise bean instance
• Remove an enterprise bean instance
• Get the meta-data for the enterprise bean through the javax.ejb.EJBMetaData
interface. The javax.ejb.EJBMetaData interface is provided to allow applica-
tion assembly tools to discover the meta-data information about the enterprise
bean at deployment time.
• Obtain a handle to the home interface, which provides the mechanism for per-
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER120
sistent enterprise beans. The home handle can be serialized and written to sta-
ble storage. Later, possibly in a different Java virtual machine, the handle can
be deserialized from stable storage and used to obtain a reference to the home
interface.
In addition, the home interface of an entity bean provides methods for finding
existing entity bean instances within the home. A client that knows the primary
key of an entity object can obtain a reference to the entity object by invoking the
findByPrimaryKey method on the entity bean’s home interface.
5.2.1.2 Remote Interface
The remote interface defines the client view of an enterprise bean—the set of busi-
ness methods available to the clients. This interface must extend javax.ejb.EJBOb-
ject. An EJBObject supports:
• The business methods of the object. The EJBObject delegates invocation of a
business method to the enterprise bean instance.
The javax.ejb.EJBObject interface defines the methods that allow clients to
perform the following operations on a reference to an enterprise bean instance:
• Obtain the home interface
• Remove the enterprise bean instance
• Obtain a handle to the enterprise bean instance
• Obtain an entity bean instance’s primary key
5.2.1.3 Enterprise Bean Class
The enterprise bean class is the second part of the mechanism that allows for con-
tainer-managed services in the EJB architecture. It provides the actual implementa-
tion of the business methods of the bean. It is called by the container when the client
calls the corresponding methods listed in the remote interface. This class must
implement the javax.ejb.EntityBean or javax.ejb.SessionBean interface.
In addition to business methods, the remote interface and enterprise bean class
also share responsibility for two specialized categories of methods: create
methods and finder methods. The create methods provide ways to customize the
ENTITY BEANS 121
bean at the time it is created, and the finder methods provide ways to locate a
bean.
For each create method listed in the home interface, the bean class imple-
ments the corresponding ejbCreate method. For each finder method listed in
home interface, the bean class provides the corresponding ejbFindBy... method.
The enterprise bean class must also provide implementations of the methods listed
in the interface it extends. A developer can choose to provide empty implementa-
tions of any methods in the interface that aren’t required for the specific purposes
of a bean.
Figure 5.1 illustrates the implementation of the client view of an enterprise
bean.
Figure 5.1 Implementation of Client View of Enterprise Beans
The following two sections contain in-depth discussions of the properties and
uses of entity and session beans.
5.3 Entity Beans
An entity bean represents an object view of business data stored in persistent storage
or an existing application. The bean provides an object wrapper around the data to
simplify the task of accessing and manipulating it. This object interface lends itself
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER122
to software reuse. For example, an entity bean representing user account informa-
tion can be used by order management, user personalization, and marketing in a
uniform way.
An entity bean allows shared access from multiple clients and can live past the
duration of client’s session with the server. If the state of an entity bean is being
updated by a transaction at the time of server crash, the entity bean’s state is auto-
matically reset to the state of the last committed transaction.
5.3.1 Guidelines for Using Entity Beans
A Bean Provider can use the following entity bean characteristics as guidelines
when deciding whether to model a business object as an entity bean:
• Representing persistent data
If the state of a business object needs to be stored in a persistent storage
and its behavior primarily represents manipulation of data represented in its
state, then it should be modeled as entity bean.
However, it should be noted that every method call to an entity object via
the remote and home interface is potentially a remote call. Even if the calling
and called enterprise beans are located in the same Java virtual machine, the
call must go through the container, which must create copies of all parameters
that are passed through the interface by value. The container also checks secu-
rity and applies declarative transaction attributes on the inter-component calls.
Therefore modeling every object representing a row in the database as an
entity bean is not recommended. An entity bean is better suited to represent a
coarse-grained business object that provides more complex behavior than
only get and set methods for its fields.
• Providing concurrent access by multiple clients
When the state and behavior of a business object needs to be shared
among multiple clients, they should be modeled as entity beans. This kind of
business object needs to maintain state between method calls. However, this
state is not specific to a particular client but is representative of persistent state
of the business object, typically stored in a database. By modeling such busi-
ness objects as entity beans, a Bean Provider can rely on an EJB server to
ENTITY BEANS 123
ensure appropriate synchronization for entity beans as they are accessed con-
currently from multiple transactions.
• Representing a single logical record (row) of data
The business objects that typically operate on one logical record in the
database are excellent candidates to model as entity beans. In fact, entity
beans are designed to represent an individual (logical) record in the database.
Entity beans provide methods to locate, create, and manipulate one row at a
time.
• Providing robust, long-lived persistent data management
A business object that needs to live after a client’s session with the server
is over or that needs to be present when the server comes back after a crash,
should be modeled as an entity bean. Entity beans live even after a client’s
session with the server is over and can even survive server crashes. If the state
of an entity bean is being updated by a transaction at the time of server crash,
the entity bean’s state is automatically reset to the state of the last committed
transaction.
5.3.1.1 Example: A User Account Bean
The concept of a user account is central to all clients in many e-commerce applica-
tions. Multiple clients need to share behavior such as creating an account, verifying
an existing account, and updating account information. Updates to the state of an
account object need to be written to persistent storage and an account object lives
even when the client’s session with the server is over. Therefore, in the sample appli-
cation, an account object is modeled as entity bean.
To avoid expensive remote methods to get the value of account objects fields,
the sample application uses a value object (discussed in Section 5.5.2 on page
134) to represent account details. Only one remote call is required to retrieve the
value object and then a client’s request to query the state of an account object can
then be satisfied via local get methods on this details object. Similarly, to avoid
fine-grained set methods, the sample application uses a coarse-grained method to
update all account information via one remote call. Code Example 5.1 shows the
remote interface of the Account enterprise bean and the implementation of
AccountDetails.
public interface Account extends EJBObject {
public void changeContactInformation(ContactInformation info)
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER124
throws RemoteException;
public AccountDetails getAccountDetails()
throws RemoteException;
}
public class AccountDetails implements java.io.Serializable {
private String userId;
private String status;
private ContactInformation info;
public String getUserId() {
return userId;
}
...
}
Code Example 5.1 Account Remote Interface and AccountDetails Class
Like most entity beans, the account bean provides an object view of data
stored in a database and most of its code revolves around connecting to, accessing,
and updating database tables. The next section discusses options for implementing
data access logic for entity beans.
5.3.2 Persistence in Entity Beans
The protocol for transferring the state of an entity between the enterprise bean
instance and the underlying persistent store is referred to as object persistence. An
entity bean can implement persistence in the following ways:
• Directly implementing persistence in the enterprise bean class or in one or
more helper objects provided with the enterprise bean class (bean-managed
persistence)
• Delegating the handling of its persistence to its container (container-managed
persistence)
With bean-managed persistence, the Bean Provider writes database access
calls. The data access calls can be coded directly into the enterprise bean class, or
can be encapsulated in a data access component that is part of the entity bean. If
SESSION BEANS 125
data access calls are coded directly in the enterprise bean class, it may be more
difficult to adapt the entity component to work with a database that has a different
schema, or with a different type of database. Encapsulating data access calls in a
data access object makes it easier to adapt the enterprise bean’s data access to dif-
ferent schemas or different database types. The sample application uses separate
data access objects for implementing persistence. Data access objects are dis-
cussed in detail in Section 5.5.1 on page 130.
With container-managed persistence, the Bean Provider identifies the fields to
be stored to the database and the Container Provider’s tools generate database
access calls at deployment time. The type and structure of the data source is trans-
parent to the Bean Provider. The container tools can generate classes that use
JDBC or SQL/J to access the entity state in a relational database, classes that
implement access to a non-relational data source, or classes that implement func-
tion calls to existing enterprise applications. The bean state is defined indepen-
dently of how and where it will be stored and hence is more flexible across
applications. The disadvantage is that sophisticated tools must be used at deploy-
ment time to map the enterprise bean’s fields to a data source. These tools and
containers are typically specific to each data source.
When a container supports container-managed persistence, it simplifies the
task of writing entity beans because the container takes the responsibility of gen-
erating the code to access the data source. Bean developers should take advantage
of this feature and delegate the task of saving the state of an entity bean to the con-
tainer whenever possible. Some containers may not be capable of handling
complex state objects (for example, objects representing multiple joins). In such
cases, the Bean Provider may have to use bean-managed persistence.
5.4 Session Beans
Session beans are used to implement business objects that hold client-specific busi-
ness logic. The state of such a business object reflects its interaction with a particular
client and is not intended for general access. Therefore, a session bean typically exe-
cutes on behalf of a single client and cannot be shared among multiple clients. A
session bean is a logical extension of the client program that runs on the server and
contains information specific to the client. In contrast to entity beans, session beans
do not directly represent shared data in the database, although they can access and
update such data. The state of a session object is non-persistent and need not be
written to the database.
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER126
A session bean is intended to be stateful. However, the Enterprise JavaBeans
specification allows stateless session beans as a way to provide server-side behav-
ior that doesn’t maintain any specific state. The next section discusses the proper-
ties and uses of both stateful and stateless session beans.
5.4.1 Stateful Session Beans
A stateful session bean contains conversational state on behalf of the client. A con-
versational state is defined as the session bean’s field values plus all objects reach-
able from the session bean’s fields. Stateful session beans do not directly represent
data in a persistent data store, but they can access and update data on behalf of the
client. As its name suggests, the lifetime of a stateful session bean is typically that of
its client.
5.4.1.1 Uses of Stateful Session Beans
A Bean Provider can use the following session bean characteristics as guidelines
when deciding whether to model a business object as a stateful session bean:
• Maintaining client-specific state
Stateful session beans are designed to maintain a conversational state on
behalf of a client, therefore business objects representing client-centric busi-
ness logic should be modeled as stateful session beans. Since stateful session
bean instances are tied to a client, system resources held by stateful session
beans cannot be shared among multiple clients.
• Representing non-persistent objects
Stateful session bean state is not stored in the persistent storage and can-
not be recreated after the client’s session with the server is over. Therefore,
business objects that are relatively short-lived and non-persistent should be
modeled as stateful session beans. In other words, a business object that does
not need to live after a client’s session with the server is over, or be present
when the server comes back after a crash, should be modeled as a session
bean.
• Representing work flow between business objects
The business objects that manage the interaction of various business
objects in a system are excellent candidates to be modeled as stateful session
SESSION BEANS 127
beans. Such objects usually exhibit both of the above characteristics, since
they are client specific and represent data-neutral non-persistent behavior.
5.4.1.2 Example: A Shopping Cart Bean
A shopping cart object represents the collection of products selected by a particular
user for purchase during a session. The state of the shopping cart object is specific to
a particular user session and need not be saved unless the user is ready to place an
order. The shopping cart object is short-lived. The data should not be shared, since it
represents a particular interaction with a particular user and is alive only for the
user’s session with the server. The sample application models the concept of shop-
ping cart as a stateful session bean.
As mentioned earlier, stateful session beans can also be used to model an
object that manages the interaction of various objects in the work flow on behalf
of a client. The sample application follows the MVC architecture. If the view (cli-
ent) needs to read the data (model) it does it by directly interacting with the data.
However, if the view needs to update the data, it uses the controller as a mediator.
The controller interacts with multiple objects representing data on behalf of the
view or user.
In the sample application, the controller is implemented as a stateful session
bean named ShoppingClientController. As shown in Code Example 5.2, Shop-
pingClientController is responsible for managing the life cycle of model objects
such as the shopping cart and account enterprise beans and processes business
events. For example, when a user places an order, ShoppingClientController
handles the order event.
public interface ShoppingClientController extends EJBObject {
public Catalog getCatalog() throws RemoteException;
public ShoppingCart getShoppingCart() throws RemoteException;
public Account getAccount() throws RemoteException;
public Collection getOrders() throws
RemoteException, FinderException;
public Order getOrder(int requestId) throws
RemoteException, FinderException;
// Returns a list of updated models
public Collection handleEvent(EStoreEvent se) throws
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER128
RemoteException, DuplicateAccountException;
}
Code Example 5.2 ShoppingClientController Remote Interface
5.4.2 Stateless Session Beans
Stateless session beans are designed strictly to provide server-side behavior. They
are anonymous in that they contain no user-specific data. In fact, the EJB architec-
ture provides ways for a single stateless session bean to serve the needs of many cli-
ents. This means that all stateless session bean instances are equivalent when they
are not involved in serving a client-invoked method. The term stateless means that it
does not have any state information for a specific client. However, stateless session
beans can have non-client specific state, for example, an open database connection.
5.4.2.1 Uses of Stateless Session Beans
A Bean Provider can use the following session bean characteristics as guidelines
when deciding whether to model a business object as a stateless session bean:
• Modeling reusable service objects
A business object that provides some generic service to all its clients can
be modeled as stateless session beans. Such an object does not need to main-
tain any client specific state information, so the same bean instance can be
reused to service other clients. For example, it would be appropriate to model
a business object that validates an employee ID against a database as a state-
less service.
• Providing high performance
A stateless session bean can be very efficient as it requires fewer system
resources by the virtue of being not tied to one client. Since stateless session
beans minimize the resources needed to support a large number of clients,
depending on the implementation of the EJB server, applications that use this
approach may scale better than those using stateful session beans. However,
this benefit may be offset by the increased complexity of the client application
SESSION BEANS 129
that uses the stateless session beans because the client has to perform the state
management functions.
• Operating on multiple rows at a time
A business object that manipulates multiple rows in a database and repre-
sents a shared view of the data is an ideal stateless session bean. An example
of a such business object would be a catalog object that presents a list of vari-
ous products and categories. Since all users would be interested in such infor-
mation, the stateless session bean that represents it could easily be shared.
• Providing procedural view of data
In a procedural view of data, methods of the business object do not oper-
ate on instance variables. Instead they behave like calls in a procedural lan-
guage. The method caller provides all the input and the method returns all
output to the caller. If a business object exhibits such functionality then it
should be modeled as a stateless session bean.
5.4.2.2 Example: A Catalog Bean
The sample application uses a stateless session beans to model a catalog object. A
catalog object represents different categories and products and provides browsing
and searching services to its clients. Both of the primary functions of the catalog,
browsing and searching, are generic services that are not tied to any particular client.
Also, the catalog object operates on multiple rows in the database at the same time
and provides a shared view of the data. Code Example 5.3 lists the services provided
by a catalog object:
public interface Catalog extends EJBObject {
public Collection getCategories()throws RemoteException;
public Collection getProducts(String categoryId,
int startIndex, int count)throws RemoteException;
public Product getProduct(String productId)
throws RemoteException;
public Collection getItems(String productId,int startIndex,
int count)throws RemoteException;
public Item getItem(String itemId)
throws RemoteException;
public Collection searchProducts(Collection keyWords,
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER130
int startIndex,int count)throws RemoteException;
}
Code Example 5.3 Catalog Remote Interface
Another example of a stateless session bean is the mailer object used to send
confirmation mail to clients after their order has been placed successfully. Mailer
provides a generic service that can be completed within a single method call with
its state is not tied to any particular client. Also, since the instances can be shared
among multiple clients, they are modeled as stateless session beans.
5.5 Design Guidelines
In addition to the guidelines discussed previously for choosing specific bean types,
there are other design choices that Application Component Providers must make
when developing objects for the EJB tier. These choices include what types of
objects should be enterprise beans, and what role an enterprise bean may play in a
group of collaborating components.
Since enterprise beans are remote objects that consume a significant amount
of system resources and network bandwidth, it is not appropriate to model all
business objects as enterprise beans. Only the business objects that need to be
accessed directly by a client need to be enterprise beans; other objects can be
modeled as data access objects, which encapsulate database access, and value
objects, which model fine-grained objects that are dependent on enterprise beans.
It may not be appropriate to give clients direct access to all enterprise beans
within an application. As a consequence, some enterprise beans may act as media-
tors of communication between clients and the EJB tier. A bean of this type can
encapsulate work flow specific to an application or can serve as an entry point to a
hierarchy of information keyed to an attribute of the entry-point bean.
5.5.1 Data Access Objects
To encapsulate access to data, the sample application uses data access objects. The
use of separate objects to access databases was driven by following requirements:
• Keep session bean code clear and simple
DESIGN GUIDELINES 131
• Ensure easier migration to container-managed persistence for entity beans
• Allow for cross-database and cross-schema portability
• Provide a mechanism that supports tools from different vendors
5.5.1.1 Clarifying Session Bean Implementations
Any session bean method that needs to access a database has a corresponding
method in the data access object that implements the actual logic of fetching or
updating data in the database. This makes the enterprise bean implementation much
cleaner and readable by conveying the business logic at a glance without being clut-
tered up with JDBC calls.
For example, consider the Catalog session bean. The business method
getProducts need to return all the products for a category. Whenever getProducts
needs to operate on data residing in the database, it hands over control to a data
access object. The data access object formulates the query, fetches the result set,
and returns the data in the desired format to the calling method of the enterprise
bean.
In the sample application, the implementation of the Catalog session bean is
provided by CatalogEJB, which inherits from CatalogImpl. The code for Cata-
logImpl.getProducts appears in Code Example 5.4; the code for the correspond-
ing data access object appears in Code Example 5.5.
public Collection getProducts(String categoryId,
int startIndex, int count) {
Connection con = getDBConnection();
try {
CatalogDAO dao = new CatalogDAO(con);
return dao.getProducts(categoryId, startIndex, count);
} catch (SQLException se) {
throw new GeneralFailureException(se);
} finally {
try {
con.close();
} catch (Exception ex) {
...
}
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER132
}
}
Code Example 5.4 CatalogImpl.getProducts
public Collection getProducts(String categoryId, int startIndex,
int count) throws SQLException {
String qstr =
"select itemid, listprice, unitcost, " +
"attr1, a.productid, name, descn " +
"from item a, product b where " +
"a.productid = b.productid and category = "
+ "'" + categoryId + "' " + " order by name";
ArrayList al = new ArrayList();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(qstr);
HashMap table = new HashMap();
// skip initial rows as specified by the startIndex parameter
while (startIndex-- > 0 && rs.next());
// Now get data as requested
while (count-- > 0 && rs.next()) {
int i = 1;
String itemid = rs.getString(i++).trim();
double listprice = rs.getDouble(i++);
double unitcost = rs.getDouble(i++);
...
Product product = null;
if (table.get(productid) == null) {
product = new Product(productid, name, descn);
table.put(productid, product);
al.add(product);
}
}
rs.close();
stmt.close();
DESIGN GUIDELINES 133
return al;
}
Code Example 5.5 CatalogDAO.getProducts
5.5.1.2 Migrating to Container-Managed Persistence
Apart from neater, more maintainable code, the use of data access objects provides
an easier migration path to container-managed persistence. To convert an entity
bean from bean-managed persistence to container-managed persistence you simply
need to discard corresponding the data access object along with references to it in
the entity bean’s code.
5.5.1.3 Database and Schema Portability
By encapsulating data access calls, data access objects allow adapting data access to
different schemas or even to a different database types. Data access objects for dif-
ferent schemas and databases can share a common interface enabling the Applica-
tion Assembler to choose the appropriate object from among several at assembly
time.
In the sample application we have used the flexibility provided by data access
objects to access different types of databases, namely Oracle, Sybase, and Cloud-
scape. In the order management module, a separate data access object is provided
for each vendor. This allows the same enterprise bean code to run on all databases.
The decision of which data access object to invoke is taken dynamically when a
connection to the database is made. A similar approach can be used to access data-
bases with different schemas.
5.5.1.4 Tool Compatibility
Data access objects fill a gap in the J2EE application architecture between responsi-
bilities of application developers and those of Server Providers. They represent an
excellent opportunity for the tool vendors to add value. Data access objects are a
type of class that can be easily generated by sophisticated tools. In the future,
custom data access objects, such as those in the sample application, will most likely
be replaced by sophisticated object-relational tools.
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER134
5.5.2 Value Objects
As mentioned earlier, because enterprise beans are remote objects, they consume
significant amount of system resources and network bandwidth to execute. There-
fore, before modeling a business object as an enterprise bean, you should determine
that there is a good case for doing so. For example, if a business object merely repre-
sents a structure to hold data fields, and the only behavior it provides are get and set
methods for the fields, then it would be wasteful of system resources to implement it
as an enterprise bean.
A better alternative would be to model it as a value object. A value object is a
serializable Java object that can be passed by value to the client. A business
concept should be implemented as a value object when it is:
• Fine-grained, which means it only contains methods to get the values of fields.
• Dependent, which means its life cycle is completely controlled by another ob-
ject.
• Immutable, which means that its fields are not independently modifiable.
A client’s request for a value object can be fulfilled by the server more simply
than for an enterprise bean; the object is serialized and sent over the network to
the client where the object is deserialized. The object can then be used as a local
object. This conserves system resources by reducing the load on a remote object.
It also reduces network traffic as the method calls to get fields of the object are all
local.
In the sample application the details of an account are modeled as a value
object representing the state of a particular account in the database and providing
getter methods to query the state of this account. The client makes just one remote
call to execute getAccountDetails on the remote object account and gets back the
serialized AccountDetails object. The client can then query the state of this
account locally via the methods provided with the AccountDetails object. Simi-
larly, the state of an account object can be modified in just one remote call by
passing a ContactInformation object to the remote method for updating contact
information.
5.5.2.1 Example: An Address Value Object
In the sample application, an address and credit card information are modeled as
value objects. The definition of the Address class is shown in Code Example 5.6.
DESIGN GUIDELINES 135
public class Address implements java.io.Serializable {
public Address (String streetName1, String streetName2,
String city, String state, String zipCode, String country){
this.streetName1 = streetName1;
this.streetName2 = streetName2;
...
}
public String getStreetName1() {
return streetName1;
}
...
private String streetName1;
private String streetName2;
...
}
Code Example 5.6 Address
An Address does not exhibit complex behavior, but is merely a data structure
that contains only data fields. An address is fine-grained, having only get and set
methods. Also, it is a dependent object; it only has meaning if it is associated with
an account.
When making the object pass-by-value it is important to make it immutable to
reinforce the idea that the dependent object is not a remote object and changes to
its state will not be reflected on the server; in other words, it is just a copy and not
the remote reference. To make an Address object immutable, all its instance data
is declared private and it only has methods to get fields. To change a pass-by-value
object the client must first remove it and then create a new object with the desired
field values.
5.5.3 Session Beans as a Facade to Entity Beans
A facade provides a unified interface to a set of interfaces. This section describes
when and how to use an session bean as a facade to entity beans.
Entity beans represent an object-oriented view of data and provide business
logic to manipulate this data. In an enterprise environment, entity beans often
need to be shared among different applications representing different work flows.
In such cases, use of application-specific stateful session beans to manage the
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER136
interaction of various entity beans provides a simpler interface to the client, by
giving the client a central point of entry. The client always interacts with this
session bean and is unaware of the existence of other entity beans in the system.
Stateful session beans are logical extensions of the client programs. Whether
to use one or many session bean facades depends on the types of clients the appli-
cation supports. Since the sample application has only one kind of client for the
application, namely the shopping client, the sample application uses a single state-
ful session bean called ShoppingSessionController. It’s easy to imagine another
client that would provide administration functionality such as inventory and order
status monitoring. The work flow of such a client would be entirely different from
a shopping client. Therefore, defining another stateful session bean that encapsu-
lates this work flow would be advisable. However, creating a session bean for
every entity bean in the system would waste server resources and is not recom-
mended.
Where the client interacts with only a few entity beans in a relatively simple
way, the entity beans can be exposed directly. For example, in the sample applica-
tion the client that converts pending orders to XML (for use by business-to-busi-
ness transactions) interacts with the order entity bean directly.
5.5.4 Master-Detail Modeling Using Enterprise Beans
In a master-detail relationship, one object serves as a pointer to another. Typically
such a relationship is represented to the user as a list of items from which to select.
This list is called a master record and its contents are provided by the master object.
Selecting an item from this list leads to an expanded view of that item. The
expanded view is provided by a detail object.
A master-detail relationship is a one-to-many type relationship among data
sets. For example, if we have a set of customers and a set of orders placed by each
customer, a master-detail relationship is created by having customer number as a
common field between the two. An application can use this master-detail relation-
ship to enable users to navigate through the customer data set and see the detail
data for orders placed by the selected customer.
When modeling a master-detail relationship as enterprise beans, the guide-
lines for using entity or session beans still hold. The choice is not affected by the
master-detail relationship. However, the relationship is relevant when designing
the behavior of the master. For example, suppose the master object should be
SUMMARY 137
modeled as a session bean and the details object should be an entity bean. In this
case, the issue to be decided is how to implement the behavior of the master:
• Expose the underlying entity beans to its clients when the client wants the de-
tail object.
• Implement the logic of collecting the details in the master.
In analyzing various possible combinations of session beans, entity beans, or
value objects, to represent master and detail objects, these questions are relevant
only when the details are entity beans. For this case there are two possible sce-
narios:
• If the client modifies the detail entity object, then the master object needs to
expose the underlying entity object to the clients.
• If the client does not modify the detail entity object, then the master object can
have the necessary business logic to know which detail bean to access to con-
struct the logical master/detail object. The client should not be exposed to the
logic associated with accessing and aggregating the entity beans representing
the details.
5.6 Summary
There are a number of common services that distributed enterprise applications
require. These include maintaining state, operating on shared data, participating in
transactions, servicing a large number of clients, providing remote access to data,
and controlling access to data. The middle tier of enterprise computing has evolved
as the ideal place to provide these services. The J2EE platform promotes the Enter-
prise JavaBeans architecture as a way to provide the system services that most enter-
prise applications need. The EJB architecture frees enterprise application developers
from concerns about these services enabling them to concentrate on providing busi-
ness logic.
The Enterprise JavaBeans architecture provides various types of enterprise
beans to model business objects: entity beans, stateful session beans, and stateless
session beans. When choosing a particular enterprise bean type to model a busi-
ness concept, the choice depends on a number of factors such as the need to
CHAPTER 5 THE ENTERPRISE JAVABEANS TIER138
provide robust data handling, the need to provide efficient behavior, and the need
to maintain client state during a user session.
An entity bean provides an object-oriented view of relational data stored in a
database; a stateless session bean gives a procedural view of the data. An Applica-
tion Component Provider should use entity beans to model logical entities such as
individual records in a database. When implementing behavior to visit multiple
rows in a database and present a read-only view of data, stateless session beans
are the best choice. They are designed to provide generic services to multiple cli-
ents.
Some business concepts actually require more than one view of data. An
example would be a catalog that provides browsing and searching services as well
as mechanisms to update the product information. In such cases, you can use a
stateless session bean to operate on a product information as a whole and an entity
bean to provide access to a particular product.
Because enterprise beans are remote objects that consume significant amount
of system resources and network bandwidth, they are not appropriate for model-
ing all business objects. An Application Component Provider can use data access
objects to encapsulate database access and value objects to model objects that are
dependent on enterprise beans.
Also, it may not be appropriate to give clients direct access to all enterprise
beans used by an application. Some enterprise beans may act as mediators for
communication between clients and the EJB tier. Such beans can encapsulate
work flow specific to an application or can serve as an entry point to a hierarchy of
information.
About the Author
RAHUL SHARMA is a Staff Engineer with Sun Microsystems, where he is the lead
architect for the J2EE Connector architecture 1.0. Before this, Rahul has worked in the
areas of Java computing, Web technologies, distributed computing, CORBA, databases,
and object-oriented programming. Rahul received a degree in Computer Science from
Delhi University in India. He is presently pursuing his M.B.A. from Haas School of
Business, University of California at Berkeley.
141
C H A P T E R 6
The Enterprise Information
System Tier
by Rahul Sharma
ENTERPRISE applications require access to applications running on enterprise
information systems. These systems provide the information infrastructure for an
enterprise. Examples of enterprise information systems include enterprise resource
planning systems, mainframe transaction processing systems, relational database
management systems, and other legacy information systems. Enterprises run their
businesses using the information stored in these systems; the success of an enter-
prise critically depends on this information. An enterprise cannot afford to have an
application cause inconsistent data or compromise the integrity of data stored in
these systems. This leads to a requirement for ensuring transactional access to enter-
prise information systems from various applications.
The emergence of the e-business model has added another dimension to infor-
mation system access: enterprises want their information to be accessible over the
Web to their partners, suppliers, customers, and employees. Typically enterprises
develop Web-enabled applications that access and manage information stored in
their information systems. These enterprises can use J2EE applications to extend
the reach of their existing information systems and make them accessible over the
Web. Enterprises also develop new e-business applications. The sample applica-
tion described in this book is one example of this class of application.
This added dimension requires an enterprise to ensure secure access to its
enterprise information systems because any break in security can compromise
critical information. An increase in the number of relationships that an enterprise
has to establish with its suppliers, buyers, and partners leads to a requirement that
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER142
J2EE applications accessing enterprise information systems be scalable and
support a large number of clients.
This chapter describes the application programming model for accessing
enterprise information system resources from enterprise applications in a secure,
transactional, and scalable manner.
6.1 Enterprise Information System Capabilities and
Limitations
Some enterprise information systems provide advanced support for transaction and
security. For example, some systems support controlled access to their resources
through transactions. These systems can participate in transactions with others by
supporting two-phase commit protocol, managed by a transaction manager sup-
ported by a J2EE server. Other systems offer limited or almost no support for trans-
actional access. For example, a system may only support transactions that are
coordinated internally.
Legacy systems or applications that have been in existence for a long time
may impose specific technology and administrative restrictions. For example, it
may be difficult to create new user accounts in a legacy system or to extend this
system to support development of new applications. In this case, an Application
Component Provider has to live with what exists and enable access to such
systems under restrictions. This may be a very typical situation.
When developing an application to integrate enterprise information systems,
an Application Component Provider has to be aware of its functional and system
capabilities, and design application components taking into account possibilities
and limitations of the system. For example, application components should not be
developed and deployed so that they require transactions spanning multiple
resource managers if the J2EE server cannot really provide support for such trans-
actions due to the fact that the participating enterprise information system
resource managers do not support the two-phase commit protocol. In other cases,
application components may need to limit their security requirements due to con-
straints of the underlying system.
ENTERPRISE INFORMATION SYSTEM INTEGRATION SCENARIOS 143
6.2 Enterprise Information System Integration Scenarios
There are any number of configurations in which a J2EE application might be struc-
tured to access an enterprise information system. The following sections illustrate a
few typical enterprise information system integration scenarios.
6.2.1 An Internet E-Store Application
Company A has an e-store application based on the J2EE platform. This application
is composed of a set of enterprise beans, JSP pages, and servlets that collaborate to
provide the overall functionality of the application. The database stores data related
to product catalogs, shopping carts, customer registration and profiles, transaction
status and records, and order status.
The architecture of this application is illustrated in Figure 6.1.
Figure 6.1 An Internet E-Store Application
A customer uses a Web browser to initiate an e-commerce transaction with the
e-store application. A customer browses the catalog, makes a selection of prod-
ucts, puts the product selection into a shopping cart, enters a user name and pass-
word to initiate a secure transaction, fills in order related information, and finally
places an order. In this scenario, the e-store application uses an existing database
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER144
that already contains product and inventory information to store all persistent
information about customers and their transactions.
6.2.2 An Intranet Human Resources Application
Company B has developed and deployed an employee self-service application based
on the J2EE platform. This application supports a Web interface to existing human
resources applications supported by the enterprise resource planning system from
vendor X and provides additional business processes that are customized to the
needs of company B.
Figure 6.2 illustrates an architecture for this application. The middle tier is
composed of enterprise beans and JSP pages that provide customization of busi-
ness processes and support a company standardized Web interface. This applica-
tion enables an employee (under the different roles of Manager, HR manager, and
Employee) to perform various personnel management functions: personal informa-
tion management, payroll management, compensation management, benefits
administration, travel management, and cost planning.
The IT department of company B deploys this application and enterprise
resource planning system in a secure environment at a single physical location.
Access to the application is permitted only to employees of the organization based
on their roles and access privileges, and within the confines of the organization-
wide intranet.
Figure 6.2 An Intranet Human Resources Application
ENTERPRISE INFORMATION SYSTEM INTEGRATION SCENARIOS 145
6.2.3 A Distributed Purchasing Application
Company C has a distributed purchasing application. This application enables an
employee to use a Web-based interface to perform multiple purchasing transactions.
An employee can manage the whole procurement process, from creating a purchase
requisition to getting invoice approval. This application also integrates with the
existing financial applications in the enterprise for tracking financial aspects of the
procurement business processes.
Figure 6.3 illustrates an architecture for this application. The application as
developed and deployed on the J2EE platform, is composed of JSP pages, enter-
prise beans, and existing information systems. The enterprise beans integrate a
logistics application that provides integrated purchasing and inventory manage-
ment functions from vendor X and another that provides financial accounting
functions from vendor Y.
Figure 6.3 A Distributed Purchasing Application
Company C is a large decentralized enterprise with geographically distributed
business units and departments. In this scenario, system X and system Y are
managed by different IT departments and have been deployed at secured data
centers in different geographic locations. The integrated purchasing application is
deployed at a location different from either system X or system Y.
System X and System Y are in different security domains; they use different
security technologies and have their own specific security policies and mecha-
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER146
nisms. The distributed purchasing application is deployed in a security domain
that is different from either that of system X or system Y.
6.3 Relational Database Management System Access
Application Component Providers use the JDBC 2.0 API for accessing relational
databases to manage persistent data for their applications. The JDBC API has two
parts: a client API for direct use by developers to access relational databases and a
standard contract between J2EE servers and JDBC drivers for supporting connec-
tion pooling and transactions. The latter contract is not directly used by the develop-
ers, it is used by J2EE server vendors to automatically provide pooling and
transaction services to J2EE components.
An Application Component Provider uses the JDBC client-level API to get a
database connection, to retrieve database records, to execute queries and stored
procedures and to perform other database functions. Even though the JDBC API
is quite simple, an Application Component Provider still experiences a learning
curve and intensive programming effort due to differences between relational and
object-oriented methodologies.
6.4 Other Enterprise Information System Access
An enterprise environment invariably includes enterprise information systems other
than relational database systems:
• Enterprise resource planning systems
• Mainframe transaction processing systems
• Legacy applications
• Non-relational database systems
Currently, there is no standard architecture for integration of a J2EE server
with enterprise information systems; most enterprise information system vendors
and J2EE Server Providers use vendor-specific architectures to support enterprise
information system integration. For example, a J2EE Server Provider can special-
ize its container to support integration with an enterprise resource planning
system.
APPLICATION COMPONENT PROVIDER TASKS 147
A major disadvantage of developing enterprise information system integration
applications for deployment on specialized containers is that application compo-
nents become tied to mechanisms and programming models defined by the spe-
cialized container. As a result, such components are not portable across different
types of containers.
The J2EE Connector architecture (described in Section 6.10 on page 161) is a
standard architecture for the integration of J2EE products and applications with
heterogeneous enterprise information systems. This architecture is currently under
development and will be part of the next version of the J2EE platform. In this doc-
ument, we make no specific recommendations based on the Connector architec-
ture.
In the interim, an Application Component Provider can use vendor-specific
architectures to integrate with enterprise information systems. However, while
developing various types of application components we suggest following the
guidelines that are discussed in the subsequent sections in this chapter in order to
ensure that the migration path to the Connector architecture will be smooth.
6.5 Application Component Provider Tasks
The task of an Application Component Provider assumes different levels of com-
plexity and effort depending on whether the programming model used is based on
the J2EE application programming model or not. In either case, an Application
Component Provider has to write the business and application logic for the applica-
tion.
In the absence of J2EE platform support, the Component Provider faces sig-
nificant complexity when programming access to enterprise information system
resources (data and functions managed by an enterprise information system). This
complexity comes from dealing with security, transaction, and application pro-
gramming models that are specific to an enterprise information system. A Compo-
nent Provider has to manage transactions using a transaction demarcation API
specific to an enterprise information system, such as the transaction demarcation
API defined in the java.sql.Connection interface in the JDBC 2.0 API. In the
application, the Application Component Provider has to explicitly code security
checks to restrict enterprise information system access to valid users.
Using the J2EE application programming model, an Application Component
Provider faces reduced complexity by relying on the Web and EJB containers to
handle transactions, security, and scalability related to enterprise information
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER148
system access. The Application Component Provider can focus on the task of
writing business and application logic and use a simple client-oriented API for
accessing the enterprise information system. The task of accessing enterprise
information system resources from the application code is made even easier
through the use of enterprise application development tools.
By letting J2EE containers manage transactions, security, and scalability,
Application Component Providers focus on what they do the best: writing busi-
ness and application logic. The J2EE platform vendors focus on their core
strengths: multiuser, secure, transactional, scalable implementations of J2EE plat-
form that enable different enterprise information systems to plug into the J2EE
platform. Together Application Component Providers and J2EE Platform Provid-
ers succeed in ensuring that enterprises can rely on J2EE applications to extend
their enterprise information systems without compromising the information stored
in these systems.
6.6 Application Programming Model
The J2EE application programming model for enterprise information system access
lays down a set of design choices, guidelines, and recommendations for Application
Component Providers. These guidelines enable an Application Component Provider
to develop an application based on its overall functional and system requirements.
The application programming model focuses on the following aspects:
• Accessing enterprise information system resources from components
• Using tools to simplify and reduce application development effort involved in
accessing enterprise information systems
• Getting connections to an enterprise information system and managing con-
nections
• Supporting the security requirements of an application
• Supporting the transactional requirements of an application
The following sections describe each of these aspects from the perspective of
relational database access using JDBC 2.0 API, with the exception of transactions,
which are discussed in Chapter 8. An important point to note is that the following
sections are not meant to be a programmer’s guide to using the JDBC API.
PROGRAMMING ACCESS TO DATA AND FUNCTIONS 149
6.7 Programming Access to Data and Functions
In an application that requires access to an enterprise information system, an Appli-
cation Component Provider is responsible for programming access to resources
managed by the enterprise information system, including tables, stored procedures,
business objects, and transaction programs. The Application Component Provider
also has to write the business and application logic when developing functionality of
applications that target enterprise information system.
The API for accessing an enterprise information system belongs to two cate-
gories: a client-level API to access data and execute functions (for example,
java.sql.PreparedStatement and java.sql.ResultSet in JDBC 2.0) and a
system-level API for getting connections and demarcating transactions (for exam-
ple, javax.sql.DataSource in JDBC 2.0).
In the J2EE programming model, a container assumes primary responsibility
for managing connection pooling, transactions, and security. The level of service
provided is based on the declarative specification of application requirements by
an Application Component Provider or Deployer. This leaves an Application
Component Provider to concentrate on programming access to data and functions
being managed by an enterprise information system.
6.7.1 Client API for Enterprise Information System Access
A client API for accessing data and functions can be difficult to understand and use
for one or more of the following reasons:
• The client API may be tied to a specific enterprise information system pro-
graming model.
• The client API may not present object-oriented abstractions. For example, it
may require remote function calls to access business functions on an ERP sys-
tem.
• An Application Component Provider who is proficient with the JavaBeans
component model and visual application composition and development tools
may see any API that does not support such functionality as being difficult to
use.
• The lack of application development tool support for a specific client API may
force Application Component Providers to hand-code all data and/or function
access.
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER150
These factors increase the need for tools to support end-to-end application develop-
ment. Application Component Providers also have to use additional programming
techniques to simplify enterprise information system integration.
6.7.2 Tools for Application Development
The J2EE programming model recognizes that Application Component Providers
will rely on enterprise development tools for simplifying development during enter-
prise information system integration. These tools will come from different vendors,
provide varied functionalities, and serve various steps in the application develop-
ment process. A number of these tools will be integrated together to form an end-to-
end development environment. The tools include:
• Data and function mining tools, which enable Application Component Provid-
ers to look at the scope and structure of data and functions in an existing infor-
mation system.
• Object-oriented analysis and design tools, which enable Application Compo-
nent Providers to design an application in terms of enterprise information sys-
tem functionality.
• Application code generation tools, which generate higher level abstractions for
accessing data and functions. A mapping tool that bridges different program-
ming models, such as an object to relational mapping, will fall into this cate-
gory.
• Application composition tools, which enable Application Component Provid-
ers to compose application components from generated abstractions (such as
those described in previous bullets). These tools will use the JavaBeans com-
ponent model to enhance ease of programming and composition.
• Deployment tools, which are used by Application Component Providers and
Deployers to set transaction, security, and other deployment time require-
ments.
Since programming access to enterprise information system data and functions is a
complex application development task in itself, we recommend that application
development tools should be used to reduce the effort and complexity involved in
enterprise information system integration.
PROGRAMMING ACCESS TO DATA AND FUNCTIONS 151
6.7.3 Access Objects
A component can access data and functions in an enterprise information system in a
couple of ways, either directly by using the corresponding client API or indirectly
by abstracting the complexity and low-level details of enterprise information system
access API into higher level access objects. An Application Component Provider
comes across these access objects in different forms, scopes, and structure.
The use of access objects provides several advantages:
• An access object can adapt the low-level programming API used for accessing
enterprise information system data and/or functions to an easy-to-use API that
can be designed to be consistent across various types of enterprise information
systems. For example, an access object may follow a design pattern that maps
function parameters to setter methods and return values to getter methods. The
Application Component Provider uses a function by first calling the appropri-
ate setter methods, then calling the method corresponding to the enterprise in-
formation system function, and finally calling the getter methods to retrieve the
results.
• A clear separation of concern between access objects and components will en-
able a component to be adapted to different enterprise information system re-
sources. For example, a component can use an access object to adapt its
persistent state management to a different database schema or to a different
type of database.
• Since access objects can be made composable through support for the Java-
Beans model, components can be composed out of access objects or can be
linked with generated access objects using application development tools. This
simplifies the application development effort.
Since access objects primarily provide a programming technique to simplify appli-
cation development through one or more of the above advantages, we recommend
that Application Component Providers consider using them anywhere they need to
access data or functions in an enterprise information system. In some cases tools
may be available to generate such access objects. In other cases they will need to be
hand-coded by Application Component Providers.
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER152
6.7.3.1 Guidelines for Access Objects
Here are some guidelines to follow in developing access objects:
• An access object shouldn’t make assumptions about the environment in which
it will be deployed and used.
• An access object should be designed to be usable by different types of compo-
nents. For example, if an access object follows the set-execute-get design pat-
tern described previously, then its programming model should be consistent
across both enterprise beans and JSP pages.
• An access object shouldn’t define declarative transaction or security require-
ments of its own. It should follow the transaction and security management
model of the component that uses it.
• All programming restrictions that apply to a component apply to the set of ac-
cess objects associated with it. For example, an enterprise bean isn’t allowed
to start new threads, to terminate a running thread, or to use any thread syn-
chronization primitives. Therefore, access objects should conform to the same
restrictions.
6.7.3.2 Examples of Access Objects
Access objects can be used in a number of ways, as represented in the following
examples:
• Encapsulating functions
An access object can encapsulate one or more enterprise information sys-
tem functions, such as business functions or stored procedures. The following
code implements an access object that drives a purchase requisition business
process on an enterprise resource planning system by mapping purchasing
functions to method calls on a purchase function object.
PurchaseFunction pf = // instantiate access object for PurchaseFunc-
tion
// set fields for this purchase order
pf.setCustomer("Wombat Inc");
pf.setMaterial(...);
pf.setSalesOrganization(...);
CONNECTIONS 153
po.execute();
// now get the result of purchase requisition using getter methods
• Encapsulating persistent data
A data access object can encapsulate access to persistent data such as that
stored in a database management system. Data access objects can provide a
consistent API across different types of such systems. Data access objects
used by the sample application (see Section 5.5.1 on page 130) are used to
access order objects stored in different types of databases.
• Aggregating behaviors
An access object can aggregate access to other access objects, providing a
higher level abstraction of application functionality. For example, a Purchase-
Order aggregated access object can drive its purchase requisition business
process through the PurchaseFunction access object and use a data access
object PurchaseData to maintain persistent attributes of the purchase order.
6.7.3.3 Usage Scenarios for Access Objects
A component can use access objects in different ways depending on the functional-
ity they offer. A couple of common ways to use access objects would be:
• Define a one-to-one association between components and access objects. That
is, each access object encapsulates the enterprise information system function-
ality required by a particular component. This usage scenario will typically be
used to enable Web access to enterprise information system resources being
encapsulated by an access object.
• Define components to aggregate the behavior of multiple access objects. This
will happen often where a component accesses multiple enterprise information
system resources or adds additional business logic to the functionality defined
by multiple enterprise information system resources.
6.8 Connections
Virtually all enterprise information systems are accessed via objects called connec-
tions. The following discussions provide pointers on efficient techniques for getting
and managing connections.
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER154
6.8.1 Establishing a Connection
A component is responsible for getting a connection to an enterprise information
system. Once a connection to the enterprise information system is established, the
component uses the connection to access enterprise information system resources.
After the component is finished, it closes the connection.
The specific steps in establishing a connection to an enterprise information
system are:
1. The Deployer configures a connection factory instance in the JNDI name
space. This connection factory instance is tied to the connection factory re-
quirements specified in the deployment descriptor by the Application Compo-
nent Provider.
2. A component looks up a connection factory from the JNDI name space. After
a successful lookup, the component calls a connection factory method to create
a connection to the enterprise information system.
3. The connection factory returns a connection instance. The component uses the
connection instance to access enterprise information system resources.
4. Having established a connection to the enterprise information system, the com-
ponent manages this connection and its life cycle.
5. Once the component is finished using the connection, it closes the connection
instance.
Code Example 6.1 illustrates how a component gets a connection to a relational
database using the JDBC 2.0 API.
public void getConnection(...) {
// obtain the initial JNDI context
Context initctx = new InitialContext();
// Perform JNDI lookup to obtain factory
javax.sql.DataSource ds =
(javax.sql.DataSource)initctx.lookup(
"java:comp/env/jdbc/MyDatabase");
// Invoke factory to get a connection
java.sql.Connection cx = ds.getConnection();
CONNECTIONS 155
// Use the Connection to access the resource manager
...
}
Code Example 6.1 Establishing a Database Connection
6.8.2 Guidelines for Connection Management
If each component were to acquire an enterprise information system connection and
hold it until it gets removed, it would be difficult to scale up an application to
support thousands of users. Since holding on to an enterprise information system
connection across long-lived instances or transactions is expensive, components
should manage connections more efficiently. To avoid scaling problems, almost
every J2EE server should support connection pooling. However, an Application
Component Provider still needs to follow sound connection management practices.
When an application is migrated from a two-tier structure to a multitier com-
ponent-based structure, the issue of connection management becomes especially
important. For example, a two-tier JDBC application may share a single connec-
tion across an entire application. After migration to a component-based partition-
ing, the application will need to deal with shared connections across multiple
component instances.
This section provides guidelines for addressing application programming
model issues related to connections using a JDBC connection to a relational data-
base as an example.
6.8.2.1 Connection Life Cycle and Connection Pooling
A component can get a connection to a database in any client- or container-invoked
method. We recommend that components open and close their connections within a
single method, rather than holding connection state across methods. Only when the
design of an application requires components to share connections across compo-
nent instances or method invocations should connections be retained.
A component can retain a connection across methods at the cost of additional
system resources and added programming model complexity required to manage
the connection. One example might be a stateful session bean instance that retains
the results of queries and database access operations across methods. The session
bean gets a connection and starts a transaction through it. The transaction itself is
handled internally by database with no external transaction management. Since
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER156
the session bean wants to have this transaction span multiple methods, it must
keep the connection open across method invocations.
Ideally, containers should take care of connection sharing. But currently the
J2EE platform defines no standardized way of implementing connection sharing
across different containers. Until a connection sharing mechanism is standardized
for containers, a component can choose to do connection sharing through vendor-
specific mechanisms offered by different containers and JDBC drivers. This
comes at the cost of portability across containers.
6.8.2.2 Connection Management by Component Type
A J2EE application is typically composed of components of different types: JSP
pages, servlets, and enterprise beans. These component types vary in terms of
support for container-managed activation and passivation, execution of an instance
for multiple clients, sharing of an instance across multiple clients, long-lived nature,
and other factors. The Application Component Provider has to account for such dif-
ferences across component types when deciding on a connection management
model for an application. Here are a few examples that illustrate these differences.
A JSP page or servlet acquires and holds on to a JDBC connection in relation
to the life cycle of its HTTP session. It can handle multiple HTTP requests across
a single HTTP session from Web clients using the same JDBC connection.
A stateful session bean can share an open connection and its client-specific
query results across multiple methods. However stateless session beans are
designed to have no state specific to a client. So if stateless session beans share a
connection across methods, they are required to maintain no client-specific state
associated with the connection.
For entity beans, the EJB specification identifies methods that are allowed to
perform enterprise information system access through a connection. These
include ejbCreate, ejbPostCreate, ejbRemove, ejbFind, ejbActivate, ejbLoad,
ejbStore, and business methods from the remote interface. An entity bean cannot
access enterprise information systems from within the setEntityContext and
unsetEntityContext methods because a container does not have a meaningful
transaction or security context when they are called.
6.8.2.3 Multiple Connections
Some JDBC drivers don’t support multiple concurrent connections under a single
transaction. To be portable, components should avoid opening multiple concurrent
SECURITY 157
connections to a single database. However, multiple component instances can access
the same database using different connections.
6.9 Security
An enterprise has a critical dependency on its information systems for its business
activities. Loss or inaccuracy of information or unauthorized access to an enterprise
information system can be extremely costly. So, enterprises require that the security
of their enterprise information systems should never be compromised. Applications
need to provide access to enterprise information systems without creating security
threats to these valuable resources.
Enterprise applications should clearly establish the requirements and architec-
ture for secure enterprise information system integration environment. For exam-
ple, an application should require only the level of protection needed by the
enterprise: reducing the level of protection for less sensitive information or where
the system is less vulnerable to threats. The cost of implementing, administering,
and running a secure system should also be weighed against the security needs of
an application. This trade-off, based on the security benefits and cost, is difficult
to make for an enterprise application. However, this trade-off is important to make
for the security architecture for enterprise information system integration.
6.9.1 Security Architecture
A security architecture for enterprise information system integration should fulfill a
variety of requirements to ensure seamless support for distributed applications:
• Support a consistent end-to-end security architecture across Web, EJB, and en-
terprise information system tiers for applications based on the J2EE platform.
• Fit with the existing security environment and infrastructure supported by an
enterprise information system.
• Support authentication and authorization of users who are accessing enterprise
information systems.
• Be transparent to application components. This includes support for enabling
end-users to log on only once to the enterprise environment and access multi-
ple enterprise information systems.
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER158
• Enable applications to be portable across security environments that enforce
different security policies and support different mechanisms.
The relative importance of achieving these goals depends on the cost/benefit
trade-off for the security requirements. The more an architecture takes care of
these security requirements for the application, the easier the application develop-
ment effort.
6.9.2 Application Programming Model
While developing and deploying application components, an Application Compo-
nent Provider follows the security model defined for the corresponding J2EE com-
ponent—EJB, JSP, or servlet. We recommend the following application
programming model for all types of components:
• An Application Component Provider should specify security requirements for
an application declaratively in the deployment descriptor. The security re-
quirements include security roles, method permissions, and authentication ap-
proach for enterprise information system signon.
• A security-aware Application Component Provider can use a simple program-
matic interface to manage security at an application level. This programmatic
interface allows the Application Component Provider to make access control
decisions based on the security context (principal, role) associated with the
caller of a method and to do programmatic signon to an enterprise information
system (described in Section 6.9.3.2 on page 160).
• Other development roles—J2EE Server Provider, Deployer, System Adminis-
trator—should satisfy an application’s security requirements (as specified in
the deployment descriptor) in the operational environment.
6.9.3 Resource Signon
From a security perspective, the mechanism for getting a connection to a resource is
referred to as resource signon. A user requests a connection to be established under
its security context. This security context includes various attributes, such as role,
access privileges, and authorization level for the user. All application-level invoca-
tions to the database using this connection are then provided through the security
context associated with the connection.
SECURITY 159
If the resource signon mechanism involves authentication of the user, then an
Application Component Provider has the following two choices:
• Allow the Deployer to set up the resource signon information. For example, the
Deployer sets the user name and password for establishing the database con-
nection. The container then takes the responsibility of managing the database
signon.
• Implement sign on to the database from the component code by providing ex-
plicit security information for the user requesting the connection.
We recommend that a component let the container manage resource signon.
This takes the burden of managing security information for the signon off of the
Application Component Provider. It also enables J2EE servers to provide addi-
tional useful security services, such as single signon across multiple enterprise
information systems and principal mapping across security domains.
Container-managed resource signon enables the Application Component Pro-
vider to avoid hard-coding security details in the component code. A component
with hard-coded security logic is less portable because it is difficult to deploy on
containers with different security policies and mechanisms. The following sec-
tions illustrate how to sign on using both approaches.
6.9.3.1 Container-Managed Signon
In this example, the Application Component Provider delegates the responsibility
of setting up and managing resource signon to the container. The Deployer sets up
the resource signon so that the user account for connecting to the database is always
eStoreUser. The Deployer also configures the user identification and authentication
information—user name and password—that is needed to authenticate eStoreUser
to the database.
As shown in Code Example 6.2, the component code invokes the connection
request method on the javax.sql.DataSource with no security parameters. The
component instance relies on the container to do the signon to the database using
the security information configured by the Deployer. Code Example 6.3 contains
the corresponding connection factory reference deployment descriptor entry,
where the res-auth element specifies that signon is performed by the container.
// Obtain the initial JNDI context
Context initctx = new InitialContext();
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER160
// Perform JNDI lookup to obtain connection factory
javax.sql.DataSource ds = (javax.sql.DataSource)initctx.lookup(
"java:comp/env/jdbc/MyDatabase");
// Invoke factory to obtain a connection. The security
// information is not given, and therefore it will be
// configured by the Deployer.
java.sql.Connection cx = ds.getConnection();
Code Example 6.2 Container-Managed Signon
description
jdbc/MyDatabase
javax.sql.DataSource
Container
Code Example 6.3 Connection Factory Reference Element
6.9.3.2 Application-Managed Signon
In this example, the Application Component Provider performs a programmatic
signon to the database. The component passes explicit security information (user
name, password) to the connection request method of the javax.sql.DataSource.
// Obtain the initial JNDI context
Context initctx = new InitialContext();
// Perform JNDI lookup to obtain factory
javax.sql.DataSource ds = (javax.sql.DataSource)initctx.lookup(
"java:comp/env/jdbc/MyDatabase");
// Get connection passing in the security information
java.sql.Connection cx = ds.getConnection("eStoreUser",
"password");
Code Example 6.4 Application-Managed Signon
J2EE CONNECTOR ARCHITECTURE 161
6.9.3.3 Authorization Model
An Application Component Provider relies on the container and enterprise informa-
tion system for authorizing access to enterprise information system data and func-
tions. The Application Component Provider specifies security requirements for
application components declaratively in a deployment descriptor. A set of security
roles and method permissions can be used to authorize access to methods on a com-
ponent. For example, an Application Component Provider declaratively specifies
the PurchaseManager role as the only security role that is granted permission to call
the purchase method on a PurchaseOrder enterprise bean. The purchase method in
turn drives its execution through an ERP Logistics application by issuing a purchase
requisition. So in effect, this application has authorized only end-users with the Pur-
chaseManager role to do a purchase requisition. This is the recommended authoriza-
tion model.
An Application Component Provider can also programmatically control
access to enterprise information system data and functions based on the principal
or role associated with the client who initiated the operation. For example, the
EJB specification allows component code to invoke getCallerPrincipal and
isCallerInRole to get the caller’s security context. An Application Component
Provider can use these two methods to perform security checks that cannot be
expressed declaratively in the deployment descriptor.
An application can also rely on an enterprise information system to do access
control based on the security context under which a connection to the enterprise
information system has been established. For example, if all users of an applica-
tion connect to the database as dbUser, then a database administrator can set
explicit permissions for dbUser in the database security domain. The database
administrator can deny dbUser permission to execute certain stored procedures or
to access certain tables.
6.10 J2EE Connector Architecture
The J2EE Connector architecture is an API under development to define a standard
for connecting the J2EE platform to heterogeneous enterprise information systems
such as enterprise resource planning, mainframe transaction processing, and data-
base systems. This API defines a set of scalable, secure, and transactional mecha-
nisms to support the integration of enterprise information systems with J2EE servers
and enterprise applications.
CHAPTER 6 THE ENTERPRISE INFORMATION SYSTEM TIER162
The Connector architecture enables an enterprise information system vendor
to provide a standard connector for its enterprise information system. This con-
nector is plugged into a J2EE server to provide the underlying infrastructure for
integration with an enterprise information system. The J2EE server that is
extended to support the Connector architecture is then assured of connectivity to
multiple enterprise information systems. Likewise, an enterprise information
system vendor provides one standard connector that will plug into any J2EE
server supporting the Connector architecture.
The J2EE server and enterprise information system collaborate through the
connector to keep all system-level mechanisms—transactions, security, connec-
tion management—transparent to the application components. This enables an
application component developer to focus on the business and presentation logic
for the application components without getting involved in the system-level issues
related to enterprise information system integration. This leads to an easier and
faster cycle for the development of scalable, secure, and transactional enterprise
applications that require integration with multiple enterprise information systems.
The Connector architecture will be supported in the J2EE platform, version 1.3.
6.11 Summary
This chapter has described a set of design choices, guidelines, and recommendations
for integrating enterprise information systems into enterprise applications. These
guidelines enable an Application Component Provider to develop an enterprise
application based on its overall functional and system requirements for enterprise
information system integration. The focus has been on accessing enterprise informa-
tion system resources from the component, using tools to simplify and reduce appli-
cation development effort involved in accessing enterprise information systems,
getting and managing connections to enterprise information systems, and support-
ing the security requirements of an application.
The current version of the J2EE platform provides full support for database
systems through the JDBC API. In the next version of J2EE platform, the Connec-
tor architecture will support integration with enterprise information systems other
than database systems.
About the Author
INDERJEET SINGH is a Staff Engineer with Sun Microsystems where he leads the
technical aspects of the J2EE Blueprints program. He also designed and implemented
the Web-caching and proxy-service module of the Java Web Server. In another incarna-
tion, he designed fault-tolerance software for large-scale distributed telecommunications
switching systems. Inderjeet holds an M.S. in Computer Science from Washington Uni-
versity at Saint Louis, and a B.Tech. in Computer Science and Engineering from Indian
Institute of Technology at Delhi.
165
C H A P T E R 7
Packaging and Deployment
by Inderjeet Singh
THE J2EE platform enables developers to create different parts of their applica-
tions as reusable components. The process of assembling components into modules
and modules into enterprise applications is called packaging. In good software
design, reusable components can be customized to the operational environment. The
process of installing and customizing an application in an operational environment
is called deployment. To enable customization, the components of an application
need to be configurable. However, application developers should not have to rein-
vent a configuration mechanism over and over again. They need a standard mecha-
nism that provides flexibility for configuration and supports tools to help the
process.
The J2EE platform provides facilities to make the packaging and deployment
process simple. It uses JAR files as the standard package for modules and applica-
tions, and XML-based deployment descriptors for customizing components and
applications. This chapter begins by providing an overview of the J2EE packing
and deployment process. It describes how to perform each stage in the process and
provides guidelines for each stage. It concludes by discussing requirements for
tools that support the deployment process.
7.1 Roles and Tasks
The J2EE packaging and deployment process involves three different development
roles: Application Component Providers, Application Assemblers, and Deployers.
The packaging and deployment tasks that each role performs are summarized in
Figure 7.1.
CHAPTER 7 PACKAGING AND DEPLOYMENT166
Figure 7.1 J2EE Packaging and Deployment Tasks
Application Component Providers develop enterprise beans, HTML and JSP
pages, and their associated helper classes. They supply the structural information
of the deployment descriptor for each component. This information includes the
home and remote interfaces and implementation classes of enterprise beans, the
persistence mechanisms used, and the type of resources the components use,
information typically hard coded in the application and not configurable at
deployment time. Code Example 7.1 contains an excerpt from the sample applica-
tion’s enterprise bean deployment descriptor:
TheAccount
TheAccount
com.sun.estore.account.ejb.AccountHome
com.sun.estore.account.ejb.Account
com.sun.estore.account.ejb.AccountEJB
Bean
java.lang.String
False
description
jdbc/EstoreDataSource
ROLES AND TASKS 167
javax.sql.DataSource
Container
Code Example 7.1 Descriptor Elements for an Entity Bean
Application Assemblers provide information related to the application as a
whole. In the sample application, the Application Assembler configures the file
Main.jsp to handle requests coming to the URL namespace, (/control/*), the
error pages the application uses, its security constraints and roles, and so on. Code
Example 7.2 contains excerpts from the sample application’s Web deployment
descriptor:
JavaPetStoreDemoWebTier
webTierEntryPoint
centralJsp
central point of entry for the Web app
Main.jsp
webTierEntryPoint
/control/*
...
java.lang.Exception
/errorpage.jsp
...
Code Example 7.2 Descriptor Elements for Web Application
CHAPTER 7 PACKAGING AND DEPLOYMENT168
A Deployer is responsible for deploying J2EE components and applications into
an operational environment. Deployment typically involves two tasks:
1. Installation - The Deployer moves the media to the server, generates the addi-
tional container-specific classes and interfaces that enable the container to
manage the components at runtime, and installs the components and additional
classes and interfaces into the J2EE server.
2. Configuration - The Deployer resolves all the external dependencies declared
by the Application Component Provider and follows the application assembly
instructions defined by the Application Assembler. For example, the Deployer
is responsible for mapping the security roles defined by the Application As-
sembler to the user groups and accounts that exist in the operational environ-
ment into which the components and applications are deployed. In some cases,
a qualified Deployer may customize the business logic of the application’s
components at deployment time by using tools provided with a J2EE product.
For example, a Deployer may write application code that wraps an enterprise
bean’s business methods or customizes the appearance of a JSP page, for ex-
ample, by adding a company’s logo or other graphics to a login page.
7.2 Packaging J2EE Applications
A J2EE application is packaged as an Enterprise ARchive (EAR) file, a standard
Java JAR file with an .ear extension. The goal of this file format is to provide an
application deployment unit that is assured of being portable.
A J2EE application file contains one or more J2EE modules and a J2EE appli-
cation deployment descriptor. Therefore, creation of a J2EE application is a two-
step process. First, the Application Component Providers create the J2EE
modules: EJB, Web, and application client modules. Second, the Application
Assembler packages these modules together to create the J2EE application. In this
section, we will discuss the issues involved in both of these steps.
It is important to note that all J2EE modules are independently deployable
units. This enables component providers to create units of functionality without
having to implement full scale applications.
To assemble an application, an Application Assembler edits deployment
descriptors for the J2EE modules to link dependencies between components
within each archive and between components in different archives. All such
dependencies must be linked before deployment. For example, in the sample
PACKAGING J2EE APPLICATIONS 169
application, the Web components in the WAR file need to refer to ShoppingCli-
entController, Catalog, Account, Order, and ShoppingCart enterprise beans
present in the EJB JAR file. The role of the Application Assembler is to make sure
that the description of the enterprise beans in the WAR file matches with their
description in the EJB JAR file.
Once the application assembly is complete, we recommend that the Applica-
tion Assemblers run J2EE verifier tools (one is provided with the J2EE SDK) on
the EAR file to ensure that its contents are well-formed. The verifiers perform a
number of static checks to ensure that the deployment descriptor and the archive
file contents are consistent with the EJB, Servlet, and J2EE specifications. While
verification is not a guarantee of correct behavior at runtime, it is useful for catch-
ing some errors early on.
The following sections discuss the different types of J2EE modules and give
some heuristic rules and practical tips on how best to package the different compo-
nent types into modules.
7.2.1 EJB Modules
An EJB module is the smallest deployable and usable unit of enterprise beans. An
EJB module is packaged and deployed as an EJB JAR file, a JAR file with a .jar
extension. It contains:
• Java class files for the enterprise beans and their remote and home interfaces.
If the bean is an entity bean, its primary key class must also be present in the
EJB module.
• Java class files for any classes and interfaces that the enterprise bean code de-
pends on that are not included with the J2EE platform. This may include su-
perclasses and superinterfaces and the classes and interfaces used as method
parameters, results, and exceptions.
• A EJB deployment descriptor that provides both the structural and application
assembly information for the enterprise beans in the EJB module. The applica-
tion assembly information is optional and is typically included only with as-
sembled applications.
An EJB JAR file differs from a standard JAR file in one key aspect: it is aug-
mented with a deployment descriptor that contains meta-information about one or
more enterprise beans.
CHAPTER 7 PACKAGING AND DEPLOYMENT170
The EJB JAR file producer can create a client JAR file to be used by the
clients of the enterprise beans contained in the EJB JAR file. The client JAR file
consists of all the class files that a client program needs to use to access the enter-
prise beans that are contained in the EJB JAR file.
7.2.2 Packaging Components Into EJB Modules
A typical enterprise application will contain many enterprise beans. Some of these
enterprise beans could be off-the-shelf components while others may use third-party
libraries. The Application Assembler, therefore, has to choose from the following
packaging options:
1. Package each enterprise bean for an application in its own EJB module. In this
approach, each enterprise bean has its own deployment descriptor and is pack-
aged in one EJB module along with its dependent classes. One advantage of
this approach is the maximum reusability of each enterprise bean, by leaving
the Application Assembler free to pick and choose among these EJB modules
to compose additional J2EE applications. This option is recommended if your
enterprise beans are each highly reusable. In such a case, the Application As-
semblers will be able to reuse precisely those enterprise beans that they wish
to, and no more.
2. Package all enterprise beans for an application in one EJB module. In this ap-
proach all enterprise beans and their dependent classes are packaged together
in one EJB module. This approach is the simplest to implement. The Applica-
tion Assembler does not have to specify references to the enterprise beans
present in this EJB module as unresolved. This makes the job of Application
Assemblers easier in the case when they wish to use all the enterprise beans.
Application Assemblers who only wish to use a subset of the enterprise beans
in the EJB module will still be able to do so, but may end up with a bloated
application. The Deployer in this case may have to deploy superfluous enter-
prise beans.
3. Package all related (closely-coupled) enterprise beans for an application in one
EJB module. In this approach, all off-the-shelf components are used as is (that
is, in their own EJB modules). All in-house enterprise beans are grouped based
on their functional nature and put in one EJB module. For example, all enter-
prise beans related to account management can be put in one EJB module.
PACKAGING J2EE APPLICATIONS 171
Because its more modular, the third option is recommended for reasonably-
sized J2EE applications. It strikes the right balance between maximum reusability
(option 1) and maximum simplicity (option 2). It promotes the black-box use of
third-party components, which is especially important when such third-party com-
ponents that are digitally signed. Another value of the third option arises when a
J2EE server deploys each EJB module on a separate Java virtual machine for load
balancing. In such cases, the third option is most efficient since it groups closely-
coupled enterprise beans together, allowing many remote calls to be optimized to
local calls. Another advantage of option 3 is that it promotes reusability at the
functional level rather than at the enterprise bean level. For example, making a
single Account enterprise bean reusable is more difficult than providing a reusable
set of classes that provide account management functionality collectively. Logical
grouping also makes sense from a tool point of view. A deployment or assembly
tool may show the EJB module as a group under a single icon. The following dis-
cussions provide guidelines on grouping enterprise beans.
7.2.2.1 Grouping by Related Functionality
Once a group of enterprise beans is packaged into the same EJB module, they may
not be easily separated without knowing significant implementation details of each
enterprise bean. To reuse one bean from an EJB module, you would generally have
to deploy all of them. So, it makes good sense to package together a group of enter-
prise beans only if they will be commonly deployed and used together.
The utility classes used by a bean must be packaged into the EJB module of
that bean in order for the bean to function correctly at runtime. If you package
related beans together, you reduce the number of copies of utility classes which
would otherwise increase the virtual machine size of most J2EE servers and could
cause potential conflicts during upgrades.
EJB modules will commonly be displayed in a palette of reusable components
in a J2EE application assembly tool. Tools will commonly group together enter-
prise beans from the same EJB module in a user interface. For example, it makes
sense to group server-side components related to accounting functionality or spe-
cialized database functionality in a single code library or EJB module.
7.2.2.2 Grouping Interrelated Beans
Enterprise beans can call one another at runtime, and one enterprise bean can dele-
gate some of its functionality to another. Though some J2EE servers will support
CHAPTER 7 PACKAGING AND DEPLOYMENT172
highly efficient cross-application dependencies, enterprise beans that depend on one
another should be grouped together in the same JAR file for both organizational and
performance reasons. Where beans call one another, the EJB module may be deliv-
ered preassembled, with all the enterprise bean cross-references resolved within the
same unit. This makes the tasks of both the Assembler and the Deployer much
easier. Locating an appropriate accounting bean for use by a teller bean across a
number of servers may prove tedious despite the best efforts and user interface wiz-
ardry of the authors of a J2EE deployment tool. Where one bean delegates to
another, many servers will partition deployed EJB modules across different process
and even machine boundaries. If a bean makes frequent calls on another bean, there
may be performance issues when they are run within separate address spaces.
7.2.2.3 Grouping for Circular References
When two enterprise beans refer to each other, the result is a circular dependency.
Neither bean can function without the other and so neither is reusable without the
other. In some cases redesign may eliminate these dependencies. When circular ref-
erences are necessary, you should also package the components together in the same
EJB module to ensure reusability.
7.2.2.4 Groupings with Common Security Profiles
While each EJB module allows a number of abstract security roles to be specified,
enterprise beans are often written with a discrete set of users in mind. Enterprise
beans that have the same security profile should be grouped together to reduce nego-
tiation of security role names across EJB modules.
7.2.3 Web Modules
A Web module is the smallest deployable and usable unit of Web resources. A Web
module is packaged and deployed as a Web ARchive (WAR) file, a JAR file with a
.war extension. It contains:
• Java class files for the servlets and the classes that they depend on, optionally
packaged as a library JAR file
• JSP pages and their helper Java classes
• Static documents (for example, HTML, images, sound files, and so on)
PACKAGING J2EE APPLICATIONS 173
• Applets and their class files
• A Web deployment descriptor
The WAR file format does not conform to all the requirements of the JAR
format because the classes in a WAR file are not usually loadable by a classloader
if the JAR is added to a classpath.
7.2.4 Packaging Components Into Web Modules
The Web module is the smallest indivisible unit of Web resources functionality that
Application Component Providers will supply to the Application Assembler. There-
fore, an Application Component Provider needs to choose how to package Web tier
components into Web modules. This section contains guidelines for doing so.
7.2.4.1 Cross-Dependent Servlets
Servlets may directly call each other via HTTP. The URL by which a servlet is
known on the J2EE platform depends on the J2EE application in which it was
deployed. For reasons of robustness, servlets that call one another should be
deployed together. It is therefore recommended that you put them in the same Web
module.
7.2.4.2 Cross-Linked Static Content
Since a WAR file is typically deployed under its own context root, cross-linked Web
pages must be packaged in a single Web module to avoid broken links. Moreover,
cross-linked HTML Web pages are typically reusable as a bundle, so it makes sense
to package them together.
7.2.4.3 Logical Grouping of Functionality
A Web module that has a clearly defined purpose is easier to reuse in different sce-
narios than one with less well-defined overall behavior. For example, a well-
designed Web module concerned purely with inventory management can be reused
in many e-commerce applications that need inventory management capability. Such
a module would be ideal for adding a Web-based interface for inventory manage-
ment to the sample application.
CHAPTER 7 PACKAGING AND DEPLOYMENT174
7.2.5 Application Client Modules
Application client modules are packaged in JAR files with a .jar extension. Applica-
tion client modules contain:
• Java classes that implement the client
• An application client deployment descriptor
An application client will use a client JAR file created by the EJB JAR file
producer. The client JAR file consists of all the class files that a client program
needs to use to access the enterprise beans that are contained in an EJB module.
Figure 7.2 illustrates the various types of J2EE packages and how they can be
deployed. Although the figure only shows an independently deployed EJB
module, all three types of J2EE modules can be deployed independently.
7.3 Deployment Descriptors
A deployment descriptor is an XML-based text file whose elements describe how
to assemble and deploy the unit into a specific environment. Each element con-
sists of a tag and a value expressed in the following syntax: value.
Usually deployment descriptors are automatically generated by deployment tools,
so you will not have to manage them directly. Deployment descriptor elements
contain behavioral information about components not included directly in code.
Their purpose is to tell the Deployer how to deploy an application, not tell the
server how to manage components at runtime.
There are different types of deployment descriptors: EJB deployment descrip-
tor described in the Enterprise JavaBeans specification, Web deployment descrip-
tor described in the Servlet specification, and application and application client
deployment descriptors described in the J2EE specification.
Deployment descriptors specify two kinds of information:
• Structural information describes the different components of the JAR file, their
relationship with each other, and their external dependencies. An Application
Assembler or Deployer risks breaking the functionality of the component if
this information is changed. Environment entries and resource requirements
are part of structural information.
• Assembly information describes how contents of a JAR file can be composed
DEPLOYMENT DESCRIPTORS 175
into a deployable unit. Assembly information is optional. Assembly informa-
tion can be changed without breaking the functionality of the contents, al-
though doing so may alter the behavior of the assembled application.
The remainder of this section describes how to specify the most commonly
used deployment descriptor elements.
Figure 7.2 J2EE Packages
CHAPTER 7 PACKAGING AND DEPLOYMENT176
7.3.1 Specifying Deployment Descriptor Elements
This section describes how to specify commonly used elements in the various
deployment descriptors. First we describe elements common to various J2EE com-
ponent types. Then we describe elements specific to enterprise beans, in particular,
the elements related to transactions and persistence. Finally we cover Web compo-
nent elements. For the definitions of each type of deployment descriptor, see the
J2EE, EJB, and servlet specifications.
7.3.1.1 Common Elements
This section describes the deployment descriptor elements common across the dif-
ferent J2EE component types. These include environment entries, references to
enterprise beans, references to connection factories, and security-related elements.
Naming Environment Entries
Naming environment entries allow customization of a component during deploy-
ment or assembly without the need to access or change the component’s source
code. The container implements the naming environment, and provides it to the
component instance through a JNDI naming context.
The Deployer must ensure that the values of all the environment entries
declared by a component are set to meaningful values. The Deployer can modify
values of environment entries that have been previously set by the Application
Component Provider and/or Application Assembler. The Deployer must set the
values of those environment entries for which no value has been specified. The
description elements provided by the Application Component Provider or Appli-
cation Assembler help the Deployer with this task.
Naming environment entries are specified with the env-entry element. Code
Example 7.3 uses an environment entry to determine whether confirmation email
is sent when an order is processed. Code Example 7.4 shows how to set the value
of the environment entry.
public static boolean sendConfirmationMail() {
boolean boolVal = false;
try {
InitialContext ic = new InitialContext();
Boolean bool = (Boolean)
ic.lookup("java:comp/env/sendConfirmationMail");
if (bool != null) {
DEPLOYMENT DESCRIPTORS 177
boolVal = bool.booleanValue();
}
} catch (NamingException ne) {
...
}
return boolVal;
}
Code Example 7.3 Looking up a Naming Environment Entry
sendConfirmationMail
java.lang.Boolean
false
Code Example 7.4 Environment Entry Element
References to Enterprise Beans
There are two parts to the mechanism for establishing connections to enterprise
beans in a J2EE application: the Java language interface for accessing a bean and the
deployment descriptor declarations for identifying those references. The Applica-
tion Component Provider looks up the references in the source code of the referring
component using the Java interfaces, then identifies these references in the deploy-
ment descriptor when packaging the component. A Deployer binds enterprise bean
references to the enterprise beans’ homes in the target environment. The deployment
descriptor also allows an Application Assembler to link an enterprise bean reference
declared in one enterprise bean to other enterprise beans contained in the same EJB
module, or in other EJB modules in the same J2EE application unit. The link is an
instruction to the tools used by the Deployer that the enterprise bean reference must
be bound to the home of the specified enterprise bean.
Code Example 7.5 illustrates how a component obtains a reference to the
home interface of another enterprise bean. In the example, the Application Com-
ponent Provider of the ShoppingClientControllerEJB assigned the environment
entry cart as the name to refer to the home of another enterprise bean, Shopping-
CartHome. ShoppingClientControllerEJB calls a utility method getShopping-
CartHome, which performs a JNDI lookup of cart in the ejb subcontext of the
CHAPTER 7 PACKAGING AND DEPLOYMENT178
environment naming context java:comp/env. ShoppingClientControllerEJB
caches the reference to the home interface in the cart variable so that the lookup
need only be performed once.
public class ShoppingClientControllerEJB implements SessionBean {
public ShoppingCart getShoppingCart() {
if (cart == null) {
try {
ShoppingCartHome cartHome =
EJBUtil.getShoppingCartHome();
cart = cartHome.create();
} catch (CreateException ce) {
...
}
}
return cart;
}
}
public static ShoppingCartHome getShoppingCartHome() {
try {
InitialContext initial = new InitialContext();
Object objref = initial.lookup("java:comp/env/ejb/cart");
return (ShoppingCartHome) PortableRemoteObject.
narrow(objref, ShoppingCartHome.class);
} catch (NamingException ne) {
throw new GeneralFailureException(ne);
}
}
Code Example 7.5 Locating a Home Interface
An Application Component Provider must use the ejb-ref element of the
deployment descriptor to declare all enterprise bean references. Similarly, the
deployment descriptor for a Web component must contain ejb-ref elements for the
enterprise beans that it uses. Such declarations allow the EJB module consumer
(that is, Application Assembler or Deployer) to discover all the enterprise beans
used by the components.
DEPLOYMENT DESCRIPTORS 179
Code Example 7.6 illustrates the declaration of an enterprise bean reference to
ShoppingCart in the deployment descriptor for ShoppingClientController. Note
the ejb-ref-name element, which contains string ejb/cart used in the JNDI
lookup performed in Code Example 7.5.
TheShoppingClientController
TheShoppingClientController
com.sun.estore.control.ejb.
ShoppingClientControllerHome
com.sun.estore.control.ejb.
ShoppingClientController
com.sun.estore.control.ejb.
ShoppingClientControllerEJB
...
ejb/cart
Session
com.sun.estore.cart.ejb.ShoppingCartHome
com.sun.estore.cart.ejb.ShoppingCart
TheCart
...
Code Example 7.6 Enterprise Bean Reference Element
An Application Assembler uses the ejb-link element in the deployment
descriptor to link an enterprise bean reference to a target enterprise bean. The
ejb-link element is a subelement of the ejb-ref element. The value of the ejb-
link element is the name of the target enterprise bean, that is, the name defined in
the ejb-name element of the target enterprise bean. The target enterprise bean can
be in the same EJB module or in another EJB module in the same J2EE applica-
tion as the referencing enterprise bean. The Application Assembler needs to
ensure that the target enterprise bean is type compatible with the declared enter-
prise bean reference. This means that the target enterprise bean must be of the
type indicated in the ejb-ref-type element, and that the home and remote ele-
CHAPTER 7 PACKAGING AND DEPLOYMENT180
ments of the target enterprise bean must be type compatible with the home and
remote elements declared in the enterprise bean reference.
The ejb-link element in Code Example 7.6 indicates that the enterprise bean
reference cart declared in ShoppingClientController is linked to the enterprise
bean TheCart shown in Code Example 7.7.
TheCart
TheCart
com.sun.estore.cart.ejb.ShoppingCartHome
com.sun.estore.cart.ejb.ShoppingCart
com.sun.estore.cart.ejb.ShoppingCartEJB
Stateful
transaction-type>Container
Code Example 7.7 Enterprise Bean Element
References to Connection Factories
A connection factory is an object used to create connections to a resource manager.
For example, an object that implements the javax.sql.DataSource interface is a
connection factory for java.sql.Connection objects which provide connections to
database management systems.
An Application Component Provider must obtain connections to resources as
follows:
• Declare a connection factory reference in the component’s naming environ-
ment.
For each connection factory that is used by a component, an Application
Component Provider declares a connection factory reference in the deploy-
ment descriptor using the resource-ref element. This allows the EJB module
consumer (that is, Application Assembler or Deployer) to discover all the
connection factory references used by an enterprise bean. All connection fac-
tory references should be organized in the subcontexts of a component’s envi-
ronment, using a different subcontext for each resource manager type. For
example, all JDBC DataSource references might be declared in the
java:comp/env/jdbc subcontext (see Section 6.9.3.1 on page 159), and all
email sessions in the java:comp/env/mail subcontext. Connection factory
DEPLOYMENT DESCRIPTORS 181
references are also used to refer to URL resources and JMS connections.
• Look up the connection factory object in the component’s naming environ-
ment using the JNDI interface.
• Invoke the appropriate method on the connection factory method to obtain a
connection to the resource. The factory method is specific to the resource type.
It is possible to obtain multiple connections by calling the factory object mul-
tiple times.
A Deployer binds connection factory references to actual connection factories
that are configured in the Container.
Code Example 7.8 illustrates the mail connection factory reference in the
entry for the Mailer enterprise bean.
TheMailer
TheMailer
com.sun.estore.mail.ejb.MailerHome
com.sun.estore.mail.ejb.Mailer
...
mail/MailSession
javax.mail.Session
Container
Code Example 7.8 Connection Factory Reference Element
Note that the connection factory type must be compatible with the type
declared in the res-type element. The res-auth subelement of the resource-ref
element specifies whether resource signon is managed by an application compo-
nent or its container. See Section 6.9.3 on page 158 for more information on
resource signon.
The Mailer enterprise bean calls MailHelper to open a mail session. Code
Example 7.9 contains the code from the MailHelper class that requests a mail
CHAPTER 7 PACKAGING AND DEPLOYMENT182
session object declared as java:comp/env/mail/MailSession in the JNDI con-
text.
public void createAndSendMail(String to, String subject,
String htmlContents) {
try {
InitialContext ic = new InitialContext();
Session session = (Session) ic.
lookup("java:comp/env/mail/MailSession");
...
}
}
Code Example 7.9 Looking Up a Connection Factory
The Deployer must bind the connection factory references to the actual
resource factories configured in the target environment. A Deployer can use the
JNDI LinkRef mechanism to create a symbolic link to the actual JNDI name of
the connection factory. The Deployer also needs to provide any additional config-
uration information that the resource manager needs for opening and managing
the resource.
Security Elements
An Application Component Provider uses the security-role element to define
logical security roles that can be assumed by an authenticated principal. Code
Example 7.10 illustrates how the sample application defines the gold_customer
security role.
gold_customer
Code Example 7.10 Security Role Element
The security-role-ref element is used to link a role name used by the
isCallerInRole method with a security role. In the sample application, this
DEPLOYMENT DESCRIPTORS 183
method is used by the Order entity bean to enforce business rules based on
whether the user is a preferred customer.
Code Example 7.11 and Code Example 7.12 illustrate how the security-
role-ref element establishes a link between the string GOLD_CUSTOMER used by the
isCallerInRole method and the security role named gold_customer.
private int getBonusMiles() {
int miles = (totalPrice >= 100) ? 1000 : 500;
if (context.isCallerInRole("GOLD_CUSTOMER"))
miles += 1000;
return miles;
}
Code Example 7.11 Referencing a Security Role Name
GOLD_CUSTOMER
gold_customer
Code Example 7.12 Linking a Security Role Name and Security Role
An Application Component Provider declaratively controls access to an enter-
prise bean’s methods by specifying the method-permission element in the enter-
prise bean’s deployment descriptor. The component provider defines this element
to list the set of methods that can be accessed by each security role. The authoriza-
tion scenario described in Section 9.3.8 on page 232 illustrates how method-per-
mission elements affect the execution of enterprise bean methods.
7.3.1.2 Enterprise Bean Elements
The component-specific elements that must be specified for an enterprise bean are
those related to transactions and those related to persistence.
CHAPTER 7 PACKAGING AND DEPLOYMENT184
Transaction Elements
Two transaction elements must be specified: whether the bean uses container- or
bean-managed transaction demarcation, and for container-managed demarcation,
the transaction attributes of the bean’s methods.
An Application Assembler must ensure that the methods of the deployed
enterprise beans with container-managed transaction demarcation have been
assigned a transaction attribute. If the transaction attributes have not been
assigned by the Application Component Provider, they must be assigned by the
Application Assembler. Code Example 7.13 illustrates how transaction attributes
are declared for an Account entity bean. Recall that entity beans can only use con-
tainer-managed transactions. The container-transaction element for Account
specifies that when the changeContactInformation method is invoked, it must be
within the scope of a transaction. See Section 8.7.2.1 on page 205 for detailed
information about the values that a transaction attribute can take.
TheAccount
Remote
changeContactInformation
com.sun.estore.util.
ContactInformation
Required
Code Example 7.13 Transaction Elements
Persistence Elements
The Application Component Provider must specify whether a bean manages its own
persistence or uses container-managed persistence. When a bean uses container-
managed persistence, the Application Component Provider must specify the fields
of the bean. Code Example 7.14 illustrates how the Account entity bean uses the
persistence-type element to declare that it will manage its own persistence.
DEPLOYMENT DESCRIPTORS 185
Account of a shopper
TheAccount
...
Bean
Code Example 7.14 Persistence Element
7.3.1.3 Web Component Elements
Some of the more commonly used Web component deployment descriptor elements
are discussed in this section.
Servlet
The one deployment descriptor element that must be specified for a Web component
is the servlet element, shown in Code Example 7.15. This element associates a
logical identifier (servlet-name) with the name of the servlet class or the JSP file
associated with the component.
webTierEntryPoint
centralJsp
Main.jsp
Code Example 7.15 Servlet Element
Servlet Mapping
The servlet-mapping element specifies the URLs that the Web component is
aliased to handle. While the element is called servlet-mapping, it is used to map
URLs to both servlets and JSP pages. Code Example 7.16 aliases Main.jsp to
handle all requests coming to the set of URLs /control/*.
webTierEntryPoint
CHAPTER 7 PACKAGING AND DEPLOYMENT186
/control/*
Code Example 7.16 Servlet Mapping Element
Error Pages
The error-page element can be used to invoke an error page automatically when
the Web application throws a Java language exception. Code Example 7.17 shows
how to enable the J2EE server to send errorpage.jsp to the browser client if the
Web application ever throws any exception of the type java.lang.Exception or its
subclass.
java.lang.Exception
/errorpage.jsp
Code Example 7.17 Error Page Element
Form-Based Authentication Configuration
Form-based authentication is the preferred mechanism for authenticating applica-
tion users in the J2EE platform. Code Example 7.18 illustrates how to configure a
Web application to activate form-based authentication when the Web server receives
a request for the URL /control/placeorder. The security-constraint element
specifies that the URL /control/placeorder is a protected resource. The login-
config element specifies that the URL formbasedloginscreen will be displayed
when an unauthenticated user tries to access /control/placeorder. This page
contains an HTML form that prompts for a user name and password.
MySecureBit0
no description
/control/placeorder
POST
GET
DEPLOYMENT TOOLS 187
no description
gold_customer
customer
no description
NONE
FORM
default
formbasedloginscreen
formbasedloginerrorscreen
Code Example 7.18 Form-Based Authentication Configuration
7.4 Deployment Tools
Although deployment can be performed directly by editing XML text files, the
process best handled by specialized tools. This section describes the actions that a
deployment tool performs and outlines requirements on packaging and development
tools. The requirements serve as recommendations to vendors of packaging and
deployment tools and determine what developers can expect from such tools.
7.4.1 Deployment Tool Actions
This section discusses what happens behind the scenes when a J2EE application is
deployed on a J2EE server. Since there can be many J2EE applications deployed on
the same J2EE server, the J2EE servers typically register each application under a
different identifier. The deployment of a J2EE application involves three different
types of components: enterprise beans, Web components, and application clients.
For each enterprise bean, the J2EE server must perform the following tasks:
CHAPTER 7 PACKAGING AND DEPLOYMENT188
1. Generate and compile the stubs and skeletons for the enterprise bean.
2. Set up the security environment to host the enterprise bean according to its de-
ployment descriptor. This is needed so that the access to the methods of the en-
terprise bean can be regulated according to the security policy of the
application.
3. Set up the transaction environment for the enterprise bean according to its de-
ployment descriptor. This is needed so that the calls to the methods of the en-
terprise bean happen in the correct transaction context.
4. Register the enterprise bean, its environment properties, resources references,
and so on, in the JNDI name space.
5. Create database tables for enterprise beans that use container-managed persis-
tence.
For each Web component, the J2EE server must perform the following tasks:
1. Transfer the contents of the Web component underneath the document root of
the server. Since there can be more than one J2EE application installed, the
server may install each under a specific directory. For example, the J2EE SDK
installs each application under a context root specified at the deployment time.
The sample application is installed under the estore directory.
2. Initialize the security environment of the application. This involves configur-
ing the form-based login mechanism, role-to-principal mappings, and so on.
3. Register environment properties, resource references, and EJB references in
the JNDI name space.
4. Set up the environment for the Web application. For example, it performs the
alias mappings and configures the servlet context parameters.
5. Precompile JSP pages as specified in the deployment descriptor.
The tool used to deploy an application client, and the mechanism used to install
the application client, is not specified by the J2EE specification. Very sophisticated
J2EE products may allow the application client to be deployed on a J2EE server and
automatically made available to some set of (usually intranet) clients. Other J2EE
products may require the J2EE application bundle containing the application client
to be manually deployed and installed on each client machine. And yet another
approach would be for the deployment tool on the J2EE server to produce an instal-
lation package that could be taken to each client to install the application client.
DEPLOYMENT TOOLS 189
7.4.2 Deployment Tool Requirements
When considering the requirements on deployment tools, it is important to consider
the deployment process at two different times: during application development and
during production deployment. A developer’s deployment needs are different than
the needs of a Deployer installing a production application on a mission-critical
system. When an application is being developed, it must be deployed before it can
be tested. Developers want fast response times, and the ability to undeploy, rede-
ploy, and partially deploy applications easily and quickly. They will often make
minor changes to Java classes, and hence will not want to go through a lengthy
deployment process over and over again. They also need extensive debugging facili-
ties. Many Java development environments will contain a J2EE server optimized for
these purposes.
When deploying a production application on a mission-critical server, the pri-
orities are robustness, performance, and stability. Often, to avoid downtime and
unforeseen problems, the application is first brought up on parallel systems. The
foremost consideration of the Deployer is to be able to connect all legacy systems
to the newly developed application. A Deployer may also want detailed logging of
the deployment process.
The following sections explore packaging and deployment issues from a tools
perspective and point out differences, if any, in the light of the two different
deployment times.
7.4.2.1 Vendor-Specific Information
The J2EE platform specification specifies file formats for each of the three J2EE
component types and for a J2EE application itself. This specification defines how
such files must be structured to be correctly handled by a J2EE deployment tool. A
certain amount of information must be available to each container along with the
application code and deployment descriptor for proper runtime support of an appli-
cation. This information is usually related to bindings of the application in a vendor-
specific or environment specific setting. Here is a partial list of information the
deployment tool of the J2EE SDK solicits from the Deployer after consuming an
application EAR file:
• A JNDI name for each enterprise bean’s home interface
• A mapping of abstract security roles of the application to user and group names
• JNDI lookup names and account information for all databases
CHAPTER 7 PACKAGING AND DEPLOYMENT190
• JavaMail session configuration information
Note that these issues only come up at deployment time—they in no way
affect the ability to deploy an application on servers from different J2EE Product
Providers.
There are many ways to represent this information. The J2EE SDK represents
this information in an XML document held as a separate entry within the applica-
tion archive. Code Example 7.19 is an example of the XML document that repre-
sents runtime information for the sample application after the runtime bindings
have been made with the J2EE SDK:
localhost
j2ee
TheAccount
estore/account
jdbc/EstoreDataSource
jdbc/EstoreDB
estoreuser
DEPLOYMENT TOOLS 191
estore
Code Example 7.19 Runtime Deployment Descriptor
Different J2EE product vendors will also need to add similar information in
the deployment process of a J2EE application. Vendors may find it useful to take
advantage of the attribute ID mechanism afforded by document type definitions to
link vendor-specific information to components and entities within a J2EE appli-
cation.
The output of a deployment tool should remain compliant with the J2EE spec-
ifications in order that it may be easily opened in other deployment tools even
when such extra information has been added. We recommend that the deployment
descriptors within an application remain as unchanged as possible to support this.
We also recommend that the tools preserve vendor-specific information added to
an application across sessions. This can be done by storing such information with
or inside the J2EE application file or using an IDE-like project structure.
EJB and Web modules are independently deployable units and hence any
deployment tools should be able to accept and deploy them. Although the archive
files may be augmented with vendor-specific information, we recommend that
other deployment tools be able to accept and deploy these augmented EJB and
Web modules and J2EE applications even though they may not understand a par-
ticular vendor’s runtime binding information. We recommend that the vendor-spe-
cific information that the deployment tool expects have reasonable fall-back
default options for this purpose.
7.4.2.2 Single Point of Entry for Deployment
A high-end mission-critical server often consists of multiple physical servers. Often
the number of Web containers is greater than the number of EJB containers. In such
cases, the Deployer to shouldn’t have to install applications individually on each
machine. We recommend that the deployment process has a single point of entry—
either a stand-alone deployment tool or the deployment component of a J2EE server.
For example, the J2EE SDK has a deployment tool that provides a single point of
CHAPTER 7 PACKAGING AND DEPLOYMENT192
entry to the J2EE server. This central component then takes care of distributing
appropriate components on both the Web and the EJB containers.
This approach has following benefits:
• It simplifies the deployment process since the Deployer has to interact with
only one deployment tool. The Deployer also has a clear understanding of
when deployment is complete. The tool also handles determining which com-
ponents are required to be deployed on each machine.
• It provides a way to perform centralized logging and auditing.
• It provides better fault tolerance. Since the deployment tool has complete con-
trol over all application components on all servers, it can detect server failures
and handle them by dynamic load balancing. It can also detect when a server
comes back up and redeploy the application to bring it in sync. An added ad-
vantage is that the Deployer does not have to worry about load-balancing.
• It simplifies undeployment and upgrading.
7.4.2.3 Remotely Accessible Deployment
Deployers often need to deploy multiple applications on multiple J2EE servers. To
handle such scenarios more easily, the deployment tool should be remotely accessi-
ble as either a Web-based or client-server application. The deployment tool bundled
with the J2EE SDK takes a client-server approach, using RMI-IIOP to communicate
with the administration back-end of the J2EE server. The tool has the capability to
access multiple J2EE servers and deploy applications on them.
7.4.2.4 Undeployment Capability
In development-time deployment, it is critical to have undeployment capability for
quicker updating of new application components. In a high-end implementation, it
isn’t acceptable to have to bring down the server to add or remove new software
applications, so that high-end servers will likely support dynamic deployment and
dynamic undeployment. Low-end J2EE servers may not need to support this capa-
bility.
For many J2EE servers, deploying a J2EE application may be an atomic pro-
cess, with no support for incremental deployment of J2EE application compo-
nents. However, at stages of the application development process, it may be
desirable to test portions of an application. This requires the ability to divide a
SUMMARY 193
component application into smaller units so that each can be deployed and re-
deployed without the wait associated with deploying a full scale application.
7.4.2.5 JNDI Name Space Management
Deployers will need to bind external references in a J2EE application to entities in
their environment. Examples of such references include databases and enterprise
beans in the system. Since binding happens through the JNDI name space, Con-
tainer Providers need to provide tools to create and manage the JNDI name space.
These tools also need to control the access to the JNDI name space according to the
security policy of their environment.
7.4.2.6 Name Collision Management
Application Assemblers may use third-party enterprise beans, without control over
the names used for such enterprise beans. As a result, name collisions are bound to
occur. Packaging tools should automatically detect and handle such name collisions
by adjusting names through the ejb-link element of the bean’s deployment
descriptors.
7.4.2.7 Deployment Descriptor Versioning
The lifetime of many enterprise applications may be measured in years and even
decades. An important goal of the J2EE platform is to provide compatibility even
when systems and application components are upgraded. Packaging and deploy-
ment tools need to ensure that they do not add anything that is against the general
direction of evolution of deployment descriptors. They also need to follow the ver-
sioning conventions described in the J2EE, EJB, and servlet specifications.
7.5 Summary
The J2EE platform provides facilities to make the deployment process simple. It
uses JAR files as the standard package for components and applications, and XML-
based deployment descriptors for customizing parameters. For the most part, the
facilities provided by the platform support simplified application development
through the use of tools that can read and write deployment descriptor files. These
tools present users with a more intuitive view of the structure of an application and
the capabilities of its components.
CHAPTER 7 PACKAGING AND DEPLOYMENT194
The J2EE packaging and deployment process involves three different J2EE
roles: Application Component Provider, Application Assembler, and Deployer.
Application Component Providers specify component deployment descriptors
and package components into modules. Application Component Providers should
ensure that the Application Assembler and the Deployer can customize an enterprise
bean’s business logic via deployment descriptors rather than modifying source code.
When packaging components into modules, Application Component Providers
need to balance between the competing goals of reusability and simplicity.
Application Assemblers resolve dependencies between deployment descriptor
elements in different modules and assemble modules into larger deployment units.
Deployers customize deployment descriptor elements for environment in which
the application is deployed and install deployment units. The Deployer must
ensure that the values of all the environment entries declared by an enterprise bean
are set to meaningful values.
The packaging and deployment process is best handled by specialized tools.
Both Component Providers and Deployers need to deploy applications; however,
their deployment needs are different. Component Providers want fast response
times, and the ability to undeploy, redeploy, and partially deploy applications
easily and quickly. In production, the priorities are robustness, performance, and
stability. Deployment tools need to address both sets of requirements, as well as
J2EE goals such as portability and backwards compatibility.
About the Author
TONY NG is a Staff Engineer at Sun Microsystems. He is part of the J2EE Reference
Implementation team, where he leads the development of the J2EE Connector architec-
ture, distributed transaction, and database connection management in the reference
implementation. Tony also participated in the development of the J2EE programming
model and the Java Transaction Service. Formerly, he worked on Java Blend, an object-
relational database mapping product. Tony has a B.S. in Computer Science from the
University of Illinois at Urbana-Champaign and an M.S. in Electrical Engineering and
Computer Science from the Massachusetts Institute of Technology.
197
C H A P T E R 8
Transaction Management
by Tony Ng
TRANSACTIONS are a mechanism for simplifying the development of distributed
multiuser enterprise applications. By enforcing strict rules on an application’s
ability to access and update data, transactions ensure data integrity. A transactional
system ensures that a unit of work either fully completes or the work is fully rolled
back. Transactions free an application programmer from dealing with the complex
issues of failure recovery and multiuser programming.
The chapter begins with a general overview of transaction properties and
J2EE platform support for transactions. Then it describes the Java Transaction
API, the interface used by the J2EE platform to manage and coordinate transactions.
Finally, the chapter describes the J2EE transactional model available to the differ-
ent types of J2EE components and to enterprise information systems.
8.1 Properties of Transactions
All transactions share the properties of atomicity, consistency, isolation, and durabil-
ity. These properties are denoted by the acronym ACID.
Atomicity requires that all of the operations of a transaction are performed
successfully for the transaction to be considered complete. If all of a transaction’s
operations cannot be performed, then none of them may be performed.
Consistency refers to data consistency. A transaction must transition the data
from one consistent state to another. The transaction must preserve the data’s
semantic and physical integrity.
Isolation requires that each transaction appear to be the only transaction cur-
rently manipulating the data. Other transactions may run concurrently. However, a
CHAPTER 8 TRANSACTION MANAGEMENT198
transaction should not see the intermediate data manipulations of other transac-
tions until and unless they successfully complete and commit their work. Because
of interdependencies among updates, a transaction might get an inconsistent view
of the database were it to see just a subset of another transaction’s updates. Isola-
tion protects a transaction from this sort of data inconsistency.
Durability means that updates made by committed transactions persist in the
database regardless of failures that occur after the commit operation and it also
ensures that databases can be recovered after a system or media failure.
8.2 J2EE Platform Transactions
Support for transactions is an essential element of the J2EE architecture. The J2EE
platform supports both programmatic and declarative transaction demarcation. The
component provider can use the Java Transaction API to programmatically demar-
cate transaction boundaries in the component code. Declarative transaction demar-
cation is supported in enterprise beans, where transactions are started and completed
automatically by the enterprise bean’s container. In both cases, the burden of imple-
menting transaction management is on the J2EE platform. The J2EE server imple-
ments the necessary low-level transaction protocols, such as interactions between
transaction manager and JDBC database systems, transaction context propagation,
and optionally distributed two-phase commit. Currently, the J2EE platform only
supports flat transactions. A flat transaction cannot have any child (nested) transac-
tions.
The J2EE platform supports a transactional application that is comprised of a
combination of servlets and/or JSP pages accessing multiple enterprise beans
within a single transaction. Each component may acquire one or more connections
to access one or more shared resource managers. Currently, the J2EE platform is
only required to support access to a single JDBC database within a transaction
(multiple connections to the same database are allowed). It is not required to
support access to multiple JDBC databases within a single transaction. It is also
not required to support access to other types of enterprise information systems
such as enterprise resource planning systems. However, some products might
choose to provide these extra transactional capabilities. For example, the J2EE
SDK supports access to multiple JDBC databases in one transaction using the
two-phase commit protocol.
It is important for developers to understand and distinguish which transaction
capabilities are required and which are optional in a J2EE product. To write a truly
SCENARIOS 199
portable application, developers should only use features required by the J2EE
specification. For example, if a J2EE application needs to access multiple data-
bases under a single transaction, it will not run properly on a J2EE product that
does not support two-phase commit.
8.3 Scenarios
The following scenarios illustrate the use of transactions in a J2EE environment.
8.3.1 Accessing Multiple Databases
In Figure 8.1, a client invokes enterprise bean X. Bean X accesses database A using a
JDBC connection. Then enterprise bean X calls another enterprise bean Y. Y accesses
database B. The J2EE server and resource adapters for both database systems ensure
that updates to both databases are either all committed, or all rolled back.
Figure 8.1 Accessing Multiple Databases in the Same Transaction
An Application Component Provider does not have to write extra code to
ensure transactional semantics. Enterprise beans X and Y access the database
systems using the JDBC client access API. Behind the scenes, the J2EE server
enlists the connections to both systems as part of the transaction. When the trans-
action is committed, the J2EE server and the resource managers perform a two-
phase commit protocol to ensure atomic update of the two systems.
CHAPTER 8 TRANSACTION MANAGEMENT200
8.3.2 Accessing Multiple Enterprise Information Systems From
Multiple EJB Servers
In Figure 8.2, a client invokes the enterprise bean X, which updates data in enterprise
information system A, and then calls another enterprise bean Y that is installed in
another J2EE server. Enterprise bean Y performs read-write access to enterprise
information system B.
Figure 8.2 Accessing Multiple Enterprise Information Systems in the Same
Transaction
When X invokes Y, the two J2EE servers cooperate to propagate the transaction
context from X to Y. This transaction context propagation is transparent to the
application code. At transaction commit time, the two J2EE servers use a distrib-
uted two-phase commit protocol to ensure that the two enterprise information
systems are updated under a single transaction.
8.4 JTA Transactions
A JTA transaction is a transaction managed and coordinated by the J2EE platform.
A J2EE product is required to support JTA transactions according to the transaction
requirements defined in the J2EE specification. A JTA transaction can span multiple
components and enterprise information systems. They are propagated automatically
between components and to enterprise information systems accessed by compo-
nents within that transaction. For example, a JTA transaction may be comprised of a
JTA TRANSACTIONS 201
servlet or JSP page accessing multiple enterprise beans, some of which access one
or more relational databases.
There are two ways to begin a JTA transaction. A component can begin a JTA
transaction using the JTA javax.transaction.UserTransaction interface. For an
enterprise bean, a JTA transaction might also be started automatically by the EJB
container if the bean uses container-managed transaction demarcation.
The main benefit of using JTA transactions is the ability to combine multiple
components and enterprise information system accesses into one single transac-
tion with little programming effort. For example, if a component A begins a JTA
transaction and invokes a method of component B, the transaction will be propa-
gated transparently from component A to B by the platform. Similarly, if compo-
nent A updates a table in a relational database, the update will automatically be
under the scope of the same transaction. No extra programming is required to
propagate transactions between multiple components and enterprise information
systems. In addition, enterprise beans using container-managed transaction
demarcation will not need to begin or commit transactions programmatically as
the demarcation is handled automatically by the EJB container.
It is recommend that an enterprise information system, such as a database, be
accessed within the scope of a JTA transaction. Accessing an enterprise informa-
tion system within a transaction provides some guarantee on the consistency and
integrity of the data. In addition, using a JTA transaction allows work performed
by multiple components through multiple enterprise information system connec-
tions to be grouped as an atomic unit. It also allows work performed on one or
more independent enterprise information systems to be grouped as an atomic unit
if the J2EE product supports two-phase commit.
8.4.1 JTA and JTS
JTA allows applications to access transaction management in a manner that is inde-
pendent of a specific implementation. JTA specifies standard Java interfaces
between a transaction manager and the parties involved in a distributed transaction
system: the transactional application, the J2EE server, and the manager that controls
access to the shared resources affected by the transactions.
JTS specifies the implementation of a transaction manager that supports JTA
and implements the Java mapping of the OMG Object Transaction Service (OTS)
1.1 specification at the level below the API. JTS propagates transactions using
IIOP. A JTS transaction manager provides the services and management functions
CHAPTER 8 TRANSACTION MANAGEMENT202
required to support transaction demarcation, transactional resource management,
synchronization, and transaction context propagation.
An Application Component Provider uses the JTA UserTransaction interface
to demarcate JTA transaction boundaries in components. The JTS
TransactionManager and XAResource interfaces are low-level APIs between a
J2EE server and enterprise information system resource managers and are not
intended to be used by applications.
A J2EE platform might choose to use a JTS implementation to support the
transaction semantics defined in J2EE specification. An example is the J2EE
SDK. The JTS implementation is transparent to J2EE components. Components
should never interact directly with JTS. Instead, they should use the JTA
UserTransaction interface for transaction demarcation.
8.5 Transactions in Applets and Application Clients
The J2EE platform does not require transaction support in applets and application
clients, though like distributed transactions, a J2EE product might choose to provide
this capability for added value. So, whether applets and application clients can
directly access a UserTransaction object depends on the capabilities provided by
the container. To ensure portability, applets and application clients should delegate
transactional work to enterprise beans.
8.6 Transactions in Web Components
A servlet or JSP page can use JNDI to lookup a UserTransaction object, then use
the UserTransaction interface to demarcation transactions. This is useful in a two-
tier application where a Web component needs to access enterprise information
systems under the scope of a JTA transaction.
Code Example 8.1 illustrates the use of the JTA interface to demarcate trans-
actions within a Web component:
Context ic = new InitialContext();
UserTransaction ut =
(UserTransaction) ic.lookup("java:comp/UserTransaction");
ut.begin();
TRANSACTIONS IN ENTERPRISE BEANS 203
// perform transactional work here
ut.commit();
Code Example 8.1 Web Component Using JTA Transactions
A Web component may only start a transaction in its service method. A
transaction that is started by a servlet or JSP page must be completed before the
service method returns. In other words, transactions may not span Web requests.
There are many subtle and complex interactions between the use of JTA trans-
actions, threads, and JDBC connections. Web components should follow the
guidelines stated in the transaction management chapter of the J2EE specification:
• JTA transactions should be started and completed only from the thread in
which the service method is called. If the Web component creates additional
threads for any purpose, these threads should not attempt to start JTA transac-
tions.
• JDBC connections may be acquired and released by a thread other than the
service method thread, but should not be shared between threads.
• JDBC Connection objects should not be stored in static fields.
• For Web components implementing SingleThreadModel, JDBC Connection
objects may be stored in class instance fields.
• For Web components not implementing SingleThreadModel, JDBC Connec-
tion objects should not be stored in class instance fields, and should be ac-
quired and released within the same invocation of the service method.
In a multitier environment, servlets and JSP pages are mainly responsible for
the presentation of the application and dealing with browser interaction. In this
case, the use of JTA transactions in the Web tier is not recommended. Instead,
transactional work such as database access should be delegated to enterprise beans
in the EJB tier.
8.7 Transactions in Enterprise Beans
There are two types of transaction demarcation in enterprise beans: bean-managed
and container-managed. In container-managed transaction demarcation, six differ-
CHAPTER 8 TRANSACTION MANAGEMENT204
ent transaction attributes—Required, RequiresNew, NotSupported, Supports, Man-
datory, and Never—can be associated with an enterprise bean’s method. An
Application Component Provider or Assembler specifies the type of transaction
demarcation and transaction attributes for the methods of the enterprise beans in the
deployment descriptor. The use of deployment descriptors to specify transaction ele-
ments is discussed and illustrated in “Transaction Elements” on page 184.
This section discusses the types of transactions and the attributes of container-
managed transactions and then presents guidelines for choosing among the avail-
able options.
8.7.1 Bean-Managed Transaction Demarcation
With bean-managed transaction demarcation, an enterprise bean uses the
javax.transaction.UserTransaction interface to explicitly demarcate transaction
boundaries. Only session beans can choose to use bean-managed demarcation. An
entity bean must always use container-managed transaction demarcation.
The following code illustrates the use of JTA interface to demarcate transac-
tions in an enterprise bean with bean-managed transaction demarcation.
UserTransaction ut = ejbContext.getUserTransaction();
ut.begin();
// perform transactional work here
ut.commit();
Code Example 8.2 Enterprise Bean Using a JTA Transaction
8.7.2 Container-Managed Transaction Demarcation
For an enterprise bean with container-managed transaction demarcation, the EJB
container is responsible for managing transaction boundaries. The transaction
attribute for a method determines what the EJB container needs to do in terms of
transaction management. For example, if a method has a transaction attribute
RequiresNew, the EJB container will begin a new JTA transaction every time this
method is called and attempt to commit the transaction before the method returns.
The same transaction attribute can be specified for all the methods of an enterprise
bean or different attributes can be specified for each method of a bean. Refer to
Section 8.7.2.1 on page 205 for more information on transaction attributes.
TRANSACTIONS IN ENTERPRISE BEANS 205
Even in container-managed demarcation, an enterprise bean has some control
over the transaction. For example, an enterprise bean can choose to roll back a
transaction started by the container using the method setRollbackOnly on the
SessionContext or EntityContext object.
There are several benefits of using container-managed transaction demarca-
tion:
• The transaction behavior of an enterprise bean is specified declaratively in-
stead of programmatically. This frees the Application Component Provider
from writing transaction demarcation code in the component.
• It is less error-prone because the container handles transaction demarcation au-
tomatically.
• It is easier to compose multiple enterprise beans to perform a certain task with
specific transaction behavior. An Application Assembler that understands the
application can customize the transaction attributes in the deployment descrip-
tor without code modification.
8.7.2.1 Transaction Attributes
A transaction attribute is a value associated with a method of an enterprise bean that
uses container-managed transaction demarcation. In most cases, all methods of an
enterprise bean will have the same transaction attribute. For optimization purposes,
it is possible to have different attributes for different methods. For example, an
enterprise bean may have methods that don’t need to be transactional.
A transaction attribute must be specified for the methods in the remote inter-
face of a session bean and for the methods in the remote and home interfaces of an
entity bean.
Required
If the transaction attribute is Required, the container ensures that the enterprise
bean’s method will always be invoked with a JTA transaction. If the calling client is
associated with a JTA transaction, the enterprise bean method will be invoked in the
same transaction context. However, if a client is not associated with a transaction,
the container will automatically begin a new transaction and try to commit the trans-
action when the method completes.
CHAPTER 8 TRANSACTION MANAGEMENT206
RequiresNew
If the transaction attribute is RequiresNew, the container always creates a new trans-
action before invoking the enterprise bean method and commits the transactions
when the method returns. If the calling client is associated with a transaction con-
text, the container suspends the association of the transaction context with the
current thread before starting the new transaction. When the method and the trans-
action complete, the container resumes the suspended transaction.
NotSupported
If the transaction attribute is NotSupported, the transactional context of the calling
client is not propagated to the enterprise bean. If a client calls with a transaction
context, the container suspends the client’s transaction association before invoking
the enterprise bean’s method. After the method completes, the container resumes the
suspended transaction association.
Supports
It the transaction attribute is Supports, and the client is associated with a transaction
context, the context is propagated to the enterprise bean method, similar to the way
the container treats the Required case. If the client call is not associated with any
transaction context, the container behaves similarly to the NotSupported case. The
transaction context is not propagated to the enterprise bean method.
Mandatory
The transaction attribute Mandatory requires the container to invoke a bean’s
method in a client’s transaction context. If the client is not associated with a transac-
tion context when calling this method, the container throws javax.transac-
tion.TransactionRequiredException. If the calling client has a transaction
context, the case is treated as Required by the container.
Never
The transaction attribute Never requires that the enterprise bean method not be
called within a transaction context. If the client calls with a transaction context, the
container throws the java.rmi.RemoteException. If the client is not associated with
any transaction context, the container invokes the method without initiating a trans-
action.
TRANSACTIONS IN ENTERPRISE BEANS 207
8.7.3 Transaction Guidelines
As mentioned previously, the recommended way to manage transactions is through
container-managed demarcation. Declarative transaction management provides one
of the major benefits of the J2EE platform, by freeing the Application Component
Provider from the burden of managing transactions. Furthermore, the transaction
characteristics of an application can be changed without code modification by
switching the transaction attributes. Transaction demarcation should be selected
with great care, by someone who understands the application well. Bean-managed
transaction demarcation is only for advanced users who want more control over the
work flow.
8.7.3.1 Transaction Attributes Guidelines
Most enterprise beans perform transactional work (for example, accessing a JDBC
database). The default choice for a transaction attribute should be Required. Using
this attribute ensures that the methods of an enterprise bean are invoked under a JTA
transaction. In addition, enterprise beans with the Required transaction attribute can
be easily composed to perform work under the scope of a single JTA transaction.
The RequiresNew transaction attribute is useful when the bean method needs
to commit its results unconditionally, whether or not a transaction is already in
progress. An example of this requirement is a bean method that performs logging.
This bean method should be invoked with RequiresNew transaction attribute so
that the logging records are created even if the calling client’s transaction is rolled
back.
The NotSupported transaction attribute can be used when the resource
manager responsible for the transaction is not supported by the J2EE product. For
example, if a bean method is invoking an operation on an enterprise resource plan-
ning system that is not integrated with the J2EE server, the server has no control
over that system’s transactions. In this case, it is best to set the transaction
attribute of the bean to be NotSupported to clearly indicate that the enterprise
resource planning system is not accessed within a JTA transaction.
We do not recommend using the transaction attribute Supports. An enterprise
bean with this attribute would have transactional behavior that differed depending
on whether the caller is associated with a transaction context, leading to possibly a
violation of the ACID rules for transactions.
The transaction attributes Mandatory and Never can be used when it is neces-
sary to verify the transaction association of the calling client. They reduce the
CHAPTER 8 TRANSACTION MANAGEMENT208
composability of a component by putting constraints on the calling client’s trans-
action context.
8.8 Transactions in Enterprise Information Systems
Most enterprise information systems support some form of transactions. For exam-
ple, a typical JDBC database allows multiple SQL updates to be grouped in an
atomic transaction.
Components should always access an enterprise information system under the
scope of a transaction since this provides some guarantee on the integrity and con-
sistency of the underlying data. Such systems can be accessed under a JTA trans-
action or a resource manager (RM) local transaction.
8.8.1 JTA Transactions
When an enterprise information system is accessed under the scope of a JTA trans-
action, any updates performed on the system will commit or roll back depending on
the outcome of the JTA transaction. Multiple connections to information systems
can be opened and all updates through the connections will be atomic if they are
performed under the scope of a JTA transaction. The J2EE server is responsible for
coordinating and propagating transactions between the server and the enterprise
information system.
If the J2EE product supports multiple enterprise information systems in one
transaction, a J2EE application can access and perform updates on multiple enter-
prise information systems atomically, without extra programming effort, by
grouping all updates within a JTA transaction. Code Example 8.3 illustrates this
use:
InitialContext ic = new InitialContext("java:comp/env");
DataSource db1 = (DataSource) ic.lookup("OrdersDB");
DataSource db2 = (DataSource) ic.lookup("InventoryDB");
Connection con1 = db1.getConnection();
Connection con2 = db2.getConnection();
UserTransaction ut = ejbContext.getUserTransaction();
ut.begin();
// perform updates to OrdersDB using connection con1
TRANSACTIONS IN ENTERPRISE INFORMATION SYSTEMS 209
// perform updates to InventoryDB using connection con2
ut.commit();
Code Example 8.3 Accessing Multiple Databases
8.8.2 Resource Manager Local Transactions
A resource manager local transaction (or local transaction) is a transaction specific
to a particular enterprise information system connection. A local transaction is
managed by the underlying enterprise information system resource manager. The
J2EE platform usually does not have control or knowledge about any local transac-
tions begun by components. Typically access to a transactional enterprise informa-
tion system will be under a local transaction if no JTA transaction has been initiated.
For example, if a servlet accesses a JDBC database without starting a JTA transac-
tion, the database access will be under the scope of a local transaction, specific to the
database.
Another scenario where enterprise information system access is under the
scope of a local transaction is when the enterprise information system is not sup-
ported by the J2EE platform. For example, a standard J2EE platform is not
required to support object-oriented databases. As a result, the platform would not
be able to propagate any JTA transactions to the object-oriented databases and any
access will be under local transactions.
8.8.3 Choosing Between JTA and Local Transactions
It is recommended that enterprise information systems, such as databases, be
accessed under the scope of a transaction. Accessing an enterprise information
system under a transaction provides some guarantee on the consistency and integ-
rity of the data.
We recommend that a component use JTA transactions whenever possible to
access enterprise information systems. Using a JTA transaction allows multiple
components accessing enterprise information systems to be grouped in a single
transaction without adding extra logic. If a component marks the transaction as
rollback only, all enterprise information system work will be rolled back automat-
ically. With local transactions, each enterprise information system accessed will
have to be committed or rolled back explicitly. In addition, components need extra
logic to deal with individual enterprise information system rollbacks or failures.
CHAPTER 8 TRANSACTION MANAGEMENT210
8.8.4 Compensating Transactions
A compensating transaction is a transaction or a group of operations that is used
to undo the effect of a previously committed transaction. In the case where multi-
ple access to enterprise information systems need to be grouped under a single
transaction, but not all of the systems support JTA transactions, it will be neces-
sary to define a compensating transaction for each enterprise information system
access that is under the scope of a local transaction.
Compensating transactions are useful if a component needs to access an enter-
prise information system that does not support JTA transactions or access an
enterprise information system that is not supported by a particular J2EE platform.
In both cases, the enterprise information system will be accessed under the scope
of a RM local transaction. If multiple enterprise information systems are involved,
this creates the challenge of having to group all the work to multiple enterprise
information systems into an atomic unit.
For example, suppose an application needs to perform an atomic operation
that involves updating three enterprise information systems: two JDBC databases
that supports JTA transactions and an enterprise resource planning system that
does not. The application would need to define a compensating transaction for the
update to the enterprise resource planning system. The approach is illustrated in
Code Example 8.4.
updateERPSystem();
try {
UserTransaction.begin();
updateJDBCDatabaseOne();
updateJDBCDatabaseTwo();
UserTransaction.commit();
}
catch (RollbackException ex) {
undoUpdateERPSystem();
}
Code Example 8.4 Compensating Transaction
The methods updateERPSystem, updateJDBCDatabaseOne, and updateJDBCDa-
tabaseTwo contain code to access and perform work on enterprise information
TRANSACTIONS IN ENTERPRISE INFORMATION SYSTEMS 211
systems. The undoUpdateERPSystem method contains code to undo the effect of
updateERPSystem if the JTA transaction does not commit successfully.
This compensation logic should be encapsulated in a session enterprise bean
with a bean-managed transaction. If the enterprise information system access
logic is relatively simple, they can all reside in this bean. Otherwise, the enterprise
bean can invoke other enterprise beans to access the enterprise information
system. If an enterprise bean’s only responsibility is to access an enterprise infor-
mation system that does not support JTA transactions, its transaction attribute
should be set to NotSupported. This denotes that a JTA transaction will not be
used in the enterprise bean.
There are a few pitfalls regarding the use of compensating transactions:
• It is not always possible to undo the effect of a committed transaction. Consid-
er Code Example 8.4. If the JTA transaction does not commit and for some rea-
son the method undoUpdateERPSystem does not succeed, the data will be left in
an inconsistent state.
• Atomicity could also be broken if the server crashes when a compensating
transaction is used. For example, if the system crashes after the method
updateERPSystem, the updates to the two databases will not happen.
• Inconsistent data might be seen by concurrent enterprise information system
access. In this approach, non-JTA transactions are actually committed but may
be undone subsequently. In the previous example, a concurrent enterprise in-
formation system access might see the update to the enterprise resource plan-
ning system which might be rolled back later. In other words, it sees
uncommitted data.
An application that depends on compensating transactions must have extra
logic to deal with potential failures and inconsistencies. The extra work and pit-
falls of compensating transactions mean applications should avoid using them if
possible. Instead, JTA transactions should be used as they provide a simple and
safe way to achieve the ACID properties across multiple components and enter-
prise information systems.
CHAPTER 8 TRANSACTION MANAGEMENT212
8.8.5 Isolation Level
An isolation level defines how concurrent transactions to an enterprise information
system are isolated from one another. Enterprise information systems usually
support the following the isolation levels:
• ReadCommitted: This level prevents a transaction from reading uncommitted
changes from other transactions.
• RepeatableRead: This level prevents a transaction from reading uncommitted
changes from other transactions. In addition, it ensures that reading the same
data multiple times will receive the same value even if another transaction
modifies the data.
• Serializable: This level prevents a transaction from reading uncommitted
changes from other transactions and ensures that reading the same data multi-
ple times will receive the same value even if another transaction modifies the
data. In addition, it ensures that if a query retrieves a result set based on a pred-
icate condition and another transaction inserts data that satisfy the predicate
condition, re-execution of the query will return the same result set.
Isolation level and concurrency are closely related. A lower isolation level
typically allows greater concurrency, at the expense of more complicated logic to
deal with potential data inconsistencies. A useful guideline is to use the highest
isolation level provided by enterprise information systems that gives acceptable
performance.
For consistency, all enterprise information systems accessed by a J2EE appli-
cation should use the same isolation level. Currently, the J2EE specification does
not define a standard way to set isolation levels when an enterprise information
system is accessed under JTA transactions. If a J2EE product does not provide a
way to configure the isolation level, the enterprise information system default iso-
lation level will be used. For most relational databases, the default isolation level
is ReadCommitted.
We recommend that you not change the isolation level within a transaction,
especially if some work has already been done. Some enterprise information
systems will force a commit if you attempt to change the isolation level.
SUMMARY 213
8.9 Summary
This chapter provides the guidelines for using transactions on the J2EE platform.
It describes the J2EE transactional model available to each J2EE component type—
application clients, JSP pages and servlets, and enterprise beans—and enterprise
information systems.
The J2EE platform provides powerful support for writing transactional appli-
cations. It contains the Java Transaction API, which allows applications to access
transactions in a manner that is independent of specific implementations and a
means for declaratively specifying the transactional needs of an application. These
capabilities shift the burden of transaction management from J2EE Application
Component Providers to J2EE product vendors. Application Component Provid-
ers can thus focus on specifying the desired transaction behavior, and rely on a
J2EE product to implement the behavior.
About the Author
RON MONZILLO is a Senior Staff Engineer at Sun Microsystems where he is the
J2EE security specification lead. Prior to joining Sun, Ron worked for the Open Group
where he contributed to the evolution of the Distributed Computing Environment. Ron
has also worked for BBN, where he developed Network Management systems, and as a
Principal Investigator for the MITRE Corporation where he researched fault-tolerant
distributed database systems and multi-processor architectures. Ron received an M.S. in
Computer Science from the University of Connecticut and a B.S. in Biology from Bates
College.
215
C H A P T E R 9
Security
by Ron Monzillo
IN an enterprise computing environment, failure, compromise, or lack of availabil-
ity of computing resources can jeopardize the viability of the enterprise. An organi-
zation must take steps to identify threats to security. Once they are identified, steps
should be taken to reduce these threats.
It is unreasonable to assume that J2EE products, and hence J2EE applications,
can displace existing enterprise security infrastructures. The J2EE application
programming model attempts to leverage existing security services rather than
require new services or mechanisms.
This discussion begins with a review of some security concepts and mecha-
nisms. We describe the security concerns and characteristics of enterprise applica-
tions and explore the application of J2EE security mechanisms to the design,
implementation, and deployment of secure enterprise applications.
9.1 Security Threats and Mechanisms
Threats to enterprise-critical assets fall into a few general categories:
• Disclosure of confidential information
• Modification or destruction of information
• Misappropriation of protected resources
• Compromise of accountability
• Misappropriation that compromises availability
CHAPTER 9 SECURITY216
Depending on the environment in which an enterprise application operates,
these threats may manifest themselves in different forms. For example, in a tradi-
tional single system environment, a threat of disclosure might manifest itself in
the vulnerability of information kept in files. In a distributed environment with
multiple servers and clients, a threat of disclosure might also result from expo-
sures occurring as the result of networking.
Although not all threats can or need be eliminated, there are many circum-
stances where exposure can be reduced to an acceptable level through the use of
the following security mechanisms: authentication, authorization, signing,
encryption, and auditing. The following sections describe J2EE platform security
mechanisms and indicate how the mechanisms are used to support security poli-
cies in an operational environment.
9.2 Authentication
In distributed component computing, authentication is the mechanism by which
callers and service providers prove to one another that they are acting on behalf of
specific users or systems. When the proof is bidirectional, we refer to it as mutual
authentication. Authentication establishes the call identities and proves that the par-
ticipants are authentic instances of these identities. An entity that participates in a
call without establishing and/or proving an identity (that is, anonymously), is
called unauthenticated.
When calls are made from a client program being run by a user, the caller
identity is likely to be that of the user. When the caller is an application compo-
nent acting as an intermediary in a call chain originating with some user, the iden-
tity may be associated with that of the user, in which case the component would
be impersonating the user. Alternatively, one application component may call
another with an identity of its own and unrelated to that of its caller.
Authentication is often achieved in two phases. First, service-independent
authentication requiring knowledge of some secret is performed to establish an
authentication context that encapsulates the identity and is able to fabricate
authenticators (proofs of identity). Then, the authentication context is used to
authenticate with other (called or calling) entities. Controlling access to the
authentication context, and thus the ability to authenticate as the associated iden-
AUTHENTICATION 217
tity, becomes the basis of authentication. Among the possible policies and mecha-
nisms for controlling access to an authentication context are:
• Once the user performs an initial authentication, the processes the user starts
inherit access to the authentication context.
• When a component is authenticated, access to the authentication context may
be available to other related or trusted components, such as those that are part
of the same application.
• When a component is expected to impersonate its caller, the caller may dele-
gate its authentication context to the called component.
9.2.1 Protection Domains
Some entities may communicate without requiring authentication. A protection
domain is a set of entities that are assumed or known to trust each other. Entities in
such a domain need not be authenticated to one another.
Figure 9.1 illustrates that authentication is only required for interactions that
cross the boundary of a protection domain. When a component interacts with
components in the same protection domain, no constraint is placed on the identity
that it can associate with its call. The caller may propagate the caller’s identity, or
choose an identity based on knowledge of authorization constraints imposed by
the called component, since the caller’s ability to claim an identity is based on
trust, not authentication. If the concept of protection domains is employed to
avoid the need for authentication, there must be a means to establish the bound-
aries of protection domains, so that trust in unproven identities does not cross
these boundaries. Entities that are universally trusting of all other entities should
not be trusted as a member of any protection domain.
In the J2EE architecture, a container provides an authentication boundary
between external callers and the components it hosts. The boundaries of protec-
tion domains don’t always align with those of containers. Containers enforce the
boundaries, and implementations are likely to support protection domains that
span containers. However, a container is not required to host components from
different protection domains, although an implementation may choose to do so.
CHAPTER 9 SECURITY218
Figure 9.1 Protection Domain
For inbound calls, it is the container’s responsibility to make an authentic rep-
resentation of the caller identity available to the component in the form of a cre-
dential. An X.509 certificate and a Kerberos service ticket are examples of
credentials. A passport or a driver’s licence are analogous artifacts used in person-
to-person interactions.
For outbound calls, the container is responsible for establishing the identity of
the calling component. In general, it is the job of the container to provide bidirec-
tional authentication functionality to enforce the protection domain boundaries of
the deployed applications.
Without proof of component identity, the interacting containers must deter-
mine if there is sufficient inter-container trust to accept the container-provided
representations of component identity. In some environments, trust may simply be
presumed, in others it may be more explicitly evaluated based on inter-container
authentication and possibly the comparison of container identities to lists of
trusted identities. If a required proof of identity is not provided, and in the absence
of a sufficient inter-container trust relationship, a container should reject or
abandon a call.
Figure 9.2 illustrates these authentication concepts in two scenarios: an
authenticated user scenario and an unauthenticated user scenario.
AUTHENTICATION 219
Figure 9.2 Authentication Scenarios
The authenticated user invokes a calling component that employs the user’s
authentication context to prove its identity to an intermediate component. When
the called component makes a call it propagates the identity of its caller. The prop-
agated identity is unproven, and so will be accepted only if the targets trust the
caller, that is, if they reside in the same protection domain. The figure also differ-
entiates identity propagation from delegation and subsequent impersonation. In
propagation, the service providers bear the burden of determining whether they
should accept propagated identities as authentic. In delegation, the user provides
the called component with access to its authentication context, enabling the called
CHAPTER 9 SECURITY220
component to impersonate the user in subsequent calls. Impersonation requires
the user to trust the impersonator to act in its behalf. The lower portion of the
figure depicts the propagation of an unauthenticated user identity in the form of an
anonymous credential. An anonymous credential is the one form of unproven
identity that may be propagated independent of trust.
9.2.2 Authentication Mechanisms
In a typical J2EE application, a user would go through a client container to interact
with enterprise resources in the Web or EJB tiers. Resources available to the user
may be protected or unprotected. Protected resources are distinguished by the pres-
ence of authorization rules (see Section 9.3 on page 225) that restrict access to some
subset of non-anonymous identities. To access a protected resource, a user must
present a non-anonymous credential such that its identity can be evaluated against
the resource authorization policy. In the absence of a trust relationship between the
client and resource containers, the credential must be accompanied by an authenti-
cator that confirms its validity. This section describes the various authentication
mechanisms supported by the J2EE platform and how to configure them.
9.2.2.1 Web Tier Authentication
An Application Component Provider can designate that a collection of Web
resources (Web components, HTML documents, image files, compressed archives,
and so on) is protected by specifying an authorization constraint (described in
Section 9.3.7.1 on page 230) for the collection. When an anonymous user tries to
access a protected Web resource, the Web container will prompt the user for a pass-
word to authenticate with the Web container. The request will not be accepted by the
Web container until the user identity has been proven to the Web container and
shown to be one of the identities granted permission to access the resource. Caller
authentication performed on the first access to a protected resource is called lazy
authentication.
When a user tries to access a protected Web-tier resource, the Web container
activates the authentication mechanism defined in the application’s deployment
descriptor. J2EE Web containers must support three authentication mechanisms:
HTTP basic authentication, form-based authentication, and HTTPS mutual authen-
tication, and are encouraged to support HTTP digest authentication.
In basic authentication, the Web server authenticates a principal using the user
name and password obtained from the Web client. In digest authentication a Web
AUTHENTICATION 221
client authenticates to a Web server by sending the server a message digest along its
HTTP request message. The digest is computed by employing a one-way hash algo-
rithm to a concatenation of the HTTP request message and the client’s password.
The digest is typically much smaller than the HTTP request, and doesn’t contain the
password.
Form-based authentication lets developers customize the authentication user
interface presented by an HTTP browser. Like HTTP basic authentication, form-
based authentication is not secure, since the content of the user dialog is sent as
plain text, and the target server is not authenticated.
In single-signon environments, discretion must be exercised in customizing
an application’s authentication interface. It may be preferable to provide a single
enterprise-wide custom user authentication interface, rather than implementing a
set of application-specific interfaces.
With mutual authentication, the client and server use X.509 certificates to
establish their identity. Mutual authentication occurs over a channel protected by
SSL. Hybrid mechanisms featuring either HTTP basic authentication, form-based
authentication, or HTTP digest authentication over SSL are also supported.
Authentication Configuration
An authentication mechanism is configured using the login-config element of the
Web component deployment descriptor. Code Example 9.1, Code Example 9.2, and
Code Example 9.3 illustrate the declaration of each type of authentication mecha-
nism.
BASIC|DIGEST
jpets
Code Example 9.1 HTTP Basic and Digest Authentication Configuration
FORM
CHAPTER 9 SECURITY222
login.jsp
error.jsp
Code Example 9.2 Form-Based Authentication Configuration
CLIENT-CERT
Code Example 9.3 Client Certificate Authentication Configuration
Hybrid Authentication
In both HTTP basic and form-based authentication, passwords are not protected for
confidentiality. This vulnerability can be overcome by running these authentication
protocols over an SSL-protected session, which ensures that all message content,
including the client authenticators, are protected for confidentiality. Code Example
9.4 demonstrates how to configure HTTP basic authentication over SSL using the
transport-guarantee element. Form-based authentication over SSL is configured
in the same way.
...
CONFIDENTIAL
Code Example 9.4 SSL Hybrid Authentication Mechanism
AUTHENTICATION 223
9.2.2.2 EJB Tier Authentication
The J2EE 1.2 platform specification doesn’t require interoperable caller authentica-
tion at the EJB container. Also, network firewall technology may prevent direct
Internet interaction (via RMI) between client containers and enterprise beans. One
way that an EJB container can protect access to enterprise beans is to entrust the
Web container to vouch for the identity of users accessing the beans via protected
Web components. As illustrated in Figure 9.3, such configurations use the Web con-
tainer to enforce protection domain boundaries for Web components and the enter-
prise beans that they call.
Figure 9.3 Typical J2EE Application Configuration
9.2.3 Authentication Call Patterns
In a multitier, multicomponent application, certain call patterns should be avoided
for security reasons. For example, an application that calls protected EJB resources
from unprotected Web resources can run into problems, because the Web tier’s lazy
authentication paradigm doesn’t require user authentication except when the user
attempts to access a protected resource. While the protection requirement can be
moved to the EJB tier, care must be taken to ensure that users who are capable of
authenticating can do so. With lazy authentication, a user who wants to visit a pro-
tected EJB resource must have visited a protected Web resource. One way to ensure
this would be to front every protected EJB resource with a protected Web resource.
Another approach would be to link to a protected Web resource (perhaps appearing
as an authenticate button) on every Web resource that calls EJB resources. This
approach gives the user the option of authenticating (by visiting the protected Web
resource linked behind the button) prior to accessing an EJB resource, especially
after having been denied access by the EJB resource through an unprotected page.
CHAPTER 9 SECURITY224
When an application is deployed with a hybrid authentication mechanism, the
Deployer must ensure that the transport-guarantee element of each protected
Web resource is set to CONFIDENTIAL. Otherwise, the client authenticator won’t be
fully protected.
9.2.3.1 Enterprise Information System Tier Authentication
In integrating with enterprise information systems, J2EE components may use dif-
ferent security mechanisms and operate in different protection domains than the
resources they access. In these cases, the calling container can be configured to
manage the authentication to the resource for the calling component. This form of
authentication is called container-managed resource manager signon. The J2EE
architecture also recognizes that some components require an ability to manage the
specification of caller identity, and the production of a suitable authenticator
directly. For these applications, the J2EE architecture provides a means for an appli-
cation component to engage in what is called application-managed resource
manager signon. Application-managed resource manager signon is used when
manipulating the authentication details is a fundamental aspect of the component’s
functionality.
The resource-ref elements of a component’s deployment descriptor
(described in greater detail in Section 9.3 on page 225) declares the resources used
by the component. The subelement res-auth specifies the type of signon authenti-
cation. Components can use the EJBContext.getCallerPrincipal and HttpServ-
letRequest.getUserPrincipal methods to obtain the identity of their caller. The
component may map the caller identity to a new identity and/or authentication
secret as required by the target enterprise information system.
With container-managed resource manager signon, the container would
perform the principal mapping on behalf of the calling component. Container-
managed principal mapping isn’t explicitly defined in any of the J2EE specifica-
tions. Whether it is performed by the container or embedded in the caller, the
mapping of caller identity to an identity and authentication secret capable of
accessing resources in the enterprise information system tier should be modeled
as a protected resource, and secured by appropriate authorization rules (see
Section 9.3.6 on page 229).
The Connector architecture discussed in Section 6.10 on page 161 offers a
standard API for application-managed resource manager signon. The Connector
provided API will ensure portability of components that authenticate with enter-
prise information systems.
AUTHORIZATION 225
9.2.4 Auto-Registration
Many e-commerce applications are designed to make it as easy as possible for a user
to become a customer. In contrast to typical computer user authentication environ-
ments, where a user must wait for an administrator to set up the user’s account,
many e-commerce applications enable users to set up their own accounts without
administrative intervention. Frequently the user is required to provide his or her
identity and location, agree to some contractual obligations, provide credit card
information for payment, and establish a password to protect the account.
Once the registration dialog is complete, the user can access the protected
resources of the site. In the future, client certificates will replace the identity and
password elements of the registration to improve the accountability of the authenti-
cation. This transition will also relieve users from the risks they assume when they
reuse a single password with multiple vendors as their own form of single signon.
Mechanisms to support auto-registration are not specified by the J2EE platform and
are thus specific to the container implementation.
Web resources that provide the user interface for auto-registration must be
protected. This is accomplished by setting the transport-guarantee of these
resources to CONFIDENTIAL.
9.2.5 Exposing Authentication Boundaries with References
The Application Component Provider is responsible for declaring references made
by each component to other J2EE components and to external resources. These dec-
larations are made in the deployment descriptor. In addition to their role in locating
services, such declarations serve to inform the Deployer of all the places in the
application where authentication may be necessary. Enterprise bean references are
declared using ejb-ref elements. Enterprise information system references are
declared with resource-ref elements. In both cases, the declarations are made in
the scope of the calling component, and the collection of declared references serves
to expose the application’s inter-component/resource call tree.
9.3 Authorization
Authorization mechanisms limit interactions with resources to collections of users
or systems for the purpose of enforcing integrity, confidentiality, or availability
constraints. Such mechanisms allow only authentic caller identities to access com-
ponents. Mechanisms provided by the J2SE platform can be used to control access
CHAPTER 9 SECURITY226
to code based on identity properties, such as the location and signer of the calling
code. In the J2EE distributed component programming model, additional authoriza-
tion mechanisms are required to limit access to called components based on who is
using the calling code. As mentioned in the section on authentication, caller identity
can be established by selecting from the set of authentication contexts available to
the calling code. Alternatively, the caller may propagate the identity of its caller,
select an arbitrary identity, or make the call anonymously.
In all cases, a credential is made available to the called component. The cre-
dential contains information describing the caller through its identity attributes. In
the case of anonymous callers, a special credential is used. These attributes
uniquely identify the caller in the context of the authority that issued the creden-
tial. Depending on the type of credential, it may also contain other attributes
which define shared authorization properties (for example, group memberships)
that distinguish collections of related credentials. The identity attributes and
shared authorization attributes appearing in the credential are referred to together
as the caller’s security attributes. In the J2SE platform, the identity attributes of
the code used by the caller may also be included in the caller’s security attributes.
Access to the called component is determined by comparing the caller’s security
attributes with those required to access the called component.
In the J2EE architecture, a container serves as an authorization boundary
between callers and the components it hosts. The authorization boundary exists
inside the container’s authentication boundary, so that authorization is considered
in the context of successful authentication. For inbound calls, the container com-
pares security attributes from the caller’s credential with the access control rules
for the target component. If the rules are satisfied, the call is allowed. Otherwise,
the call is rejected.
There are two fundamental approaches to defining access control rules: capabil-
ities and permissions. The capabilities approach focuses on what a caller can do.
The permissions approach focuses on who can do something. The J2EE application
programming model focuses on permissions. In the J2EE architecture, the job of the
Deployer is to map the permission model of the application to the capabilities of
users in the operational environment.
9.3.1 Declarative Authorization
The container-enforced access control rules associated with a J2EE application are
established by the Deployer. The Deployer uses a deployment tool to map an appli-
cation permission model (typically) supplied by the Application Assembler to
AUTHORIZATION 227
policy and mechanisms that are specific to the operational environment. The appli-
cation permission model is contained in a deployment descriptor.
The deployment descriptor defines logical privileges called security roles and
associates them with components to define the privileges required to be granted
permission to access components. The Deployer assigns these logical privileges to
specific callers to establish the capabilities of users in the runtime environment.
Callers are assigned logical privileges based on the values of their security
attributes. For example, a Deployer might map a security role to a security group
in the operational environment such that any caller whose security attributes indi-
cate that it is a member of the group would be assigned the privilege represented
by the role. As another example, a Deployer might map a security role to a list
containing one or more principal identities in the operational environment such
that a caller authenticated as one of these identities would be assigned the privi-
lege represented by the role.
The EJB container grants permission to access a method only to callers that
have at least one of the privileges associated with the method. Security roles also
protect Web resource collections, that is, a URL pattern and an associated HTTP
method, such as GET. The Web container enforces authorization requirements
similar to those for an EJB container. When a resource has no associated security
role, permission to access the resource will be granted to all.
In both tiers, access control policy is defined at deployment time, rather than
application development. The Deployer can modify the policy provided by the
Application Assembler. The Deployer refines the privileges required to access the
components, and defines the correspondence between the security attributes pre-
sented by callers and the container privileges. In any container, the mapping from
security attributes to privileges is scoped to the application, so that the mapping
applied to the components of one application may be different from that of
another application.
9.3.2 Programmatic Authorization
A J2EE container makes access control decisions before dispatching method calls to
a component. As a result, the logic or state of a component doesn’t affect the access
decisions. However, a component can use two methods, EJBContext.isCallerIn-
Role (for use by enterprise bean code) and HttpServletRequest.isUserInRole (for
use by Web components), to perform finer-grained access control. A component
uses these methods to determine whether a caller has been granted a privilege
CHAPTER 9 SECURITY228
selected by the component based on the parameters of the call, the internal state of
the component, or other factors such as the time of the call.
The Application Component Provider of a component that calls one of these
functions must declare the complete set of distinct roleName values used in all of
its calls. These declarations appear in the deployment descriptor as security-
role-ref elements. Each security-role-ref element links a privilege name
embedded in the application as a roleName to a security role. It is ultimately the
Deployer who establishes the link between the privilege names embedded in the
application and the security roles defined in the deployment descriptor. The link
between privilege names and security roles may differ for components in the same
application.
9.3.3 Declarative Versus Programmatic Authorization
There is a trade-off between the external access control policy configured by the
Deployer and the internal policy embedded in the application by the Component
Provider. The former is more flexible after the application has been written. The
latter provides more flexibility, in the form of functionality, while the application is
being written. The former is transparent and completely comprehensible. The latter
is buried in the application such that it may only be completely understood by the
those who developed the application. These trade-offs should be considered in
choosing the authorization model for particular components and methods.
9.3.4 Isolation
When designing the access control rules for protected resources, take care to ensure
that the authorization policy is consistently enforced across all the paths by which
the resource may be accessed. When method-level access control rules are applied
to a component, care must be taken that a less protected method does not serve to
undermine the policy enforced by a more rigorously protected method. Such consid-
erations are most significant when component state is shared by disparately pro-
tected methods. The simplifying rule of thumb is to apply the same access control
rules to all the methods of a component, and to partition an application as necessary
to enforce this guideline unless there’s some specific need to architect an application
otherwise.
AUTHORIZATION 229
9.3.5 Identity Selection
When setting an application’s access control policy, the Application Component
Provider bases policy decisions on assumptions about the call identities selected by
the application callers. When a call passes through intermediary components, the
caller identity at the destination component may depend on the identity selection
decisions made by the intermediaries. The destination component may assume that
caller identities have been propagated along the call chain such that the identity of
its caller will be that of the caller who initiated the chain. In other cases, the called
component must assume that one or more of the callers in its call path will employ
an identity selection policy other than identity propagation. The Application Assem-
bler is responsible for communicating these assumptions to the Deployer, while the
Deployer configures the caller identity selection for inter-component calls. Unless
the Deployer has other instructions from the Application Assembler, they should
assume that each caller will propagate the identity of the caller’s identity.
9.3.6 Encapsulation for Access Control
The component model of an application may be used to impose authorization
boundaries around what might otherwise be unprotected resources. This can be
done by using accessor components to implement the authorization barrier. If acces-
sor components are used to create an authorization boundary, access control can
either be done externally by the container, or internally by the component, or both.
An accessor component may encapsulate the mapping to an authentication
context suitable for interacting with an external resource. Considered in the
context of principal mapping for the purpose of authenticating and gaining access
to enterprise information system resources, encapsulation for access control can
be used to control who is authorized to access a mapping. Depending on the form
of the mapping, the authorization rules may be more or less complex. For exam-
ple, if all access to a resource is performed via a single conceptually omnipotent
enterprise information system tier identity, then the J2EE application can imple-
ment secure access to the resource by limiting who can access the accessor. If the
mapping of authentication context is many-to-many, then the authorization config-
uration of the accessor may need to define which of a collection of mappings are
accessible to the caller, and which should be assumed by default (if the caller does
not assert which mapping it requires).
CHAPTER 9 SECURITY230
9.3.7 Controlling Access to J2EE Resources
In a typical J2EE application, a client would go through its container to interact with
enterprise resources in the Web or EJB tiers. Resources available to the user may be
protected or unprotected. Protected resources are distinguished by the presence of
authorization rules defined in deployment descriptors that restrict access to some
subset of non-anonymous identities. To access a protected resource, a user must
present a non-anonymous credential such that its identity can be evaluated against
the resource authorization policy. In other words, caller authentication is required
any time a caller tries to access a protected component.
9.3.7.1 Controlling Access to Web Resources
To control access to a Web resource, an Application Component Provider or Appli-
cation Assembler specifies a security-constraint element with an auth-con-
straint subelement in the Web deployment descriptor. Code Example 9.5
illustrates the definition of a protected resource in a Web component deployment
descriptor. The descriptor specifies that the URL /control/placeorder can only be
accessed by users acting in the role of customer.
placeorder
/control/placeorder
POST
GET
customer
Code Example 9.5 Web Resource Authorization Configuration
9.3.7.2 Controlling Access to Enterprise Beans
An Application Component Provider or Application Assembler that has defined
security roles for an enterprise bean can also specify the methods of the remote and
home interface that each security role is allowed to invoke. This is done in the form
AUTHORIZATION 231
of method-permission elements. Ultimately, it is the assignment of users to roles
that determines if a resource is protected. When the roles required to access the
enterprise bean are assigned only to authenticated users, the bean is protected.
Code Example 9.6 contains two styles of method specifications. The first
refers to all of the remote and home interface methods of an enterprise bean. The
second is used for referring to a specific method of the remote or home interface
of an enterprise bean. If there are multiple methods with the same overloaded
name, this style refers to all of the overloaded methods. Method specifications can
be further qualified with parameter names for methods with an overloaded name.
admin
TheOrder
*
customer
TheOrder
getDetails
...
Code Example 9.6 Enterprise Bean Authorization Configuration
9.3.7.3 Unprotected Resources
Many applications feature unprotected Web-tier content, available to any caller
without authentication. Some applications also feature unprotected enterprise beans.
For example, the sample application (see Section 10.11 on page 301) allows anony-
mous, unauthenticated users to access certain EJB resources. In either tier, unpro-
tected resources are characterized by the absence of a requirement that their caller
be authenticated. In the Web tier, unrestricted access is provided simply by leaving
CHAPTER 9 SECURITY232
out an authentication rule. In the EJB tier, unrestricted access is accomplished by
mapping at least one role which is permitted access to the resource to the universal
set of users independent of authentication.
9.3.8 Example
To understand how each application, and each component within an application can
apply its own authorization requirements, consider the following examples.
One application is assembled from two enterprise beans, EJB 1 and EJB 2,
each with one method. Each method calls isCallerInRole with the role name
MANAGER. The deployment descriptor includes a security-role-ref element for
the call to isCallerInRole in each enterprise bean. The security-role-ref for
EJB 1 links MANAGER to the role good-managers and the security-role-ref
element for EJB 2 links MANAGER to the role bad-managers. The deployment
descriptor defines two method-permission elements, one establishes that the role
employees can access all methods of EJB 1 and the other does the same for EJB 2.
The deployment descriptor has 3 security-role elements: employees, good-man-
agers, and bad-managers. The Deployer assigns User 1 to roles employees and
good-managers and assigns User 2 to roles employees and bad-managers.
A second application, with one enterprise bean EJB 3, is also deployed in the
container. EJB 3 also makes a call to isCallerInRole with the role name MANAGER.
The deployment descriptor for this second application contains a security-role-
ref element that links MANAGER to the role good-managers. Similarly, the deploy-
ment descriptor defines one method-permission element that establishes that the
role employees can access all the methods of EJB 3. The deployment descriptor
has 2 role elements, employees and good-managers. The Deployer assigns User 2
to roles employees and good-managers.
Figure 9.4 illustrates the configuration of method permissions as a relation-
ship between roles and methods. It also illustrates the mapping of caller security
attributes to roles, and the link between privilege names embedded in the applica-
tion and roles.
Table 9.1 lists the authorization decisions that occur when different users ini-
tiate method calls on these enterprise beans. For example, when User 1 initiates a
method call on EJB 2’s method, the container dispatches the call because the
method-permission element specifies the security roles employees and good-man-
agers, and the Deployer has assigned User 1 to the former security role.However,
the isCallerInRole(MANAGER) method returns false, because the security-role-
ref element for EJB 2 links MANAGER to the security role bad-managers, which is
AUTHORIZATION 233
not satisfied for User 1. When User 1 invokes a method on EJB 3, the call isn’t
even dispatched, because User 1 isn’t assigned to any security roles.
Figure 9.4 Authorization Scenario
Table 9.1 Authorization Decisions
Call Call Dispatched? isCallerInRole?
User 1 - EJB 1 yes true
User 1 - EJB 2 yes false
User 1 - EJB 3 no never called
User 2 - EJB 1 yes false
CHAPTER 9 SECURITY234
9.4 Protecting Messages
In a distributed computing system, a significant amount of information is transmit-
ted through networks in the form of messages. Message content is subject to three
main types of attacks. Messages might be intercepted and modified for the purpose
of changing the affects they have on their recipients. Messages might be captured
and reused one or more times for the benefit of another party. Messages might be
monitored by an eavesdropper in an effort to capture information that would not oth-
erwise be available. Such attacks can be minimized by using integrity and confiden-
tiality mechanisms.
9.4.1 Integrity Mechanisms
Integrity mechanisms ensure that communication between entities is not being tam-
pered with by another party, especially one that can intercept and modify their com-
munications. Integrity mechanisms can also be used to ensure that messages can
only be used once.
Message integrity is ensured by attaching a message signature to a message.
The message signature is calculated by using a one-way hash algorithm to convert
the message contents into a typically smaller, fixed length message digest that is
then signed (that is, cryptographically enciphered, typically using a public key
mechanism). A message signature ensures that modification of the message by
anyone other than the caller will be detectable by the receiver. Although there are
always things a sender can do (including publishing its private authentication
keys), to compromise a receiver’s ability to hold it accountable for a received mes-
sage, both parties to the communication would be wise to select an integrity
mechanism that appends a message confounder (typically a sequence number and
a timestamp) to the message before the digest. The purpose of the confounder is to
make the message authenticator useful only once. This prevents a malicious recip-
ient from claiming that it received a message more times than it did or from
User 2 - EJB 2 yes true
User 2 - EJB 3 yes true
Table 9.1 Authorization Decisions (continued)
Call Call Dispatched? isCallerInRole?
PROTECTING MESSAGES 235
reusing an intercepted message for its own purpose. In exchange for these
receiver-side limitations, a measure of accountability is transferred to the sender.
In the J2EE architecture, a container serves as an authentication boundary
between callers and the components it hosts. Information may flow in both direc-
tions on a call (that is, a call may have input, output, or input and output parame-
ters). The Deployer is responsible for configuring containers to safeguard
interactions between components. A Deployer must configure the containers
involved in a call to implement integrity mechanisms either because the call will
traverse open or unprotected networks, or because the call will be made between
components that do not trust each other. The latter is necessary to ensure that mes-
sages can only be used once, and to reduce the plausibility of arguments made by
either of the communicants that they did not send the messages claimed to have
been received. When integrity mechanisms are configured by the Deployer, the
calling container must compute and attach a message signature to the call request,
and verify the correspondence between the call response and the message signa-
ture attached to the call response. The called container must verify the correspon-
dence between the call request and the attached message signature, and compute
and attach a message signature to the call response. If either of the verifications
fails, the call should be abandoned, and the caller notified (for example, by excep-
tion) of the failure.
The performance cost associated with applying integrity protection to all
message communication is as much a property of the operational environment as
it is a consequence of the cost of the protection. One way to safeguard the integ-
rity of application messages without unnecessarily limiting the space of opera-
tional environments, is to capture application-specific knowledge identifying
which messages must be integrity protected. The place to capture this information
is in the application’s deployment descriptor.
9.4.2 Confidentiality Mechanisms
Confidentiality mechanisms ensure that communication between entities is kept pri-
vate. Privacy is achieved by encrypting the message contents. Because symmetric
(that is, shared secret) encryption mechanisms are generally much less expensive (in
terms of compute resources) than are asymmetric (that is, public key) mechanisms,
it is quite common for an asymmetric mechanism to be used to secure the exchange
of a symmetric encryption key, which is then used to encrypt the message contents.
The Deployer is responsible for configuring containers to apply confidential-
ity mechanisms to ensure that sensitive information is not disclosed to third par-
CHAPTER 9 SECURITY236
ties. Despite the improved performance of the shared secret mechanisms, the costs
of message encryption are significant, and should be expected to have an adverse
effect on performance when confidentiality mechanisms are applied where they
are not needed. The Application Assembler should supply the Deployer with
information on which method calls of which components feature parameters or
return values that should be protected for confidentiality. The Deployer then must
configure the containers involved in a call to employ a confidentiality mechanism
whenever one of the method calls identified by the Application Assembler will
traverse open or unprotected networks. In addition to applying confidentiality
mechanisms where appropriate, the Deployer should configure containers to reject
call requests or responses with message content that should be protected but isn’t
protected. Message integrity is typically verified as a side effect of confidentiality.
9.4.3 Identifying Sensitive Components
We recommend that the Application Assembler identify the components whose
method calls feature parameters or return values that should be protected for integ-
rity and/or confidentiality. The deployment descriptor is used to convey this infor-
mation. For enterprise beans, this would be done in a description subelement
(most likely of a method-permission element). For servlets and JSP pages, this
would be done in the transport-guarantee subelement of the user-data-con-
straint subelement of a security-constraint. In cases where a component’s
interactions with an external resource are known to carry sensitive information,
these sensitivities should be described in the description subelement of the corre-
sponding resource-ref.
9.4.4 Ensuring Confidentiality of Web Resources
In addition to understanding how to configure Web transport guarantees, it is impor-
tant to understand the properties of HTTP methods, and the effects these properties
have when a link is followed from one Web resource to another. When a resource
contains links to other resources, the nature of the links determines how the protec-
tion context of the current resource affects the protection of requests made to the
linked resources.
When a link is absolute (that is, the URL begins with https:// or http://),
the HTTP client container will ignore the context of the current resource and
access the linked resource based on the nature of the absolute URL. If the URL of
the link begins with https://, a protected transport will be established with the
AUDITING 237
server before the request is sent. If the URL of the link begins with http://, the
request will be attempted over an insecure transport. When the link is relative, the
HTTP client container will protect an access to a linked resource based on
whether the resource in which the link occurs was protected.
The application developer should consider these link properties most care-
fully when a linked request must carry confidential data back to the server. There
are a few choices available to ensure security in such cases. For example, an appli-
cation developer might choose to use secure absolute links to ensure the transport
protection of requests that carry confidential data. This would solve the security
problem, at the expense of constraining the application to a very specific naming
environment.
Another option, assuming that an application opts for portability and uses rel-
ative links, is for the Deployer to configure the application so that wherever there
is a confidential interaction from one resource to another, both are deployed with a
confidential transport guarantee. This approach will ensure that an HTTP client
container will not send a request to a protected resource without protecting it.
As a related point, the POST method is favored over the GET method for deliver-
ing confidential request data, since data sent via GET appears in both client- and
server-side logs.
9.5 Auditing
Auditing is the practice of capturing a record of security-related events for the
purpose of being able to hold users or systems accountable for their actions. A
common misunderstanding of the value of auditing is evident when auditing is used
solely to determine whether security mechanisms are serving to limit access to a
system. When security is breached, it is usually much more important to know who
has been allowed access than who has not. Only by knowing who has interacted
with the system do we have a chance of determining who should be held account-
able for a breach of security. Moreover, auditing can only be used to evaluate the
effective security of a system when there is a clear understanding of what is audited
and what is not.
The Deployer is responsible for configuring the security mechanisms that will
be applied by the enterprise containers. Each of the configured mechanisms may
be thought of as a constraint that the containers will attempt to enforce on interac-
tions between components. It should be possible for the Deployer or System
Administrator to review the security constraints established for the platform, and
CHAPTER 9 SECURITY238
to associate an audit behavior with each constraint so that the container will audit
one of the following:
• All evaluations where the constraint was satisfied
• All evaluations where it was not satisfied
• All evaluations independent of outcome
• No evaluations
It would also be prudent to audit all changes (resulting from deployment or
subsequent administration) to the audit configuration or the constraints being
enforced by the platform. Audit records must be protected so that attackers cannot
escape accountability for their actions by expunging incriminating records or
changing their content.
The J2EE programming model aims to shift the burden of auditing away from
developers and integrators to those who are responsible for application deploy-
ment and management. Therefore, although not currently mandated by the J2EE
specification, we recommend that J2EE containers provide auditing functionality
that facilitates the evaluation of container-enforced security policy.
9.6 Summary
A primary goal of the J2EE platform is to relieve the application developer from the
details of security mechanisms and facilitate the secure deployment of an applica-
tion in diverse environments. The J2EE platform addresses this goal by defining a
clear separation of responsibility between those who develop application compo-
nents, those who assemble components into applications, and those who configure
applications for use in a specific environment. By allowing the Component Provider
and Application Assembler to specify which parts of an application require security,
then letting the Deployer select the specific security mechanisms used for that pro-
tection at deployment time, deployment descriptors provide a means outside of code
for the developer to communicate these needs to the Deployer. They also enable
container-specific tools to give the Deployer easier ways to engage the security con-
straints recommended by the developer.
SUMMARY 239
An Application Component Provider identifies all of the security dependen-
cies embedded in a component including:
• The names of all the role names used by the component in calls to IsCaller-
InRole or isUserInRole
• References to all of the external resources accessed by the component
• References to all the inter-component calls made by the component
An Application Component Provider may also provide a method permission
model, along with information that identifies the sensitivity with respect to
privacy of the information exchanged in particular calls.
An Application Assembler combines one or more components into an appli-
cation package and then rationalizes the external view of security provided by the
individual components to produce a consistent security view for the application as
a whole. The objective of the Application Assembler is to provide this information
so that it can inform the actions of a Deployer.
A Deployer is responsible for taking the security view of the application pro-
vided by the Application Assembler and using it to secure the application in a spe-
cific operational environment. The Deployer uses a platform-specific deployment
tool to map the view provided by the assembler to the policies and mechanisms
that are specific to the operational environment. The security mechanisms config-
ured by the Deployer are implemented by containers on behalf of the components
hosted in the containers.
J2EE security mechanisms combine the concepts of container hosting, plus
the declarative specification of application security requirements, with the avail-
ability of application-embedded mechanisms. This provides a powerful model for
secure, interoperable, distributed component computing.
About the Author
STEPHANIE BODOFF is a staff writer at Sun Microsystems. She has been involved
with object-oriented enterprise software since graduating from Columbia University
with an M.S. in electrical engineering. For several years she worked as a software engi-
neer on distributed computing and telecommunications systems and object-oriented
software development methods. During that period she co-authored Object-Oriented
Software Development: The Fusion Method, Prentice Hall. For the past 4 years
Stephanie has concentrated on technical writing, documenting object-oriented data-
bases, application servers, and enterprise application development methods.
ABHISHEK CHAUHAN has been working on the design of scalable network services
and distributed programs. At Sun Microsystems, Abhishek was involved in the evolution
of the J2EE programming model from its inception. He pioneered work on Web access
optimization techniques and implementation of the Java Web Server. He worked on the
JavaServer Pages specification and Sun’s JavaServer Pages implementations.
Abhishek was one of the founders and a lead architect at Vxtreme, where he
worked on the design of its streaming server. Vxtreme was acquired by Microsoft in
1997. In a former life, Abhishek worked at Microsoft on the Office Visual Basic
scripting engine. He has an M.S. from the University of Wisconsin at Madison and a
Bachelor’s degree from the Indian Institute of Technology at Delhi.
241
C H A P T E R 10
The Sample Application
by Stephanie Bodoff
and Abhishek Chauhan
TO conclude this discussion of the J2EE programming model, this chapter pro-
vides an in-depth description of a multitier Web application, an e-commerce Web
site. We review the entire process of developing this application from specification
to design to implementation, illustrating many of the principles discussed in the
earlier chapters.
The first section describes some scenarios in which the sample application is
used. Although the sample application supports administration and business-to-
business interactions as well as shopping interactions, this chapter focuses mainly
on shopping interactions.
The discussion then turns to the architecture of the sample application: the
partitioning of functionality into modules, the assignment of functionality to tiers,
and object decomposition within tiers. The architecture of the sample application
conforms to the Model-View-Controller architecture. We describe the motivation
for using this architecture and how each of these concepts is realized in the imple-
mentation of the sample application.
Finally, this chapter describes how the sample application uses the deploy-
ment, transaction, and security capabilities of the J2EE platform to simplify com-
ponent development and provide richer functionality.
10.1 Application Functionality
The sample application models a typical e-commerce application, an online pet
store. E-commerce sites like this are among the most common Web applications.
CHAPTER 10 THE SAMPLE APPLICATION242
The application interface is presented to its customers through a Web site and a cus-
tomer interacts with the application using a Web browser. Other potential users of
the application include administrators responsible for maintaining inventory and
performing other managerial tasks, and associated businesses such as suppliers.
Each class of users would have access to specific categories of functionality, and
each would interact with it through a specific user interface mechanism.
Like a typical e-commerce site, the pet store presents the customer with a
catalog of products. The customer selects items of interest and places them in a
shopping cart. When the customer has selected the desired items and indicates
readiness to buy what is in the shopping cart, the sample application displays a bill
of sale: a list of all selected items, a quantity for each item, the price of each item,
and the total cost. The customer can revise or cancel the order. When the customer
is ready to accept the order, the customer provides a credit card number to cover
the costs and supplies a shipping address.
10.1.1 Scenarios
The following scenarios demonstrate a few key ways the pet store application could
be used by describing a user’s view of interactions with the system. By walking
through these scenarios, you’ll gain a better understanding of the requirements as
well as the interactions that happen within the system.
The sample application could support three very different kind of scenarios.
First, there is the shopping interface described earlier, that allows shoppers to buy
items online. Second, there is an administration interface for carrying out store
administration activities. Finally, there is a business-to-business interface through
which the store can interact with suppliers. The scenarios in this section demon-
strate all three types of interaction, while the remainder of this chapter focuses
mainly on the shopping interactions.
10.1.1.1 Shopping Scenario
The primary function of the sample application is to provide an interface where cus-
tomers can browse through and purchase items. This shopping interaction typically
APPLICATION FUNCTIONALITY 243
starts with the customer’s visit to the application home page and ends when the cus-
tomer orders from the site:
1. A customer connects to the application, by pointing the browser to the URL for
the application’s home page. This allows the customer to browse through the
catalog or search for products through some search interface.
2. At any point during the whole interaction, the customer can sign into the appli-
cation by providing an account identifier and a password. When the customer
signs in, the application can recall information about the customer such as a
preferred shipping address and billing information, buying preferences, and so
on. Customers who don’t have an account can create one at any time by pro-
viding an account identifier, customer name, password and some other person-
al details.
3. The customer browses through the catalog. The customer can select a category
to see a list of all the products in that category. For example, the customer can
select the category Cats to view all cats that the pet store sells. Alternatively,
the customer can search for products using one or more keywords describing
the product. For example searching with keywords Persian and mammal might
bring a list of Persian dogs and cats.
4. The customer selects a particular product in the list. Now, the application dis-
plays detailed information about the selected product. The description and im-
age of the product is shown along with pricing information. When there are
several variants of the same product, each variant is shown as a separate item.
For example, when showing details about an African parakeet, the items could
be large male African parakeet, small female African parakeet, and so on.
5. The customer decides to purchase a particular item and clicks a button to add
the item to the shopping cart. The customer may continue shopping, adding
more items to the shopping cart. As the customer browses through the catalog,
the application remembers all the items placed in the cart. The customer can
recall the shopping cart at any time during the interaction to review or revise
the contents of the cart.
6. The customer can choose to order the items in the shopping cart at any time.
This is called checking out. A checkout button is presented along with the
shopping cart. If the customer is not signed in, the application brings up a sig-
nin/signup screen. Here the customer can sign in, or set up a new account, if
they don’t have one. After the customer is signed in, order processing contin-
ues as before.
7. When the customer asks to check out, the application presents a summary of
CHAPTER 10 THE SAMPLE APPLICATION244
all items that would be ordered along with their costs. At this point the custom-
er must confirm the order.
8. When the customer confirms the order, the application begins to gather ship-
ping and billing information for the order. First it presents a form, where the
customer can enter shipping information. If the customer is signed into the ap-
plication at this time, the form comes up filled in with the customer’s preferred
shipping address.
9. When the customer enters the shipping address, the customer is asked to enter
billing information, including credit card details and a billing address. If the
customer is signed in, the application recalls these details and the forms are re-
turned filled in.
10. Finally the customer confirms the order and the application accepts the order
for delivery. A receipt including a unique order number and other order details
is presented to the customer. The application validates credit card and other in-
formation, updates its inventory database, and optionally sends a confirmation
message via email.
This is a fairly typical shopping scenario. Some variations are possible, espe-
cially in the way the catalog is presented to the customer. For instance, the appli-
cation could provide specialized lists of items such as best-sellers, or discounts on
certain items. There may also be variations in order processing, such as reducing
the steps for making an order when the customer is already signed in. The applica-
tion developer needs to design the application to support these variations, as well
as others that might arise as the application evolves.
Although this scenario presents the application from a single customer’s point
of view, the pet store application needs to simultaneously support a large number
of shoppers.
10.1.1.2 Administration Scenario
The pet store application does most of the administrative work of managing orders,
creating new accounts, and other details without manual intervention. However,
there are some tasks where manual intervention is desirable or required. These are
often administration tasks, such as managing the inventory, reestablishing forgotten
customer passwords, rolling back orders, handling returned merchandise, and pro-
cessing and shipping of orders.
The administration interface of the pet store application could use a Visual
Basic client running in a Microsoft desktop application such as Microsoft Excel.
APPLICATION FUNCTIONALITY 245
The application must be designed to support more than one administrator simulta-
neously using the administration interface.
The administration scenario models inventory management, where an admin-
istrator updates inventory when new shipments come in:
1. The administrator starts up the shopping client application. When the client
starts, it asks the administrator to sign on to the system using a user name and
password. The administrator enters information for one of the accounts that has
administration privileges.
2. The client application then presents a list of products in the catalog, perhaps in
order by category, with the product details such as description and name also
shown.
3. The administrator clicks a product to see the items as well as their inventory
status. For any item displayed, the administrator can modify the inventory sta-
tus.
4. The administrator clicks an update button, causing the changes to inventory
status to be committed to the inventory database.
10.1.1.3 Business-to-Business Scenario
Businesses often have a need to interact with other businesses through their custom
applications. For example, a retailer needs to work with suppliers to procure inven-
tory, with shipping agencies for managing shipments, and with billing agencies for
handling its billing needs. In fact, significant pieces of the application such as inven-
tory control could themselves be off-loaded to a separate business.
It would be desirable to have some of these interactions be automated. When
businesses are tightly coordinated, perhaps under the same ownership or adminis-
tration, these interactions could be closely-coupled. In such interactions, busi-
nesses expose their entities and data to each other. However, most of the time it is
desirable to keep the businesses loosely-coupled. Here businesses interact by
passing asynchronous messages to each other. This messaging approach also
models the real world more closely, where businesses work together by sending
faxes and packages, and so on, to each other.
CHAPTER 10 THE SAMPLE APPLICATION246
An interaction between the pet store and one of its suppliers would illustrate a
loosely-coupled business interaction. A typical scenario might be:
1. A customer places an order. This causes the inventory to fall below a pre-es-
tablished low water mark, triggering the application to initiate an order to ob-
tain more items from the supplier. This process happens asynchronously and
does not interfere with the transaction being performed by the customer.
2. The application sends a purchase request message to the supplier. A typical
purchase request message could say, “Send 100 male African parakeets.”
3. At some later time, the supplier sends a message in response to the request. If
the supplier does not have enough parakeets to fill the order, the message might
say, “Can’t fulfill request. Have 20 parakeets available.”
4. The application, upon receipt of the message, might send another request for a
smaller quantity. The message might say, “Send 20 male African parakeets.”
5. The supplier initiates delivery of the shipment, and sends a message back to
the application. This message might say, “Request completed. 20 parakeets
shipped. Shipment number is 1234.”
The interaction between the store and supplier is depicted in a timing diagram
in Figure 10.1.
Figure 10.1 A Store-Supplier Business-to-Business Interaction
APPLICATION FUNCTIONALITY 247
One thing to observe about this scenario that it is asynchronous. The action is
initiated when a customer places an order. However, it proceeds without blocking
the customer’s interaction. Also note that neither the store nor the supplier is
blocked waiting for the other to respond. While the procurement is in progress,
the store’s application and the supplier’s system carry on with their activities as
usual.
10.1.2 Functional Specification
With a clear understanding of the kind of scenarios in which the application would
be used, let’s create an initial specification of the user interface of the application.
This section presents a sketch of the main user interface of an application that sup-
ports the shopping interactions. It is possible to create a similar sketch for a user
interface for administration interactions. Business interactions typically do not
require a user interface. As mentioned earlier, the remainder of this chapter focuses
on the shopping functionality of the application.
Upon arriving at the main page of the online pet store, a customer would
expect some of the following features:
• A set of links or navigation bars on each page that provide quick access to com-
mon navigational tasks.
• An organized view of the site’s contents through a categorized catalog.
• A search mechanism to provide a way to locate items based on keyword de-
scriptions. Other types of quick access could be in terms of popular items or
new additions.
• A master view of the catalog that lists items of interest. This could be the result
of the customer navigating through a catalog category or the outcome of a key-
word search.
• A detail view that describes the details of a particular item. Shoppers click on
an item in the master view to zoom in on details, including a description, a pic-
ture, the price, a link to the supplier’s URL, and so on.
• A shopping cart view that lets customers review the contents of their shopping
cart. The cart allows the customer to modify quantities of items in the cart, in-
cluding removing items from the cart altogether.
• A checkout or bill-of-sales view that displays the total order cost and allows
the customer to enter billing and shipping information. The customer will want
CHAPTER 10 THE SAMPLE APPLICATION248
assurance that order details including shipping and credit card information are
transferred securely and accountably. The interaction must be authenticated to
positively identify the customer for the purposes of accountability and encrypt-
ed through HTTPS to protect the privacy of the information the customer pro-
vides.
• A receipt view to provide confirmation of the purchase through a unique order
identifier or other mechanism to track the newly placed order and review de-
tails of the order.
In addition to these user interface requirements, the application must also
support some security requirements. We address these in Section 10.11 on
page 301.
10.2 Application Architecture
This section describes the architecture of the pet store application; exploring the par-
titioning of functionality into modules, the assignment of functionality to tiers, and
object decomposition within the tiers.
10.2.1 Application Modules
This discussion reviews the shopping interaction scenario once again, this time iden-
tifying actions within the application as it runs on the server. This replay is used to
explore ways to divide the application into modules based on similar or related func-
tionality. Dividing the problem in this manner reduces the dependency between
modules, allowing them to be developed somewhat independently. Identifying the
interface between modules enables some of the modules to be provided by third-
party component providers, or subcontracted to specialists in a particular area of
functionality.
Here’s the scenario once again, with the various behaviors organized by mod-
ules:
1. A user connects to the application. If the user logs in, the user account module
maintains user account information. It creates new user accounts and manages
these accounts. Accounts include such information as user name, password,
and account ID.
2. The product catalog module returns a list of products. The product catalog
APPLICATION ARCHITECTURE 249
module searches the product database for a list of possible matches to the
search criteria and renders the products for the user.
3. The user views a specific product. The product catalog module also returns de-
tailed information about the selected product, including pricing information. It
optionally can check the inventory module for availability information, such as
quantity in stock.
4. The user selects an item for purchase. The shopping client module creates a
shopping cart for the user for the duration of the user’s session.
5. The user chooses the checkout option and commits to buying the item. The or-
der processing module manages this interaction.
6. The application determines whether the user is logged in and if not, calls the
user account module to set up a new user account. Otherwise it instructs the
user account module to extract account information such as credit card and
shipping information.
7. The application then authenticates the user and validates the credit card and
shipping information.
8. The application lets the user revise or cancel the order. If the user accepts the
order, the order processing logic logs the order, notifies the inventory module
to update the inventory database, and sends a confirmation message by email.
This time, the run-through of the scenario has identified the following
modules and their responsibilities:
• User account module: The application tracks user account information. This
includes a user identifier and password and various types (billing and email ad-
dresses, phone number, and so on) of contact information. The application
saves user account information to a database so that it spans sessions.
• Product catalog module: The application allows the user to search for products
or services and be able to display details of individual products. The product
catalog includes descriptions of individual items.
• Order processing module: The application performs order processing. Order
processing occurs when the user performs the check-out process and buys the
items in the shopping cart.
• Messaging module: The application sends confirmation messages.
• Inventory module: The application maintains information on the number of
CHAPTER 10 THE SAMPLE APPLICATION250
each type of product in stock.
• Control module: The application allows users to browse the product catalog
and add selected items to a shopping cart. At any time, the user can modify
items in the shopping cart, add new items, or remove items already placed in
the cart.
Figure 10.2 shows the interrelationship of the modules in the sample applica-
tion.
Figure 10.2 Functional Modules for the Sample Application
This modular decomposition of the pet store application is reflected in the subpack-
ages of the sample application’s top-level package com.sun.estore:
• account: user account
• cart: shopping cart
• catalog: product catalog
• control: controls
APPLICATION ARCHITECTURE 251
• inventory: product inventory
• mail: email messaging
• order: order processing
• util: utility classes
10.2.2 Application Design
Partitioning the application into logical modules is the first step in subdividing the
overall problem. The next step is to begin the process of object-oriented design of
the application, identifying units of business logic, data, and presentation logic and
modeling each of them as a software object.
The process starts by identifying the options and approaches available at the
highest level. Once these choices are clear and the decisions and design principles
are established, the rest of the design will be simplified by leveraging these overall
principles.
One of the first decisions to make concerns the tiers that the application uses.
The J2EE platform is designed for multitier applications, and offers a lot of flexi-
bility in choosing how to distribute application functionality across the tiers. In a
Web-enabled application, such as the sample application, some tiers are always
present: the client tier provided by the browser, the Web tier provided by the
server and the enterprise information system or database tier which holds persis-
tent application data. The first choice to make is whether the Web tier accesses the
enterprise information system resources directly, or goes through an EJB tier. The
decision depends on the functionality, complexity, and scalability requirements of
the application. Since such requirements can change as the application evolves,
one goal for the design is to make it amenable to migration to an EJB-centric
approach.
After deciding what tiers constitute the application, the next decision is how
to distribute application functionality across these tiers. This division is closely
linked to how the application is divided into objects at the highest level and repre-
sents one of the most important decisions when designing enterprise applications.
Some clear and simple guidelines to help with making this decision are addressed
in the following discussions.
CHAPTER 10 THE SAMPLE APPLICATION252
10.2.2.1 Application Tiers
In a Web-centric design, the Web tier communicates directly with the enterprise
information system resources that hold application data. In this approach, the Web
tier is responsible for almost all of the application functionality. It must take care of
dynamic content generation and presentation and handling of user requests. It must
implement core application functionality such as order processing and enforce busi-
ness rules defined by the application. Finally, the components running in the Web
tier must also manage transactions and connection pooling for data access. Because
it must handle so many functions, Web-centric application software has a tendency
to become monolithic. As a result, unless special efforts are taken, it does not scale
well with increasing software complexity.
In an EJB-centric design, enterprise beans running on EJB servers encapsulate
the enterprise information system resources and the core application logic. The
Web tier communicates with the EJB tier instead of directly accessing the enter-
prise information system resources. This approach moves most of the core appli-
cation functionality to the EJB tier, using the Web tier only as a front end for
receiving client Web requests and for presenting HTML responses to the client.
The principal advantage of this approach is that enterprise beans have access
to a broad set of enterprise-level services. Because of these services, managing
transaction and security aspects of the application is easier. The EJB container
provides a highly structured environment for the components that allows a devel-
oper to focus entirely on the application domain issues, while the EJB container
takes care of system-level details. These standardized container-provided services
also translate into better software reliability. The EJB architecture supports a pro-
gramming discipline that promotes encapsulation and componentization, resulting
in software that stays manageable as applications grow more complex.
The Web-centric approach is better for getting the application off to a quick
start, while EJB-centric approach becomes more desirable when building a large
scale application where code and performance scalability are prime factors. While
the Web-centric approach may be more prevalent, with many applications imple-
mented using it, it has limitations when building large scale, complex applica-
tions.
The ideal solution is an approach that benefits from the strengths of both
approaches. The sample application demonstrates an approach that started out
simple and small, but kept the option of growth open. Its extensible design started
as Web-centric and migrated to an EJB-centric architecture. While most of its
modules are implemented with an EJB-centric design, the catalog module uses the
APPLICATION ARCHITECTURE 253
Web-centric model. Strategies for migrating components from Web-centric to
EJB-centric designs are described in detail in Section 4.7.1 on page 108.
Note that the discussion that follows describes a sample application design
that evolves from Web-centric to EJB-centric. The actual code of the sample
application reflects the final result of that migration. We have preserved the state
of the catalog module before migration to provide an indication of how the migra-
tion was performed.
10.2.2.2 Application Objects
The next issue to address in developing the overall application architecture is how to
subdivide the application into objects and how to the assign these objects to tiers.
This process is referred to as object decomposition. While most of the objects are
consigned to one tier or another, there are some that serve to connect the tiers and
will need to span tiers, and their design needs to take this into account.
This discussion focuses primarily on large scale, complex applications.
Smaller applications can probably get away with less rigorous treatment, but
object design really becomes important as applications grow more complex. Large
scale development of object-oriented software requires frameworks. It is impor-
tant to have a framework, so that every time the design requires two objects to
interact, a developer does not have to come up with a whole new notion of how the
interaction works out.
This section looks at the issues to keep in mind when doing the object decom-
position, and present techniques that we used in the sample application to deter-
mine an effective decomposition.
Design Goals
Consider the kind of goals that need to be addressed in object decomposition. Each
of these considerations identifies criteria to use to divide the application. The frame-
work must enable:
• Reuse of software designs and code
• Identification of the responsibility of each object. The division into objects
must ensure that the responsibilities of each object—what the object represents
and what it must accomplish—are easily and unambiguously identified.
CHAPTER 10 THE SAMPLE APPLICATION254
While these requirements apply to object-oriented design in general, they
become even more important for multitier enterprise applications. Our additional
objectives were:
• Separate stable code from more volatile code. All parts of an enterprise appli-
cation are not equally stable. The parts that deal with presentation and user in-
terface change more often. The business rules and database schemas employed
in the application have a much lower propensity to change. The overall archi-
tecture should separate stable portions of the application from parts that are
more volatile.
• Divide development effort along skill lines. The people that comprise an enter-
prise development team typically represent a very diverse set of skills. There
are HTML layout and graphics designers, programmers, application domain
experts, and enterprise information system resource access specialists, among
others. The decomposition should result in a set of objects that can be assigned
to various subteams based on their particular skills. This division of labor al-
lows work on each object to proceed in parallel.
• Ease migration from Web-centric to EJB-centric design. As mentioned earlier,
the sample application starts out as a Web-centric application and migrates to
being EJB-centric.
We have described these considerations from the point of view of a high-level
division. However they are equally applicable even when we are working on iden-
tifying objects at a finer level. We will keep coming back to these considerations
as we need to make choices about object decomposition.
MVC Architecture
When applying the considerations discussed above to the sample application, the
first lines of division start becoming clear. At the highest level, the application
divides into three logical categories of objects. These are objects that deal with pre-
sentation aspects of the application, objects that deal with the business rules and
data, and objects that accept and interpret user requests and control the business
objects to fulfill these request.
The look and feel of the application interface changes often, its behavior
changes less frequently, and business data and rules are relatively stable. Thus
objects responsible for control are often more stable than presentation objects
while business rules and data are generally the most stable of all.
THE VIEW 255
The implementation of presentation objects is typically handled by graphics
designers, HTML and JSP technology experts, and application administrators
after the application has been deployed. Control-related objects are implemented
by application developers. Business rules and data objects are implemented by
developers, domain experts, and database experts.
The presentation logic of a user interface can be handled by the Web tier or
the client. In the Web tier, JSP pages are used to dynamically generate HTML for
consumption by a browser. A stand-alone client, such as the one described in the
administration scenario in Section 10.1.1.2 on page 244, provides its own presen-
tation. Control-related objects are present in each tier to enable coordination of
actions across tiers. Objects that model business data and rules live in the EJB tier
in an EJB-centric approach, and in the Web tier when using a Web-centric
approach.
As discussed in several chapters in this book, the MVC architecture can be
easily applied to enterprise applications. The presentation, business, and control
categories map respectively, to the view, model, and controller concepts defined in
the MVC architecture. The following sections take a detailed look at the design,
implementation, and interactions of the sample application objects that constitute
the view, model, and controller.
10.3 The View
The view determines the presentation of the user interface of an application. In the
sample application, the implementation of the view is contained completely in the
Web tier. In the sample application, three kinds of components work together to
implement the view: JSP pages, JSP custom tags, and JavaBeans components.
JSP pages are used for dynamic generation of HTML responses. Custom tags
make it easier for JSP pages to use JavaBeans components when the underlying
model is complex. Custom tags can also help encapsulate presentation logic and
make it modular and more reusable.
JavaBeans components represent the contract between JSP pages and the
model. JSP pages rely on these beans to read model data to be rendered to HTML,
while elsewhere in the system, the model and controller coordinate to keep the
JavaBeans components up to date.
This section describes the JSP pages and custom tags that implement the view.
Because the classes that implement JavaBeans components are intimately tied to
their corresponding model classes, the discussion of the implementation of Java-
CHAPTER 10 THE SAMPLE APPLICATION256
Beans components and model classes is deferred until after the discussion of the
model.
10.3.1 Shopping Interaction Interface
The shopping scenario described in Section 10.1.1.1 on page 242 and the server-side
scenario in Section 10.2.1 on page 248 provide a behavioral specification for the
shopping interaction interface. This section translates this specification into the set
of views that the customer sees when interacting with the pet store application.
10.3.1.1 Screens
The user interface for the shopping interaction consists of a set of screens. A screen
is the total content delivered to the browser when the user requests an application
URL. In other words, a screen is what customers see when they navigate to one of
our application’s URLs. A screen can be composed of several components each con-
tributing a different part of its content.
The specification includes some notion of the kind of screens the application
displays to the customer and the dialogs it carries on with them. Taking this
process further, results in the specification of a complete set of screens, each with
a unique name.The significance of the names will become clear later when the dis-
cussion turns to how the controller selects a view for each response. The following
list identifies what model information it presents and what user gestures it can
generate.
• Name: MAIN_SCREEN, DEFAULT_SCREEN
This is the home page of the application. It displays a list of all product
categories in the catalog, such as Dogs. The customer can click on any cate-
gory to browse through a master view of products that belong in that category.
• Name: CATEGORY_SCREEN
This screen displays a master view of all products that belong to a partic-
ular category. For each product it shows the product ID and its name. The cus-
tomer can click on the name of any product on display to see further details of
the product.
• Name: SEARCH_SCREEN
This screen displays the results of a search. Searching the catalog is inte-
THE VIEW 257
gral part of the application, and a search interface is displayed as part of every
page. When the customer requests a search, the results are shown using the
search screen. This screen is similar to the CATEGORY_SCREEN in that it dis-
plays a master view of the list of products that result from a search.
• Name: PRODUCT_SCREEN
This screen displays information about a particular product. Each product
can be offered for sale in several configurations. We call each of these an item.
This screen lists inventory status for each item offered. The customer can
click on any item in inventory to see further details about it.
• Name: PRODUCT_DETAILS_SCREEN
This screen displays detailed information about a particular product item,
including a description of the item and its image and the number of items in
the inventory. It also provides an Add button. Clicking this button adds the
product currently being shown to the shopping cart and displays the resulting
shopping cart.
• Name: CART_SCREEN
This screen displays the contents of the customer’s shopping cart. For
each item in the shopping cart, it includes a brief description of the item and
its quantity. The customer can change the quantity of each item and delete
items from the cart. This screen includes an update button to update the cart
according to the changes made by the customer. It also has a checkout button.
Clicking the checkout button initiates the process of placing an order.
• Name: CHECKOUT_SCREEN
This screen displays the final unmodifiable contents of the customer’s
shopping cart once again and asks the customer to confirm everything before
placing the order. A customer confirms the order by clicking the place order
button.
• Name: PLACEORDER_SCREEN
This screen displays a form where the customer can fill in details neces-
sary to place the order. A customer places the order by clicking the submit
CHAPTER 10 THE SAMPLE APPLICATION258
button.
• Name: COMMIT_ORDER_SCREEN
This screen displays the receipt after an order has been confirmed and
committed. It shows a unique order identifier so that the customer can track
the order later on. It also shows a complete list of items ordered, the total price
and shipping charges if any, as well as shipping and billing information.
• Name: SIGNIN_SCREEN
This screen displays a customer name and password, allowing the cus-
tomer to sign into the application. The submit button initiates the signin pro-
cess.
• Name: SIGNUP_SCREEN
This screen displays a form allowing a new customer to sign up and regis-
ter themselves with the application. Once registered the customer can conve-
niently recall personal information each time they place an order.
This completes the initial set of screens that are presented to the customer
during the course of a shopping interaction with the application. As the applica-
tion evolves, more screens may be added and existing screens modified.
10.3.1.2 Graphical Design
Since we already identified the major screens in the application and the data that
needs to be shown as part of each screen, we can now involve graphic design and
HTML specialists to create the layout, look, and feel of each of the screens.
There are two parts to this design: design of the custom content of each screen
and design of a common template which remains consistent with each of the
screens. The preceding scenarios have identified the data that needs to go into
each of the screens as well as the dynamic portions of the template.
The artist needs an idea of the size and shape of each of the data element that
needs to be shown in each of the screens. They can make good progress with the
graphical design at this point using storyboarding techniques, even without an
actual implementation of the rest of the application available to them. This is one
major advantage of decoupling the design of the user interface from the rest of the
application.
THE VIEW 259
The contract with the graphic design artists is just how the application makes
the model data required for each screen available to the screen. As we shall see
later in this section, this is where the JavaServer Pages technology comes into
play.
10.3.2 JSP Pages
The JSP pages provided by the pet store application use a generic template mecha-
nism and application-specific JavaBeans components. This section describes the
template mechanism and discusses several example JSP pages. The JavaBeans com-
ponents are discussed in Section 10.5 on page 278. General guidelines on how to
use JSP technology can be found in Chapter 4.
10.3.2.1 A Template Mechanism
While sketching out the shopping interaction interface of the application, it is clear
that there are elements that we want to be part of each screen. Some of these are:
• The application logo and tag line.
• The search interface with a search text field and a search button.
• A help button to get information about the application.
• A show shopping cart button that provides immediate access to the shopping
cart from any screen.
• A signin/signout status button that changes state based on whether the custom-
er is signed in. If they are signed in, they are presented with a sign out button.
If they are not signed in, they see a sign in button.
• Copyright notices and miscellaneous status information at the bottom of each
page.
Among the elements that change on each page are the body and the title.
Other elements, such as keywords and meta-headers, may also change with each
screen as well.
To add headers and footers to every JSP page, the designer could create
header and footer JSP files and have each JSP page include these at appropriate
places. Such a technique is illustrated in Code Example 10.1.
CHAPTER 10 THE SAMPLE APPLICATION260
<%@ include file="header.jsp" %>
...
content of this screen
...
<%@ include file="footer.jsp" %>
Code Example 10.1 Templating Using JSP Include Statements
However, this approach runs into several limitations if we try to make the tem-
plate more elaborate, using HTML tables, side bar, and so on. The header and
footer files would have to be constructed and formatted properly to make sure the
body appears where intended. For instance, correct HTML requires opening
HTML tags in the header and a closing HTML tag in the footer so that the body
can be enclosed between them. This requires either hand-coded HTML or special-
ized authoring tools to ensure correct design and correct HTML. The problem
becomes compounded if we want more than just one contiguous chunk of HTML
to change on each screen. For instance, each screen might want to provide its own
HTML title as well as custom content. These features require a more flexible
screen layout mechanism.
A template mechanism provides a way to separate the common elements that
are part of each screen from the elements that change with each screen. Putting all
the common elements together into one file makes it easier to maintain and
enforce a consistent look and feel in all the screens. It also makes development of
individual screens easier since the designer can focus on portions of a screen that
are specific to that screen while the template takes care of the rest.
This section reviews the design and implementation of the sample applica-
tion’s screen template mechanism. The concept of a presentation template can be
applied to almost any Web application in one form or another. The sample appli-
cation’s template mechanism is designed so that you can easily adapt it to other
applications.
The template itself is a JSP page, with place holders for the parts that need to
change with each screen. Each of these place holders is referred to as a parameter
of the template. For example, a simple template could include a title text parame-
ter for the top of the generated screen and a body parameter to refer to a JSP page
for the custom content of the screen.
Once you have a template, you can generate different presentation screens
from it simply by passing it different parameters. This process is called instantia-
THE VIEW 261
tion of the template. A specific screen is completely characterized by identifying
the template page, and the parameters to pass to the template. The set of parame-
ters that completely defines a screen is called a screen definition.While a large
application could use multiple templates; the pet store application uses a single
template for all its screens. However, the mechanism it uses is designed to support
multiple templates.
From the templating mechanism’s point of view a screen is the instantiation of
a template according to its screen definition. Figure 10.3 illustrates the relation-
ship between a template, a screen definition, and the resulting presentation screen.
Figure 10.3 Defining a Screen in Terms of a Template and Its Parameters
Code Example 10.2 shows the contents of template.jsp, the template file
used in the sample application.
<%@ page errorPage="errorpage.jsp" %>
<%@ page import="com.sun.estore.control.Web.ScreenNames" %>
<%@ taglib uri="WEB-INF/tlds/taglib.tld" prefix="j2ee" %>
<%@ include file="ScreenDefinitions.jsp" %>
<j2ee:insert template="template"
parameter="HTML Title" />
CHAPTER 10 THE SAMPLE APPLICATION262
Code Example 10.2 template.jsp
The template is instantiated by forwarding to or dynamically including the
template.jsp page. Forwarding is performed using the jsp:forward standard
action or by calling the forward method of a RequestDispatcher; inclusion is per-
formed using an include directive or standard action or by calling the include
method of a RequestDispatcher.
An appropriate screen definition must be set up in the request scope before
invoking template.jsp. JSP pages can access objects in request, session, and
application scopes. Since a screen is presented in the context of a specific URL
request from the user, the appropriate screen definition needs to be set in the
request scope before the template file is invoked. The other possible JSP scopes,
session and application, are broader—they’re more appropriate for setting general
site and user-specific portions of the template.
The following examples show how template.jsp works. It uses the
j2ee:insert custom tag to identify place holders in the template. This tag is
responsible for extracting the screen definition from the request scope and insert-
ing it into the page. Code Example 10.3 contains the implementation of the
insert tag.
public class InsertTag extends TagSupport {
private boolean directInclude = false;
private String parameter = null;
private String templateName = null;
private Template template = null;
private TemplateParameter templateParam = null;
public void setTemplate(String templateName){
this.templateName = templateName;
}
public void setParameter(String parameter){
this.parameter = parameter;
}
THE VIEW 263
public int doStartTag() {
try {
if (templateName != null){
template = (Template)pageContext.getRequest().
getAttribute("template");
}
} catch (NullPointerException e){
...
}
if (parameter != null && template != null)
templateParam = (TemplateParameter)template.
getParam(parameter);
if (templateParam != null)
directInclude = templateParam.isDirect();
return SKIP_BODY;
}
public int doEndTag() throws JspTagException {
try {
pageContext.getOut().flush();
} catch (Exception e){
...
}
try {
if (directInclude && templateParam != null) {
pageContext.getOut().
println(templateParam.getValue());
} else if (templateParam != null) {
if (templateParam.getValue() != null)
pageContext.getRequest().
getRequestDispatcher(templateParam.
getValue()).include(pageContext.
getRequest(),
pageContext.getResponse());
}
} catch (Throwable ex) {
...
}
CHAPTER 10 THE SAMPLE APPLICATION264
return EVAL_PAGE;
}
}
Code Example 10.3 Insert Tag Implementation
The insert tag gets values of the parameters passed to it. The parameters are
automatically set by the JSP runtime environment and the tag focuses on inserting
the appropriate parameters into the response. Parameters can be direct or indirect.
Direct parameters are inserted as-is into the response stream. Indirect parameters
are treated as the name of a JSP file, and that file is dynamically included into the
response stream. This makes it possible to pass the title of a page as text using a
direct parameter, and the body as the name of a JSP file to include using an indi-
rect parameter.
10.3.2.2 View Selection
In a Web application, each screen presented to the user can be considered as a differ-
ent view. However, unlike the classic MVC architecture, all these views share the
same controller. There needs to be a mechanism that allows the controller to choose
a particular view to render in response to a user request. In the sample application,
the controller makes this selection by specifying the screen ID of the screen to
present as the response. This screen ID is mapped to a screen definition, then the
template is instantiated.
Recall that the file template.jsp defines the template for the sample applica-
tion. This file includes another file, ScreenDefinitions.jsp, which defines all the
screens of the sample application. When the controller invokes the template file at
request time, it sets the appropriate screen definition in the request scope. The
template file passes this information to the screen definitions file which then
returns the appropriate screen definition for the request.
One goal in structuring template and screen definition files is to facilitate
internationalization (discussed in Section 4.5 on page 88). This is achieved by
separating text content from Java code. Since screen definitions that contain direct
and indirect parameters are candidates for internationalization, we want to keep
ScreenDefinitions.jsp devoid of Java technology code. We achieve this through
the use of JSP custom tags. Code Example 10.4 contains an excerpt from Screen-
Definitions.jsp, which uses Screen and Parameter custom tags to pass text and
the contents of files to the response.
THE VIEW 265
<%@ page import="com.sun.estore.control.Web.ScreenNames" %>
...
...
Code Example 10.4 ScreenDefinitions.jsp
When it is included at request time by the template file, ScreenDefini-
tions.jsp uses ScreenFlowManager, a component of the controller, to identify the
view that the controller wishes to select. The nested custom tags arrange for that
screen’s definition to be set into the request scope when this file invoked.
In summary, the JSP pages template.jsp and ScreenDefinitions.jsp work
together to create the page viewed by the user. Figure 10.4 depicts the process of
view selection and instantiation in the sample application.
CHAPTER 10 THE SAMPLE APPLICATION266
Figure 10.4 View Selection and Instantiation
10.3.3 Examples
For the most part, the sample application’s presentation JSP pages use fairly
straightforward JSP elements. This section examines three example presentation
JSP pages: the home screen page (index.jsp), the products-by-category page (pro-
ductcategory.jsp), and the shopping cart page (cart.jsp).
10.3.3.1 Home Screen
The home screen of the Java Pet Store Demo application is shown in Figure 10.5.
The JSP source used to generate the screen, contained in the file index.jsp,
appears in Code Example 10.5. The screen is composed of the banner that appears
in all the Java Pet Store Demo screens, a list of the product categories (sidein-
dex.jsp) supported by the application, and an imagemap (splash.jsp) of the cat-
egories. The banner does not appear explicitly, because it is constructed by the
template described in Section 10.3.2.1 on page 259.
THE VIEW 267
Figure 10.5 Home Screen
<%@ include file="sideindex.jsp"%>
|
<%@ include file="splash.jsp" %>
|
Code Example 10.5 index.jsp
10.3.3.2 Product Category Screen
The screen that lists all the products in a category is shown in Figure 10.6.
The JSP source used to generate the screen, contained in the file productcat-
egory.jsp, appears in Code Example 10.6. In this code sample, the first statement
sets the catalog variable to point to an instance of the JavaBeans component Cat-
alogWebImpl. This component is used to retrieve the catalog entries for a particu-
CHAPTER 10 THE SAMPLE APPLICATION268
lar product category. The category is retrieved from the implicit request object
with the getParameter("category_id") method. Once the category and its prod-
ucts are retrieved, JSP scriptlets are used to generate the table of products.
Figure 10.6 Product Category Screen
<%
String key = request.getParameter("category_id");
Category category = null;
if (key != null) category = catalog.getCategory(key);
if (category != null) {
Collection products = null;
products = catalog.getProducts(key, 0, 20);
%>
<%= category.getDescription()%>
THE VIEW 269
<%
Iterator it = null;
if (products != null) it =products.iterator();
while (it.hasNext()) {
Product product = (Product)it.next();
%>
<% } %>
<%
} else {
// Category was not found:
%>
Unable to Locate Category ID <%= key
%>
<% } %>
Code Example 10.6 productcategory.jsp
10.3.3.3 Shopping Cart Screen
The screen that displays the contents of a user’s shopping cart is shown in Figure
10.7.
The JSP source used to generate the screen, contained in the file cart.jsp,
appears in Code Example 10.7 and Code Example 10.8. In this code sample, the
first statement sets the cart variable to point to an instance of the JavaBeans com-
ponent ShoppingCartWebImpl. This component is used by the shopping cart table.
CHAPTER 10 THE SAMPLE APPLICATION270
The include statement towards the middle of the code sample (begins with “<%@
include”) causes the page to include the shopping cart table (illustrated in Code
Example 10.8). The page also contains a button that accepts a modification to the
shopping cart, and a link to a checkout page.
Figure 10.7 Shopping Cart Screen
<%
if (cart.getSize() > 0) {
%>
Shopping Cart:
<%@ include file="changeable_carttable.jsp" %>
THE VIEW 271
|
|

<%
} else {
// The cart is empty
%>
Shopping Cart is empty.
<% } %>
Code Example 10.7 cart.jsp
Code Example 10.8 uses JSP scripting capabilities to display all the rows in
the shopping cart. The page retrieves shopping cart items from the cart compo-
nent set by the enclosing page cart.jsp. The page also includes a button that
allows a user to delete an item from the shopping cart.
CHAPTER 10 THE SAMPLE APPLICATION272
<%--
% Loop through each item in the shopping cart. The current item is
% available to the jsp block within the loop as "item"
--%>
<%
Iterator it = cart.getItems();
while ((it != null) && it.hasNext()) {
CartItem item = (CartItem)it.next();
%>
<% } // end for loop %>
THE MODEL 273
|
Item ID |
Product Name |
In Stock |
Unit Price |
Quantity |
Total Cost |
|
<%= item.getItemId() %> |
<%=item.getAttribute()%> <%=item.getName()%>
|
<%=(inventory.getInventory(item.getItemId())
>= item.getQuantity()) ? "yes" : "Back Ordered"%> |
<%=JSPUtil.formatCurrency(item.getUnitCost())%> |
|
<%=JSPUtil.formatCurrency(item.getTotalCost())%> |
|
Total: |
|
|
|
|
<%=JSPUtil.formatCurrency(cart.getTotalCost())%
|
Code Example 10.8 changeable_carttable.jsp
10.4 The Model
In this section we focus our attention on the state that needs to be maintained by the
application. One can think of the back-end of an application as a collection of state
with some rules on how the state changes in response to user interactions. This
section explains how the sample application maintains state in the J2EE platform
and persistent data in database tables.
10.4.1 State in the J2EE Platform
Typically, the customer will use a number of features of the pet store during a single
visit (such as requesting product information and placing items in a shopping cart),
resulting in numerous requests during the client session. While the application does
not need to store this information in a database, this information must be somehow
tracked to maintain a meaningful dialog between the customer and the application.
There is state associated with both the user interface and the business logic. In
general, the sample application must maintain the following state:
• The user identity: Typically, the user account module maintains the user iden-
tify, which includes the user’s login ID and certain security credentials.
• The search cursor and catalog position: The catalog module maintains the cur-
sor’s position within the current search and within the catalog hierarchy.
CHAPTER 10 THE SAMPLE APPLICATION274
• The items in the shopping cart: The shopping cart module maintains the list of
items placed in the customer’s shopping cart.
• Order information: When the customer confirms the order, the shopping cart
passes this information the order information—billing address, shipping ad-
dress, and payment method—to the order management module, which eventu-
ally stores it to a database.
The J2EE platform provides several choices for storing the application state.
An application can store state in the Web tier using the state maintenance capabil-
ities of servlets, which include the HTTPSession and ServletContext objects as
well as JavaBeans components. In the EJB tier, state can be maintained using
enterprise beans. Also, session state for an application can be divided between
these tiers. The decision of where each object representing application state is
stored depends on the lifetime and scope of the object. The following sections
identify each state component, its lifetime requirements, and discuss why it
should be stored using a particular mechanism.
The Web tier maintains state required by JSP pages in JavaBeans components.
These JavaBeans components are managed by a class called ModelManager that
uses both an HttpSession and a ServletContext to maintain handles to the Java-
Beans components. ModelManager is discussed further in Section 10.6.8.1 on
page 294. Beans that are specific to a client are maintained by an HTTP session
object. Beans that can be shared by all clients are maintained as an attribute of the
servlet generated from Main.jsp.
The JavaBeans components contain copies of the state maintained by corre-
sponding model objects which are maintained in the EJB tier. When designing
objects in the EJB tier to maintain state, the developer must answer two questions:
• What is the appropriate granularity for the objects? Not every business object
should be modelled as an enterprise bean. Since every method call to an enter-
prise bean is potentially a remote call, the overhead of an inter-component call
is likely to be prohibitive for interactions with fine-grained objects. Therefore,
the sample application makes extensive use of helper objects, which are non-
remote, serializable objects that mirror their respective enterprise beans.
• What type of enterprise bean should I use? An application can use either ses-
sion beans or entity beans to maintain state. For a non-transactional object, a
session bean is the simplest way to maintain session state for a short period of
time because it leverages the EJB container’s ability to manage session bean
THE MODEL 275
state. Using entity beans to maintain state provides transactional support for
storing the state data in the database. While there is overhead in making the ob-
ject transactional, the object reference could persist for as long as needed, even
beyond the scope of a single session. For example, an object reference can be
stored in a cookie on the browser to be retrieved and used even weeks later.
The sample application has examples of using both session and entity beans to
store session state.
10.4.1.1 Using Enterprise Beans to Maintain Session State
This section describes how different types of enterprise beans are used to represent
objects in the sample application. General guidelines for how to use enterprise
beans can be found in Chapter 5.
Stateless Session Beans
A stateless session bean does not contain state for a specific client. However, the
instance variables of a stateless session bean can contain state across method calls.
Examples of such state include an open database connection and a cache of data
retrieved from that connection. Stateless session beans are never written out to sec-
ondary storage. As a consequence, stateless beans usually offer better performance
than stateful beans.
The sample application uses stateless session beans for objects containing
more than one database row. In particular, because stateless session beans provide
high performance, stateless session beans are a good choice to provide a fast
access to data derived from multiple database rows. In the pet store application,
the Catalog stateless session bean functions as a cache that is built up over time.
Stateful Session Beans
A stateful session bean exists during a single client session and can maintain infor-
mation specific to a client between invocations of methods. The sample application
represents the contents of a client’s shopping cart with the ShoppingCart stateful
session bean.
Entity Beans
The sample application uses entity beans to provide an object view of individual
rows in a database. The sample application includes three such beans, Account,
Inventory, and Order, to represent individual rows in the corresponding tables.
CHAPTER 10 THE SAMPLE APPLICATION276
10.4.1.2 Helper Objects
It is not appropriate to model all objects in the EJB tier as enterprise beans. There-
fore, the sample application uses helper objects that are subordinate to their respec-
tive enterprise beans for a number of purposes. The different types of helper objects
are: data access objects and value objects. The use of helper objects is discussed in
detail in Section 5.5 on page 130.
Data Access Objects
A data access object is used to encapsulate access to databases. Data access objects
can encapsulate access to more than one database, more than one table within one
database, and different types of databases. The sample application uses data access
objects for all these purposes.
The sample application uses the abstract data access class OrderDAO to access
three tables, order, orderstatus, and lineitem, when an order is created, read, or
updated. The sample application contains three subclasses, OrderDAOOracle,
OrderDAOSybase, and OrderDAOCS, that are used to access Oracle, Sybase, and
Cloudscape databases.
Value Objects
A value object is a business object that can be passed by value as a serializable Java
object. A business concept should be implemented as a value object when it is fine-
grained, dependent, and immutable. The sample application uses two types of value
objects: dependent objects and details objects.
An object is a dependent object of another object if its life cycle is completely
managed by that object and if it can only be accessed indirectly through that
object. Examples of dependent objects in the sample application are Address and
CreditCard.
A value object can also be used to encapsulate an entire remote object. Such
objects allow a client to retrieve the value of a remote object in one remote call.
The sample application contains details objects for each enterprise bean. Code
Example 10.9 illustrates an account entity bean and its corresponding details
object. In keeping with its purpose, AccountModel’s methods only enable retrieval
of the values in the fields of its bean, while Account itself provides a method for
setting a value and a coarse-grained method (getDetails) that returns an
AccountModel.
THE MODEL 277
public interface Account extends EJBObject {
public AccountModel getDetails() throws RemoteException;
public void changeContactInformation(ContactInformation info)
throws RemoteException;
}
public class AccountModel implements java.io.Serializable {
private String userId;
private String status;
private ContactInformation info;
...
public String getUserId() {
return userId;
}
public ContactInformation getContactInformation() {
return info;
}
...
}
Code Example 10.9 Account and AccountModel
10.4.2 Persistent Data
The sample application maintains persistent data in database tables, organized
according to the functional areas of the application. Figure 10.8 illustrates the data-
base schema.
The application uses this database schema to maintain accounts and track
orders for products. Thus, there are three areas for which data must be maintained:
product, account, and order information. The product, category, and item tables
represent the business’s product catalog. Each item has an associated entry in the
inventory table that represents the inventory for that product. The account table
maintains customer account information, one record per customer, with informa-
tion such as customer name, password, and customer address. Finally, there is an
orders table with one record per order, for information such as ship-to address,
bill-to address, total price of the order, and payment (credit card name, expiration
date, type) information. The orders table is linked to lineitem and orderstatus
tables. Each item in an order is stored in a separate lineitem record, which con-
CHAPTER 10 THE SAMPLE APPLICATION278
tains the quantity ordered and price and a separate orderstatus record, which
contains a reference to the item and the status of the order.
Figure 10.8 Database Tables and Relationships
10.5 Implementation
In the implementation of the view, JSP pages rely on JavaBeans components to
mirror model data. These components are named ESObjectWebImpl (where ESOb-
ject are the e-store objects Inventory, Account, Cart, and Order). As Code
Example 10.10 illustrates, ESObjectWebImpl extends ESObjectModel and imple-
ments a listener interface so that views can be notified of changes to their corre-
sponding models. For example, when an AccountWebImpl is created, it adds itself to
the list of listeners interested in updates to the account model. When an account
model changes, the manager of the view objects invokes the performUpdate method
on all views that have registered as listeners of the account model. See Section
10.6.8 on page 294 for further discussion of model-view synchronization.
IMPLEMENTATION 279
public class AccountWebImpl extends AccountModel
implements ModelUpdateListener {
private ModelManager mm;
private Account acctEjb;
public AccountWebImpl(ModelManager mm) {
super(null, null, null);
this.mm = mm;
mm.addListener(JNDINames.ACCOUNT_EJBHOME, this);
}
public void performUpdate() {
if (acctEjb == null) {
acctEjb = mm.getAccountEJB();
}
try {
if (acctEjb != null) copy(acctEjb.getDetails());
} catch (RemoteException re) {
throw new GeneralFailureException(re);
}
}
}
Code Example 10.10 AccountWebImpl
The model is implemented by enterprise beans named ESObject. These beans
are supported by data access classes named ESObjectDAO and details classes
named ESObjectModel. As described in “Value Objects” on page 276, a client can
retrieve the contents of an enterprise bean with one remote call that returns a
details object.
JavaBeans components and details classes share aspects of their implementa-
tion (that is, the ESObjectModel classes), because the ESObjectModel classes
capture the essential information required to represent e-store business objects in
any tier.
The implementation of the catalog does not follow the pattern just described
because it implemented in both a Web-centric and EJB-centric fashion. The Web-
centric design is used for high performance since the catalog is read-only and the
most frequently accessed object in the system. Thus the Web-centric JavaBeans
CHAPTER 10 THE SAMPLE APPLICATION280
component CatalogWebImpl accesses the data access class CatalogDAO directly
instead of calling an enterprise bean.
Since the shopping cart enterprise bean needs access to the catalog and cannot
access the Web-tier catalog it uses a catalog enterprise bean. Note that high per-
formance is not as crucial in this case as compared to the earlier case but access to
the catalog is still read-only.
The implementation of the catalog functionality is essentially the same in both
cases, so both CatalogWebImpl and CatalogEJB extend CatalogImpl which imple-
ments the CatalogModel interface.
The relationships between the sample application business objects—view
classes in the Web tier, model classes (and their respective helper classes) in the
EJB tier, and database tables in the enterprise information system tier—are shown
in Figure 10.9.
Figure 10.9 Sample Application Business Objects
10.6 The Controller
The sample application must reflect the state of a user’s interaction with the applica-
tion and the current values of persistent data in the user interface. Following the
MVC architecture, this functionality is implemented within the controller. In the
sample application, the controller is split between the Web tier and the EJB tier. In
this section we will discuss the implementation of the controller for the shopping
interaction in the sample application.
The controller is responsible for coordinating the model and view. As
described in Section 10.2 on page 248, the view depends on the controller for
THE CONTROLLER 281
screen selection. The model depends on the controller for making state changes to
the model. The controller must accept user gestures from the view, translate them
into business events based on the behavior of the application, and process these
events. The processing of an event involves invoking methods of the model to
cause the desired state changes. Finally, the controller selects the screen shown in
response to the request that was processed.
Since the controller must coordinate both the view and the data, it straddles
the Web and EJB tiers. Some components of the controller are hosted by the Web
tier and facilitate communication with the view, while others are hosted by the
EJB tier and control the model.
In the Web tier, the controller consists of several components:
• Main.jsp receives and processes HTTP requests. Main.jsp calls ScreenFlow-
Manager, which is responsible for selecting the next screen to be shown to the
client after the completion of the current request.
• RequestProcessor provides the glue in the Web tier for holding the application
components together. It contains logic that needs to be executed for each request.
RequestProcessor collaborates with two classes:
■ RequestToEventProcessor translates HTTP requests into business events
that the rest of the application can operate on. Events are represented by the
class eStoreEvent and its subclasses CatalogEvent, LoginEvent, Ac-
countEvent, CartEvent, and OrderEvent.
■ ShoppingClientControllerWebImpl (SCCWI) provides a Web-tier proxy for
ShoppingClientController. It delegates all methods to its EJB tier counter-
part.
In the EJB tier, the controller is ShoppingClientController (SCC), which pro-
vides the view with read-only access to the model and handles business events.
ShoppingClientController collaborates with StateMachine, an object that con-
trols the creation and removal of enterprise beans and handles events to modify
those objects passed to it by the controller in the Web tier.
Figure 10.10 illustrates the interactions that occur between the collaborating
controller objects when an HTTP request is handled. The servlet generated from
Main.jsp receives all HTTP requests. It passes the request to RequestProcessor,
which coordinates all handling of the request. RequestProcessor uses Request-
ToEventTranslator to translate the HTTP request into a business event. Request-
Processor then passes the event to ShoppingClientControllerWebImpl, which
CHAPTER 10 THE SAMPLE APPLICATION282
forwards the event to ShoppingClientController, the controller in the EJB tier.
ShoppingClientController delegates the handling of the business event to
StateMachine. StateMachine changes the state of the model in response to the busi-
ness event or command and then retrieves a list of model objects that have changed
as a result of handling the business event from ModelUpdateManager (MUM). Finally,
RequestProcessor notifies all registered views of model changes.
Figure 10.10 Controller Object Interaction Diagram (Part 1)
Figure 10.11 shows what happens after RequestProcessor.processRequest
returns. Main.jsp forwards the initial request to template.jsp. The template
includes ScreenDefinitions.jsp, which uses ScreenFlowManager to map the
screen to a JSP page.
In the following sections, we will discuss the implementation of each of these
components in more detail.
10.6.1 Main
A front component is a component to which all requests for application URLs
are delivered. The front component Main.jsp, processes these requests and dele-
gates the generation of the response to the template page.
THE CONTROLLER 283
Figure 10.11 Controller Object Interaction Diagram (Part 2)
Code Example 10.11 shows Main.jsp. The highlighted lines in the example
indicate these two steps. Main.jsp delegates all of the request processing tasks to
RequestProcessor. The response is generated by forwarding to template.jsp. An
interesting detail to note here is that Main.jsp stores references to the request pro-
cessor and other session-specific beans in the HTTP session object.
<% modelManager.init(config.getServletContext(), session); %>
<% rp.init(config.getServletContext(), session); %>
<%
try {
rp.processRequest(request);
request.setAttribute("selectedURL" , request.getPathInfo());
} catch (MissingFormDataException mi){
request.setAttribute("missingformdata", mi);
request.setAttribute("selectedURL", "/missingformdata");
CHAPTER 10 THE SAMPLE APPLICATION284
} catch (DuplicateAccountException du){
request.setAttribute("selectedURL", "/duplicateaccount");
}
getServletConfig().getServletContext()
.getRequestDispatcher("/template.jsp")
.forward(request, response);
%>
Code Example 10.11 Main.jsp
10.6.2 RequestProcessor
RequestProcessor contains logic that gets executed for each request. For example,
when a customer tries to access a feature that requires signin, RequestProcessor
checks to detect whether the customer is logged in.
Code Example 10.12 presents an excerpt from RequestProcessor, simplified
to illustrate the key aspects of its behavior.
public class RequestProcessor {
private ShoppingClientControllerWebImpl scc;
private ModelManager mm;
private ModelUpdateNotifier mun;
private RequestToEventTranslator eventTranslator;
private SecurityAdapter securityAdapter;
public void init(...) {
mm = (ModelManager)session.getAttribute("modelManager");
mun = mm;
scc = new ShoppingClientControllerWebImpl(session);
eventTranslator =
new RequestToEventTranslator(this, mm);
...
}
public void processRequest(HttpServletRequest req) {
checkForWebServerLogin(req);
EStoreEvent event = eventTranslator.processRequest(req);
if (event != null) {
THE CONTROLLER 285
Collection updatedModelList = scc.handleEvent(event);
mun.notifyListeners(updatedModelList);
}
...
}
}
Code Example 10.12 RequestProcessor
This excerpt demonstrates the core responsibilities of RequestProcessor
including:
• Initializing the client session. RequestProcessor instantiates an object that im-
plements ShoppingClientController and related application objects when a
new session is initiated.
• Detecting when the user logs into the server using form-based authentication
and generating a login business event when this happens.
• Computing the business event to generate based on the HttpRequest that came
in, with the help of the RequestToEventTranslator.
• Raising a business event by invoking handleEvent on the ShoppingClientCon-
troller’s Web implementation.
• Gathering the outcome of the event processing. In particular, RequestProces-
sor passes the business event and its outcome to the ModelManager so the mod-
el change notifications can be processed by the view components (see Section
10.6.8 on page 294).
10.6.3 RequestToEventTranslator
RequestToEventTranslator is responsible for taking an HTTP-specific request and
converting it into a business event that is not tied to the specifics of the HTTP
protocol.
Application objects that include HTTP-specific functionality are not easy to
reuse. By removing HTTP protocol-specific details from the request as early as
possible, by turning it into a business event, the sample application ensures that all
components that deal with business events would be completely reusable with
non-HTTP clients. For example, the StateMachine that implements command
CHAPTER 10 THE SAMPLE APPLICATION286
processing logic for the sample application could be easily used as-is by a stand-
alone Java client.
The two standard HTTP requests that can be processed by the translator are
GET and POST. It is relatively straightforward to map GET requests to business
events. However, POST requests, which represent form submission in the sample
application, require the request processor to validate the form data as part of gen-
erating the business event. The processor needs to keep track of the values entered
in the form so that the presentation screen can show where the error occurred
when the form data is invalid. When the form data is valid, the processor must
encapsulate the form parameters in an application-specific business event.
Code Example 10.13 presents excerpts from RequestToEventTranslator. The
highlighted lines indicate where the translator parses HTTP request parameters
and converts them to objects to be used in business events.
public class RequestToEventTranslator {
private ModelManager mm;
public EStoreEvent processRequest(HttpServletRequest req)
throws EStoreEventException, MissingFormDataException {
String selectedUrl = req.getPathInfo();
EStoreEvent event = null;
if (selectedUrl.equals(ScreenNames.CATALOG_URL)) {
event = createCatalogEvent(req);
else if (selectedUrl.equals(ScreenNames.CART_URL)) {
mm.getCartModel();
event = createCartEvent(req);
} else if ...
return event;
}
private EStoreEvent createCatalogEvent(HttpServletRequest req) {
CatalogEvent event = null;
String[] category = req.getParameterValues(CATEGORY_ID );
if (category != null) {
event = new CatalogEvent(
CatalogEvent.BROWSING_EVENT, category[0]);
}
return event;
}
THE CONTROLLER 287
private CartEvent createCartEvent(HttpServletRequest request) {
String action = request.getParameter("action");
if (action.equals("purchaseItem")) {
return createPurchaseItemEvent(request);
} else if (action.equals("removeItem")) {
return createRemoveItemEvent(request);
} else if (action.equals("updateCart")) {
return createUpdateCartEvent(request);
}
}
}
Code Example 10.13 RequestToEventTranslator
10.6.4 ShoppingClientControllerWebImpl
ShoppingClientControllerWebImpl is a proxy object that calls methods on the EJB
tier controller ShoppingClientController. ShoppingClientControllerWebImpl
exposes a read-only interface to the model, so that the view can render the model
as needed. Keeping this interface read-only minimizes dependencies between the
view and the model, to prevent inadvertent modification of the model by the view
outside the scope of the business rules encapsulated in the application.
Code Example 10.14 contains an excerpt from ShoppingClientController-
WebImpl. Notice that all the methods of ShoppingClientController are synchro-
nized so that concurrent requests to ShoppingClientController are serialized.
This is done because an EJB container will throw an exception if a request is made
to a session bean while it is servicing another request.
public class ShoppingClientControllerWebImpl
{
private com....ejb.ShoppingClientController sccEjb;
private HttpSession session;
public ShoppingClientControllerWebImpl(HttpSession session) {
this.session = session;
ModelManager mm =
(ModelManager)session.getAttribute("modelManager");
sccEjb = mm.getSCCEJB();
}
public synchronized AccountModel getAccount() {
CHAPTER 10 THE SAMPLE APPLICATION288
return sccEjb.getAccount().getDetails();
}
...
public synchronized Collection handleEvent(EStoreEvent ese) {
return sccEjb.handleEvent(ese);
}
public synchronized void remove() {
sccEjb.remove();
}
}
Code Example 10.14 ShoppingClientControllerWebImpl
10.6.5 ShoppingClientController
ShoppingClientController manages the life cycle of model objects such as the
shopping cart and account enterprise beans and processes business events. It dele-
gates the processing of business events in the handleEvent method to StateMa-
chine. ShoppingClientController is also responsible for the life cycle of
StateMachine. ShoppingClientController is implemented by ShoppingClient-
ControllerEJB, illustrated in Code Example 10.15.
public class ShoppingClientControllerEJB implements SessionBean {
private StateMachine sm;
private ShoppingCart cart;
String userId;
Account acct;
public Account getAccount() {
if (acct == null) {
createAccountEJB();
}
return acct;
}
public ShoppingCart getShoppingCart() {
if (cart == null) {
try {
ShoppingCartHome cartHome =
THE CONTROLLER 289
EJBUtil.getShoppingCartHome();
cart = cartHome.create();
} catch (CreateException ce) {
throw new EJBException(ce);
}
}
return cart;
}
public void ejbCreate() {
sm = new StateMachine(this);
}
public Collection getOrders() throws FinderException {
Collection orders = null;
if (userId != null) {
OrderHome home = EJBUtil.getOrderHome();
orders = home.findUserOrders(userId);
}
return orders;
}
public Collection handleEvent(EStoreEvent ese)
throws EStoreEventException {
try {
return (sm.handleEvent(ese));
} catch (RemoteException re) {
throw new EJBException (re);
}
}
}
Code Example 10.15 ShoppingClientControllerEJB
10.6.6 StateMachine
StateMachine implements the core command processing business logic of the
application. It is responsible for changing the state of the models in response to a
business event or command. StateMachine consists of methods that handle each of
the different business events that the sample application can respond to. One such
method is highlighted in Code Example 10.16.
CHAPTER 10 THE SAMPLE APPLICATION290
public class StateMachine {
private ShoppingClientControllerEJB sccejb;
private ModelUpdateManager mum;
private HashMap orderTable;
public StateMachine(ShoppingClientControllerEJB sccejb) {
this.sccejb = sccejb;
this.mum = new ModelUpdateManager();
}
public Collection handleEvent(EStoreEvent ese)
throws RemoteException, EStoreEventException {
if (ese instanceof CartEvent) {
handleCartEvent((CartEvent)ese);
} else if (ese instanceof AccountEvent) {
handleAccountEvent((AccountEvent)ese);
} else if (ese instanceof OrderEvent) {
handleOrderEvent((OrderEvent)ese);
} else if (ese instanceof LoginEvent) {
login((LoginEvent)ese);
} else if (ese instanceof LogoutEvent) {
logout();
}
return (mum.getUpdatedModels(ese));
}
private void handleCartEvent(CartEvent ce)
throws RemoteException {
ShoppingCart cart = sccejb.getShoppingCart();
switch (ce.getActionType()) {
...
case CartEvent.UPDATE_ITEM :{
Collection itemIds = ce.getItemIds();
Iterator it = itemIds.iterator();
while (it.hasNext()){
String itemId = (String)it.next();
int quantity = ce.getItemQty(itemId);
if (quantity > 0){
cart.updateItemQty(itemId, quantity);
} else {
cart.deleteItem(itemId);
}
THE CONTROLLER 291
}
}
break;
}
}
...
}
Code Example 10.16 StateMachine
StateMachine has both read and write access to all of the model objects so
that it can coordinate event processing across multiple model objects. For exam-
ple, when StateMachine handles an order event, it interacts with the inventory
bean to debit the quantity of the purchased item, the order bean to insert the order
details, and the mailer bean to send confirmation email to the user. These func-
tions are performed by the method illustrated in Code Example 10.17. High-
lighted lines indicate where enterprise beans are retrieved or created.
private Order createOrder(OrderEvent oe) throws RemoteException {
ShoppingCart cart = sccejb.getShoppingCart();
Order order = null;
String userId = sccejb.getAccount().getDetails().getUserId();
try {
InventoryHome inventHome = EJBUtil.getInventoryHome();
Iterator ci = ((ShoppingCartModel)cart.getDetails()).
getItems();
ArrayList lineItems = new ArrayList();
int lineNo = 0;
double total = 0;
while (ci.hasNext()) {
lineNo++;
CartItem cartItem = (CartItem) ci.next();
LineItem li = new LineItem(cartItem.getItemId(),
cartItem.getQuantity(),cartItem.getUnitCost(),
lineNo);
lineItems.add(li);
total += cartItem.getUnitCost() * cartItem.getQuantity();
}
CHAPTER 10 THE SAMPLE APPLICATION292
for (Iterator it = lineItems.iterator(); it.hasNext();){
LineItem LI = (LineItem)it.next();
Inventory inventRef =
inventHome.findByPrimaryKey(LI.getItemNo());
inventRef.updateQuantity(LI.getQty());
}
OrderHome home = EJBUtil.getOrderHome();
order = home.create(lineItems,
oe.getShippingAddress(),
oe.getBillingAddress(),
...
total);
// put the requestId and the orderId in a table to match up later
if (orderTable == null) orderTable = new HashMap();
orderTable.put(oe.getRequestId() + "",
order.getDetails().getOrderId() +"");
// empty shopping cart
cart.empty();
if (JNDIUtil.sendConfirmationMail()) {
// send order confirmation mail.
Mailer mailer = EJBUtil.createMailerEJB();
mailer.sendOrderConfirmationMail(order.getDetails().
getOrderId());
}
} catch (DuplicateKeyException dke) {
...
} catch (CreateException ce) {
throw new EJBException(ce);
} catch (FinderException fe) {
throw new EJBException(fe);
}
THE CONTROLLER 293
return order;
}
Code Example 10.17 StateMachine.createOrder
10.6.7 ScreenFlowManager
ScreenFlowManager is responsible for selecting a screen to present to the user as the
outcome of their request. The mapping from a requested URL to a response screen
is not one to one. In fact, the response that depends not only on the request itself, but
also on the state of the application data model and the outcome of request process-
ing within the application. In other words, the flow manager keeps a state machine
that captures the flow of screens in the application. ScreenFlowManager looks at
the request and the state of the model and computes the screen to be returned.
Code Example 10.18 shows how ScreenFlowManager maps many of the
request URLs directly into response screens. For some of the requests, such as the
VALIDATE_BILLING_INFO_URL, the code inspects the model to decide which of two
possible screens to present.
public class ScreenFlowManager {
public int getCurrentScreen(HttpServletRequest req) {
String selectedUrl =
(String)req.getAttribute("selectedURL");
int nextScreen = ScreenNames.DEFAULT_SCREEN;
if (selectedUrl == null) {
// do nothing. show the default screen.
} else if (selectedUrl.equals(ScreenNames.CATALOG_URL)) {
nextScreen = ScreenNames.CATALOG_SCREEN;
...
} else if (selectedUrl.equals(
ScreenNames.VALIDATE_BILLING_INFORMATION_URL)) {
if (req.getSession()
.getAttribute("shippingAddressRequired") != null) {
boolean addrReqd = req.getSession()
.getAttribute("addrReqd").equals("true");
if (addrReqd)
CHAPTER 10 THE SAMPLE APPLICATION294
nextScreen = ScreenNames.ENTER_SHIPPING_INFO;
else
nextScreen = ScreenNames.CONFIRM_SHIPPING_INFO;
}
}
return nextScreen;
}
}
Code Example 10.18 ScreenFlowManager
10.6.8 Model-View Synchronization
Following the MVC architecture, views implemented by JSP pages and JavaBeans
components present data owned by their associated models implemented as enter-
prise beans. In the sample application, each Web-tier JavaBeans component serves
as the view, with corresponding EJB-tier classes representing the model. Whenever
a model changes, it notifies interested views so that the views can update its presen-
tation of the model.
In the sample application, the notification process is managed by ModelUp-
dateManager and ModelManager. ModelUpdateManager is responsible for convert-
ing a business event, such as AccountEvent, to a list of names of models that have
changed due to this event. ModelManager uses this list to notify all views that have
registered interest in the changed models to fetch the models’ data.
The functions of ModelManager and ModelUpdateManager and their interac-
tions with controller objects are described in the following sections.
10.6.8.1 Model Manager
ModelManager extends ModelUpdateNotifier, which provides methods for adding
listeners of model change events and causing listeners (that is, views) to perform an
update when a change event is received. ModelManager adds methods that create and
return instances of view classes.
Code Example 10.19 presents excerpts from ModelManager. Note that Model-
Manager maintains references to both a ServletContext and an HttpSession.
These objects in turn contain references to view objects (highlighted in the exam-
ple). View objects specific to a client (for example, AccountModel) are maintained
THE CONTROLLER 295
by an HTTP session object. View objects that can be shared by all clients (for
example, CatalogModel) are maintained as an attribute of the servlet generated
from Main.jsp.
public class ModelManager extends ModelUpdateNotifier {
private ServletContext context;
private HttpSession session;
private ShoppingClientController sccEjb = null;
private ShoppingCart cartEjb = null;
private Account acctEjb = null;
public void init(ServletContext context,
HttpSession session) {
this.session = session;
this.context = context;
getAccountModel();
}
public CatalogModel getCatalogModel() {
CatalogModel catalog = (CatalogModel)
context.getAttribute(WebKeys.CatalogModelKey);
if (catalog == null) {
catalog = new CatalogWebImpl();
context.setAttribute(WebKeys.CatalogModelKey, catalog);
}
return catalog;
}
public AccountModel getAccountModel() {
AccountModel acct = (AccountModel)
session.getAttribute(WebKeys.AccountModelKey);
if (acct == null) {
acct = new AccountWebImpl(this);
session.setAttribute(WebKeys.AccountModelKey, acct);
}
return acct;
}
CHAPTER 10 THE SAMPLE APPLICATION296
...
}
Code Example 10.19 ModelManager
10.6.8.2 ModelUpdateManager
ModelUpdateManager is responsible for converting an EStore event to a list of
names of models that have changed due to this event. Code Example 10.20 presents
excerpts from ModelUpdateManager.
public class ModelUpdateManager {
...
public Collection getUpdatedModels(EStoreEvent ese)
throws RemoteException {
ArrayList modelList = new ArrayList();
if (ese instanceof CartEvent) {
modelList.add(JNDINames.CART_EJBHOME);
} else if (ese instanceof AccountEvent) {
modelList.add(JNDINames.ACCOUNT_EJBHOME);
} else if (ese instanceof OrderEvent) {
modelList.add(JNDINames.ORDER_EJBHOME);
modelList.add(JNDINames.INVENTORY_EJBHOME);
modelList.add(JNDINames.CART_EJBHOME);
} else if (ese instanceof LoginEvent) {
modelList.add(JNDINames.ACCOUNT_EJBHOME);
}
return modelList;
}
}
Code Example 10.20 ModelUpdateManager
10.7 MVC Summary
Figure 10.12 summarizes the references between the view, model, and controller
classes.
MVC SUMMARY 297
Figure 10.12 Object Reference Diagram
CHAPTER 10 THE SAMPLE APPLICATION298
10.8 Stateless Services
The sample application uses stateless session beans for shared service objects. For
example, in an e-commerce application, you might want to send order confirmation
mail to customers on successful completion of an order. Such a service can be
shared by all clients of the application. The sample application Mailer service
objects are stateless session beans.
10.8.1 Example: A Mailer Bean
When a client places an order, an order event is passed to ShoppingClientControl-
ler. Although the handleEvent method is defined by ShoppingClientController,
ShoppingClientController delegates its implementation to a helper class named
StateMachine. StateMachine interacts with Inventory, Order, and Mailer enter-
prise beans to debit the quantity of the purchased item, insert the order details, and
finally send the confirmation email to the client.
The last thing that StateMachine does in the createOrder method is to send
an order confirmation message. It does this by first creating Mailer stateless
session bean and then invoking the Mailer.sendOrderConfirmationMail method
(shown in Code Example 10.21). This method uses the order ID to obtain the
information needed for the confirmation message from the Order and Account
entity beans. The Mailer then invokes the createAndSendMail method of its
helper class MailHelper.
public void sendOrderConfirmationMail(int orderId)
throws RemoteException {
OrderDetails orderDetails = null;
try {
OrderHome orderHome = EJBUtil.getOrderHome();
Order order = orderHome.findByPrimaryKey(orderId);
orderDetails = order.getOrderDetails();
} catch (FinderException fe) {
...
return;
}
String userId = orderDetails.getUserId();
AccountDetails acctDetails = null;
try {
AccountHome acctHome = EJBUtil.getAccountHome();
STATELESS SERVICES 299
Account acct = acctHome.findByPrimaryKey(userId);
acctDetails = acct.getAccountDetails();
} catch (FinderException fe) {
...
}
String subject = "Your order# "+orderId;
String HTML Contents =
"This message is a confirmation of your order# "
+ orderId + ". Please save it for your records.";
getMailHelper().createAndSendMail(acctDetails.
getEmail(), subject, HTML Contents);
}
Code Example 10.21 Mailer.sendOrderConfirmationMail
Code Example 10.22 illustrates the createAndSendMail method of Mail-
Helper. This method looks up a mail session in the JNDI namespace, creates a
MIME message, sets the mail headers, collects the contents of the message into a
string, and then sends the message.
public void createAndSendMail(String to,
String subject, String HTML Contents) {
try {
InitialContext ic = new InitialContext();
Session session = (Session) ic.
lookup(JNDI Names.MAIL_SESSION);
// construct the message
Message msg = new MimeMessage(session);
msg.setFrom();
msg.setRecipients(Message.RecipientType.TO,
InternetAddress.parse(to, false));
msg.setSubject(subject);
collect(subject, htmlContents, msg);
msg.setHeader("X-Mailer", "JavaMailer");
msg.setSentDate(new Date());
// send the message
Transport.send(msg);
CHAPTER 10 THE SAMPLE APPLICATION300
} catch (Exception e) {
...
}
}
Code Example 10.22 MailHelper.createAndSendMail
10.9 Deployment
Much of the behavior of the sample application is determined by information speci-
fied in its deployment descriptors: estore_ejb.xml, estore_ejbruntime.xml,
estore_war.xml, and estore_warruntime.xml. Elements specified in these deploy-
ment descriptors are discussed in detail in Section 7.1 on page 165 and Section 7.3
on page 174.
10.10 Transactions
The sample application’s persistent data is stored in two databases: eStoreData-
Source and InventoryDataSource. The eStoreDataSource database holds informa-
tion about accounts and orders. The InventoryDataSource database holds
information about products, product categories, and the inventory of each product.
When an order is placed, ShoppingClientController must access both databases.
The sample application uses J2EE SDK support for distributed transactions to
reduce the inventory of ordered products and add a new entry to the order table in an
atomic operation. Note that a J2EE product is not required to support access to
multiple JDBC databases within a single transaction. However, some J2EE prod-
ucts might choose to provide these extra transactional capabilities.
Recall that ShoppingClientController delegates the implementation of order
processing to a helper class named StateMachine. StateMachine is responsible for
maintaining consistency among the database tables represented by the enterprise
beans that it calls. When StateMachine handles an order event it invokes the
method createOrder illustrated in Code Example 10.17. For each bean, StateMa-
chine gets a reference to the home interface and then creates an instance of the
bean. StateMachine loops through the list of items in the order, finds the appropri-
ate inventory item, and updates the inventory table for that item. Simply creating
SECURITY 301
an instance of the Order bean causes an entry to be added to the order, lineitem,
and orderstatus tables.
Note that neither the StateMachine.createOrder nor individual bean opera-
tions explicitly invoke transactions, because ShoppingClientController uses
container-managed transactions. As a result, all database operations invoked by
ShoppingClientController are automatically wrapped in a transaction by the
container. The transaction context is automatically propagated to any enterprise
beans that ShoppingClientController invokes (in this case Inventory and
Order).
10.11 Security
This section describes the sample application’s security requirements and discusses
the ways these requirements are addressed using the J2EE security framework.
10.11.1 Requirements
The pet store application is designed to be deployed on the Internet. Like many
Web-based e-commerce applications, it allows anyone to interact with and use the
application. Any user, regardless of whether they’re a registered customer, can point
a browser at the start URL of the application and browse through the catalog,
viewing items, prices, inventory status, and so on. We call this tire kicking, and this
class of users tirekickers.
A new customer can sign up using a form presented by the application. Once
a customer has signed up, the customer can sign in, by providing a user name and
password to the application. Only customers who have signed in are allowed to
place orders and view order status. When an order is placed, the payment details,
including the credit card number, must be transmitted in a secure manner.
Some users of the pet store application may receive special treatment. For
example, a frequent shopper may a preferred customer, able to receive discounts
or awards not available to normal customer. Another class of special user might be
system administrators, with unlimited access to information on the site. For exam-
ple, they might be able to fetch a list of all orders placed after a certain date.
CHAPTER 10 THE SAMPLE APPLICATION302
These high-level functional requirements translate into the following security
requirements:
• User Authentication
Users of the pet store application can be either authenticated or unauthen-
ticated. The user must be authenticated to access a protected resource. The
application should be able to identify, differentiate, and be able to make
access control decisions based on this distinction.
There should be a way to associate each authenticated user with one or
more categories. For example, user A could be recognized as a customer,
while user B could be recognized as a preferred customer.
• Authorization
The application associates permissions with resources such as Web pages
or enterprise bean methods. Examples of the kind of authorization constraints
the application should allow:
■ Anyone (authenticated or not), to see the URL /control/product, or invoke
the getProducts method of Catalog
■ All authenticated users to see the URL /control/placeorder
■ Only preferred users to see the URL /control/discounts
• Confidentiality
Some user information, such as a credit card number, must be transmitted
confidentially to the application.
• User Administration
The sample application has its own set of users. This set of users grows
when new users add themselves using a Web-based interface. Note that other
applications, such as those developed for in-house use within an enterprise
assume and use the set of users defined in the operational environment. The
sample application does not depend on the operational environment to get its
set of users.
SECURITY 303
10.11.2 Implementation
The pet store application uses many features of the J2EE platform to address its
security requirements in a simple and transparent manner. By design, security in the
J2EE platform is mostly declarative. In some places however, we make security
decisions in our components programmatically, because we needed to make authori-
zation decisions based on the content or state of the object.
10.11.2.1 User Authentication
A J2EE application must be capable of authenticating users that access the applica-
tion from a variety of clients. This section describes how the pet store application
authenticates users of the shopping interaction Web client, how it could authenticate
users of an administration application client, and how it handles unauthenticated
users.
Web Client Authentication
Most of the interactions with the sample application occur through the Web-based
interface. Form-based authentication, one of the standard authentication mecha-
nisms in the J2EE architecture, is used to authenticate these interactions.
In form-based authentication, a Web container designates an application-spe-
cific page containing an HTML form for logging in. The sample application uses
the page login.jsp as this page. This page contains an HTML form that prompts
for a user name and password and is displayed when the user tries to access a
resource that has been designated as being protected. The sample application also
uses form-based authentication to enable:
• Explicit signin
The sample application allows users to explicitly sign in by clicking the
sign-in link in the user interface. The sign-in link points to /signin which is a
dummy URL that is inaccessible to unauthenticated users.
When the user clicks sign-in, the application attempts to take them to the
signin.jsp page, which is denied since the page is protected. As a result, the
login.jsp form is shown instead.
Note that we cannot simply make the sign-in link point to login.jsp
because an authorization failure must occur for the form-based authentication
CHAPTER 10 THE SAMPLE APPLICATION304
mechanism to be activated.
• Informing the user about failed authentication
The sample application retries the protected resource after authentication
through form-based authentication irrespective of the outcome of authentica-
tion. If authentication failed, the login.jsp form will be shown to the user
again. At this point, it is desirable to do two things: first, make sure that the
form comes back already filled with the values that were posted in the last try,
and second, inform the user somewhere in the form that authentication failed
the first time.
Form-based authentication does not provide a portable way to return the
form to the user with the values posted in the failed try. The POST to the form
is handled by the Web container, and never returned to the form.
Informing the user that signon failed is easier to accomplish. To do so, the
login.jsp page uses a session-scoped bean (see Code Example 10.23) stored
each time the form is accessed. If this time is close to the current time, and the
current request is unauthenticated, then the sample application prints a mes-
sage indicating that the login failed earlier. A request to login.jsp would
always be unauthenticated, unless there is an application programming error.
The only situation where login.jsp is shown should be when the request is
unauthenticated. Using a similar mechanism, it is also possible to go to an
error page after a fixed number of retries.
<% if (last_login.getTime() - currentTime < ... { %>
Login failed, try again
<% } %>
Code Example 10.23 login.jsp
• Abandoning signin
Sometimes the login.jsp page comes up because the user tried to access
a protected resource. If the user does not have an account and needs to create
one, the application should abandon the login process and start user signup
instead.
The pet store application’s login.jsp page has an additional button called
New User, to let new users sign up before they attempt to sign in.
The J2EE platform maintains information about the state of the signin in
SECURITY 305
the HttpSession and times it out when the login attempt is abandoned.
• Treating newly created users as signed in
When a new user signs up they should be treated as signed in for the dura-
tion of that session. This is the case for the sample application, which man-
ages its own set of users. However, in the J2EE architecture, this is not the
case. The only way users can sign in is through form-based authentication.
Since form-based authentication is not invoked when a user signs up, they still
need to explicitly sign in in order to be treated as an authenticated user.
The sample application uses a non-portable, private API provided by the
J2EE SDK to achieve the desired results.
• Detecting user login
The form-based authentication mechanism is designed to be transparent.
However there are cases where we want to be aware of the first request that
the user makes after they have signed in. For example, in the sample applica-
tion, the fetching and caching of user profile information is triggered when the
user logs in.
Since the POST to the login form is processed by the platform, there is no
direct way of doing this. We use the code shown in Code Example 10.24.
RequestProcessor detects when the user logs in and fires a LoginEvent which
can then be handled to get the desired effect.
private void checkForWebServerLogin(HttpServletRequest req) {
if ((req.getUserPrincipal() != null) &&
!req.getUserPrincipal().getName().equals("guest") &&
!mm.getAccountModel().isLoggedIn()) {
EStoreEvent loginEvent = null;
loginEvent = eventTranslator.createLoginEvent(req);
...
Code Example 10.24 Triggering the Login Event
Let’s look at the condition being tested. We first check if the principal is
set on the current call. If it is, it means that some user is currently logged in.
Next we check if our account bean knows about it. If accountBean.isLogge-
dIn returns false, it means that the account bean is not aware of the login yet.
This is exactly the condition when we want to trigger the login event. Once
CHAPTER 10 THE SAMPLE APPLICATION306
the login event is processed, account.isLoggedIn would return true.
Application Client Authentication
In the J2EE platform, stand-alone clients are authenticated by an application client
container. The application client may authenticate its user in a number of ways. The
techniques used are platform-dependent and not under control of the application
client. The application client container may integrate with the platform’s authentica-
tion system, providing a single signon capability. The application client container
may authenticate the user when the application is started. The application client con-
tainer may use lazy authentication, only authenticating the user when it needs to
access a protected resource. The J2EE specification does not describe the technique
used to authenticate the user.
The J2EE SDK generates a client JAR file1 when enterprise beans are
deployed. This library contains stub classes for accessing enterprise beans as well
as a mechanism provided by the J2EE SDK for handling authentication to an EJB
server.
Handling Unauthenticated Users
The sample application allows for anonymous, unauthenticated users to access the
application and browse selected features of the pet store. Even in such cases, calls to
the EJB tier must specify a valid principal; the EJB container rejects all calls without
a security principal. That is, if the user invokes a feature that tries to call the EJB tier
without authentication, the EJB container will not let the call go through.
However, since the Web interface needs to support anonymous, unauthenti-
cated users, the J2EE platform defines a mechanism to do so. The responsibility
for ensuring that unauthenticated calls are made using some principal is delegated
to the EJB client container. In the sample application, the Web container performs
this role by:
• Associating the credentials of a special user called guest2 to an unauthenticat-
1 This is specific to the J2EE SDK. Other J2EE products may provide other mechanisms to
create client JAR files.
2 We call it guest here. It may be called different things in different implementations. The
important thing to note however is that it is different from any valid user of the system
and is treated specially at deployment.
SECURITY 307
ed user when an EJB method is invoked.
• Treating unauthenticated users as follows:
■ The getUserPrincipal method of the servlet API returns null for such
users.
■ The form-based or other authentication mechanism will be activated when a
protected Web resource is accessed.
10.11.2.2 Authorization
Sample application security is specified in terms of the security roles customer and
gold_customer.
• A customer is a registered user of the application. Users in the customer role
can place orders and complete purchases. In the current release of the sample
application, the default user j2ee is in the customer role.
• A gold_customer is a customer with special privileges. Additional awards are
available to them. In the current release of the sample application, all users that
sign up are assigned to the gold_customer role.
By default, the J2EE SDK assigns the ANYONE role to an enterprise bean
method. The guest user, which is anonymous and unauthenticated, is assigned to
the ANYONE role.
In the sample application, access to the URLs /control/signin (described in
Section 10.11.2.1 on page 303) and /control/placeorder is restricted to the roles
customer and gold_customer. The security-constraint declaration for /con-
trol/signin is shown in Code Example 10.25.
...
/control/signin
POST
GET
no description
gold_customer
CHAPTER 10 THE SAMPLE APPLICATION308
customer
...
Code Example 10.25 Security Constraint Declaration
In the current release, the sample application does not limit enterprise bean
method invocation to specific security roles.
10.11.2.3 Confidentiality
Confidentiality constraints are specified at deployment time by setting the trans-
port-guarantee element in the Web component’s deployment descriptor to CONFI-
DENTIAL. In the current release, the sample application doesn’t demonstrate
confidentiality mechanisms.
10.11.2.4 User Administration
Many applications will need to perform two tasks that aren’t handled by the J2EE
platform: managing user profile information (other than security credentials and
attributes) and adding new users to the system dynamically.
Maintaining User Profiles
In addition to keeping security credentials, the sample application needs other infor-
mation about the user’s preferences and personalization. The J2EE security frame-
work will keep the security credentials, such as the user name and password, as well
as attributes such as the set of roles that the user belongs to. The sample application
needs another mechanism to maintain additional information for a user.
To do so, it maintains a separate relational table for user profile information.
This table is called the accounts table, and is accessed through the Account enter-
prise bean. The user name is unique for each sample customer, and we use it as a
key to the accounts database. Code Example 10.26 shows how the getCaller-
Principal method is used to retrieve the userId of the user making the current
enterprise bean method call. The value returned from this method is used as a key
to retrieve profile information for the user.
SECURITY 309
public Account getAccount() {
if (acct == null) {
try {
String userId = sc.getCallerPrincipal().getName();
AccountHome home = EJBUtil.getAccountHome();
acct = home.findByPrimaryKey(userId);
} catch (FinderException fe) {
...
} catch (RemoteException re) {
throw new EJBException (re);
}
}
return acct;
}
Code Example 10.26 ShoppingClientControllerEJB.getAccount
Adding New Users
The J2EE platform does not standardize a mechanism to add users dynamically to
applications. Any application that requires this feature needs to do so in a non-porta-
ble, container-specific manner.
In such a situation, it makes sense to isolate all the non-portable code in one
place. This small piece of platform-specific code can later be replaced if the appli-
cation needs to be ported to a different container implementation.
The J2EE SDK provides a container-specific API for managing users based
on the concept of realms. A realm is a collection of users under the same authenti-
cation policy. An application can provide its own realm and plug it into the J2EE
SDK for the container to use for authentication, or it can use realm API methods
such addUser, on the existing default J2EE realm.
The sample application uses the default J2EE realm. It uses the addUser
method of the realm to add new users while processing the signup.jsp form.
In addition to specifying the user name and password of the user being added,
we also need to specify the roles that this new user can assume. This is achieved
through the addUser method, which takes an array of roles as an argument.
CHAPTER 10 THE SAMPLE APPLICATION310
10.11.2.5 Programmatic Security
The J2EE platform encourages the use of declarative security. However there are
places where one needs to make access control decisions based on the current state
of the system. Such decisions must be made by programmatically encoding their
rules in the application.
The J2EE platform allows the application to identify the principal making the
call as well as the role that the caller is in, in both the Web and EJB tiers. The
sample application uses these facilities as follows.
Web Tier
In the Web tier, the sample application uses the getUserPrincipal and the isUse-
rInRole methods as follows:
• getUserPrincipal: This method is used to get the ID of the user that connects
to the application. This user ID could be used in the template to print the user
ID in the banner as part of a welcome message. Another way that the sample
application uses this information is to determine if a user is logged in. Code
Example 10.24 illustrates this use.
• isUserInRole: In the current release, the sample application doesn’t use this
method. This method could be used in the template in order to show a different
icon based on whether the user is a preferred or a regular customer. Addition-
ally, there might be special items that we only show to preferred customers.
Thus the catalog can be filtered based on the result returned from calling this
method with the gold_customer role.
EJB Tier
In the EJB tier, the sample application uses getCallerPrincipal and isCallerIn-
Role methods as follows:
• getCallerPrincipal: This method is used to get the caller key to be able to ac-
cess profile information associated with the principal associated with the call.
• isCallerInRole: This method is used by the order processing module to en-
force award rules based on whether the customer is a preferred customer. Code
Example 10.27 illustrates the use of isCallerInRole.
SECURITY 311
private int getBonusMiles() {
int miles = (totalPrice >= 100) ? 1000 : 500;
if (context.isCallerInRole("GOLD_CUSTOMER"))
miles += 1000;
return miles;
}
Code Example 10.27 OrderEJB.getBonusMiles
Notice the use of the embedded role name GOLD_CUSTOMER. When role names
are embedded in the code, the Application Component Provider needs to identify
these roles in a deployment descriptor so that the Deployer can ensure that they
are mapped correctly when the application is deployed. Code Example 10.28
shows the portions of the sample application deployment descriptor where this
happens.
GOLD_CUSTOMER
gold_customer
...
gold_customer
...
Code Example 10.28 Deployment Descriptor Element for Embedded Roles
In this excerpt from the deployment descriptor, the Application Component
Provider declares the use of GOLD_CUSTOMER in the application using the security-
role-ref element. The Deployer must ensure that this role is linked to the
gold_customer security role.
CHAPTER 10 THE SAMPLE APPLICATION312
10.12 Summary
This chapter illustrates the J2EE programming model in the context of an in-depth
description of a multitier Web application: the pet store e-commerce application.
The functionality of the sample application was determined using a scenario-
driven approach. Walks through scenarios illustrated the requirements for the user
interaction as well as the interactions that happen within the system. Analysis of
the sample application identified three very different kinds of interactions: a shop-
ping interface that allows shoppers to buy items online, an administration inter-
face for carrying out store administration activities, and a business-to-business
interface through which the store can interact with suppliers. The discussions in
this chapter focused mainly on the shopping interactions.
The architecture of the sample application partitions its functionality into mod-
ules, assigns functionality to tiers, and decomposes the modules into specific objects
to represent the behavior and data of the application. The principles guiding the
architecture include reuse of software designs and code, separation of stable from
volatile code, object decomposition along skill lines, and ease of migration from a
Web-centric to EJB-centric model.
The sample application adapts the Model-View-Controller architecture to the
domain of enterprise applications. The model represents the application data and
the business rules that govern access and modification of this data. The view
renders the contents of a model. It accesses data from the model and specifies how
that data should be presented. The controller defines application behavior; it inter-
prets user gestures and maps them into actions to be performed by the model. In a
stand-alone GUI client, these user gestures could be button clicks or menu selec-
tions. In a Web application, they appear as GET and POST HTTP requests to the
Web tier. Based on the user gesture and the outcome of the model commands, the
controller selects a view to be rendered as part of the response to this user request.
The J2EE platform provides system services that simplify the work that appli-
cation objects need to perform. The sample application uses the Java 2 SDK,
Enterprise Edition support for distributed transactions across multiple JDBC data-
bases. In addition, it uses deployment and security capabilities of the J2EE plat-
form to support customers with different profiles.
313
Afterword
THIS book has presented an overview of application design and development
with the Java 2 Platform, Enterprise Edition. It’s goal has been to introduce enter-
prise developers to the concepts and technology used in designing applications for
the J2EE platform, and to give a practical example of a typical enterprise applica-
tion.
While this book explores many of the key decisions to be made in the applica-
tion development process, it is necessarily limited in scope. The J2EE Blueprints
program is intended to expand on this effort. It’s goal is to provide developers
using the J2EE platform with ongoing help in designing applications that best use
the architecture and features of the platform.
The J2EE Blueprints program will include a Web site, additional publications
in various venues, and ultimately, additional books in the Addison-Wesley Java
Series. For the latest information on designing enterprise applications with the
Java 2 Platform, Enterprise Edition, be sure to regularly check the J2EE Blue-
prints Web site at http://java.sun.com/j2ee/blueprints.
Your comments on this book and your requests for coverage of additional
topics are important to the success of the J2EE Blueprints program. Please send
your feedback to j2eeblueprints-feedback@sun.com.
AFTERWORD314
315
Glossary
access control The methods by which interactions with resources are limited to
collections of users or programs for the purpose of enforcing integrity, confi-
dentiality, or availability constraints.
ACID The acronym for the four properties guaranteed by transactions: atomicity,
consistency, isolation, and durability.
activation The process of transferring an enterprise bean from secondary storage
to memory. (See passivation.)
applet A component that typically executes in a Web browser, but can execute in a
variety of other applications or devices that support the applet programming
model.
applet container A container that includes support for the applet programming
model.
Application Component Provider A vendor that provides the Java classes that
implement components’ methods, JSP page definitions, and any required
deployment descriptors.
Application Assembler A person that combines components and modules into
deployable application units.
application client A first-tier client component that executes in its own Java vir-
tual machine. Application clients have access to some (JNDI, JDBC, RMI-
IIOP, JMS) J2EE platform APIs.
application client container A container that supports application client compo-
nents.
application client module A software unit that consists of one or more classes
and an application client deployment descriptor.
authentication The process by which an entity proves to another entity that it is
acting on behalf of a specific identity. The J2EE platform requires three types
of authentication: basic, form-based, and mutual, and supports digest authen-
tication.
GLOSSARY316
authorization See access control.
authorization constraint An authorization rule that determines who is permitted
to access a Web resource collection.
basic authentication An authentication mechanism in which a Web server
authenticates an entity with a user name and password obtained using the Web
client’s built-in authentication mechanism.
bean-managed persistence When the transfer of data between an entity bean
instance’s variables and the underlying resource manager is managed by the
entity bean.
bean-managed transaction When an enterprise bean defines the boundaries of
the transaction.
business logic The code that implements the functionality of an application. In the
Enterprise JavaBeans model, this logic is implemented by the methods of an
enterprise bean.
business method A method of an enterprise bean that implements the business
logic or rules of an application.
callback methods Methods in a component called by the container to notify the
component of important events in its life cycle.
caller Same as caller principal.
caller principal The principal that identifies the invoker of the enterprise bean
method.
client certificate authentication An authentication mechanism in which a client
uses a X.509 certificate to establish its identity.
commit The point in a transaction when all updates to any resources involved in
the transaction are made permanent.
component An application-level software unit supported by a container. Compo-
nents are configurable at deployment time. The J2EE platform defines four
types of components: enterprise beans, Web components, applets, and appli-
cation clients.
component contract The contract between a component and its container. The
contract includes: life cycle management of the component, a context inter-
GLOSSARY 317
face that the instance uses to obtain various information and services from its
container, and a list of services that every container must provide for its com-
ponents.
connection See resource manager connection.
connection factory See resource manager connection factory.
connector A standard extension mechanism for containers to provide connectiv-
ity to enterprise information systems. A connector is specific to an enterprise
information system and consists of a resource adapter and application devel-
opment tools for enterprise information system connectivity. The resource
adapter is plugged in to a container through its support for system-level con-
tracts defined in the connector architecture.
Connector architecture An architecture for integration of J2EE products with
enterprise information systems. There are two parts to this architecture: a
resource adapter provided by an enterprise information system vendor and the
J2EE product that allows this resource adapter to plug in. This architecture
defines a set of contracts that a resource adapter has to support to plug in to a
J2EE product, for example, transactions, security, and resource management.
container An entity that provides life cycle management, security, deployment,
and runtime services to components. Each type of container (EJB, Web, JSP,
servlet, applet, and application client) also provides component-specific ser-
vices.
container-managed persistence When transfer of data between an entity bean’s
variables and the underlying resource manager is managed by the enterprise
bean’s container.
container-managed transaction When an EJB container defines the boundaries
of a transaction. An entity bean must use container-managed transactions.
context attribute An object bound into the context associated with a servlet.
conversational state The field values of a session bean plus the transitive closure
of the objects reachable from the bean’s fields. The transitive closure of a bean
is defined in terms of the serialization protocol for the Java programming lan-
guage, that is, the fields that would be stored by serializing the bean instance.
CORBA Common Object Request Broker Architecture. A language independent,
distributed object model specified by the Object Management Group.
GLOSSARY318
create method A method defined in the home interface and invoked by a client to
create an enterprise bean.
credentials The information describing the security attributes of a principal.
CTS Compatibility Test Suite. A suite of compatibility tests for verifying that a
J2EE product complies with the J2EE platform specification.
delegation An act whereby one principal authorizes another principal to use its
identity or privileges with some restrictions.
Deployer A person who installs modules and J2EE applications into an opera-
tional environment.
deployment The process whereby software is installed into an operational envi-
ronment.
deployment descriptor An XML file provided with each module and application
that describes how they should be deployed. The deployment descriptor
directs a deployment tool to deploy a module or application with specific con-
tainer options and describes specific configuration requirements that a
Deployer must resolve.
digest authentication An authentication mechanism in which a Web client
authenticates to a Web server by sending the server a message digest along its
HTTP request message. The digest is computed by employing a one-way hash
algorithm to a concatenation of the HTTP request message and the client’s
password. The digest is typically much smaller than the HTTP request, and
doesn’t contain the password.
distributed application An application made up of distinct components running
in separate runtime environments, usually on different platforms connected
via a network. Typical distributed applications are two-tier (client-server),
three-tier (client-middleware-server), and multitier (client-multiple middle-
ware-multiple servers).
DOM Document Object Model. A tree of objects with interfaces for traversing
the tree and writing an XML version of it, as defined by the W3C specifica-
tion.
DTD Document Type Definition. A description of the structure and properties of a
class of XML files.
GLOSSARY 319
EAR file A JAR archive that contains a J2EE application.
EJBTM See Enterprise JavaBeans.
EJB container A container that implements the EJB component contract of the
J2EE architecture. This contract specifies a runtime environment for enter-
prise beans that includes security, concurrency, life cycle management, trans-
action, deployment, naming, and other services. An EJB container is provided
by an EJB or J2EE server.
EJB Container Provider A vendor that supplies an EJB container.
EJB context An object that allows an enterprise bean to invoke services provided
by the container and to obtain the information about the caller of a client-
invoked method.
EJB home object An object that provides the life cycle operations (create,
remove, find) for an enterprise bean. The class for the EJB home object is
generated by the container’s deployment tools. The EJB home object imple-
ments the enterprise bean’s home interface. The client references an EJB
home object to perform life cycle operations on an EJB object. The client uses
JNDI to locate an EJB home object.
EJB JAR file A JAR archive that contains an EJB module.
EJB module A software unit that consists of one or more enterprise beans and an
EJB deployment descriptor.
EJB object An object whose class implements the enterprise bean’s remote inter-
face. A client never references an enterprise bean instance directly; a client
always references an EJB object. The class of an EJB object is generated by
the container’s deployment tools.
EJB server Software provides services to an EJB container. For example, an EJB
container typically relies on a transaction manager that is part of the EJB
server to perform the two-phase commit across all the participating resource
managers. The J2EE architecture assumes that an EJB container is hosted by
an EJB server from the same vendor, so does not specify the contract between
these two entities. An EJB server may host one or more EJB containers.
EJB Server Provider A vendor that supplies an EJB server.
GLOSSARY320
enterprise bean A component that implements a business task or business entity
and resides in an EJB container; either an entity bean or a session bean.
enterprise information system The applications that comprise an enterprise’s
existing system for handling company-wide information. These applications
provide an information infrastructure for an enterprise. An enterprise informa-
tion system offers a well defined set of services to its clients. These services
are exposed to clients as local and/or remote interfaces. Examples of enter-
prise information systems include: enterprise resource planning systems,
mainframe transaction processing systems, and legacy database systems.
enterprise information system resource An entity that provides enterprise infor-
mation system-specific functionality to its clients. Examples are: a record or
set of records in a database system, a business object in an enterprise resource
planning system, and a transaction program in a transaction processing sys-
tem.
Enterprise Bean Provider An application programmer who produces enterprise
bean classes, remote and home interfaces, and deployment descriptor files,
and packages them in an EJB .jar file.
Enterprise JavaBeansTM (EJBTM) A component architecture for the development
and deployment of object-oriented, distributed, enterprise-level applications.
Applications written using the Enterprise JavaBeans architecture are scalable,
transactional, and secure.
entity bean An enterprise bean that represents persistent data maintained in a
database. An entity bean can manage its own persistence or it can delegate
this function to its container. An entity bean is identified by a primary key. If
the container in which an entity bean is hosted crashes, the entity bean, its pri-
mary key, and any remote references survive the crash.
finder method A method defined in the home interface and invoked by a client to
locate an entity bean.
form-based authentication An authentication mechanism in which a Web con-
tainer provides an application-specific form for logging in.
group A collection of principals within a given security policy domain.
handle An object that identifies an enterprise bean. A client may serialize the han-
dle, and then later deserialize it to obtain a reference to the enterprise bean.
GLOSSARY 321
home interface One of two interfaces for an enterprise bean. The home interface
defines zero or more methods for creating and removing an enterprise bean.
For session beans, the home interface defines create and remove methods,
while for entity beans, the home interface defines create, finder, and remove
methods.
home handle An object that can be used to obtain a reference of the home inter-
face. A home handle can be serialized and written to stable storage and deseri-
alized to obtain the reference.
HTML Hypertext Markup Language. A markup language for hypertext docu-
ments on the Internet. HTML enables the embedding of images, sounds,
video streams, form fields, references to other objects with URLs and basic
text formatting.
HTTP Hypertext Transfer Protocol. The Internet protocol used to fetch hypertext
objects from remote hosts. HTTP messages consist of requests from client to
server and responses from server to client.
HTTPS HTTP layered over the SSL protocol.
impersonation An act whereby one entity assumes the identity and privileges of
another entity without restrictions and without any indication visible to the
recipients of the impersonator’s calls that delegation has taken place. Imper-
sonation is a case of simple delegation.
IDL Interface Definition Language. A language used to define interfaces to
remote CORBA objects. The interfaces are independent of operating systems
and programming languages.
IIOP Internet Inter-ORB Protocol. A protocol used for communication between
CORBA object request brokers.
initialization parameter A parameter that initializes the context associated with
a servlet.
ISV Independent Software Vendor.
J2EETM Java 2, Enterprise Edition.
J2METM Java 2, Micro Edition.
J2SETM Java 2, Standard Edition.
GLOSSARY322
J2EE application Any deployable unit of J2EE functionality. This can be a single
module or a group of modules packaged into an .ear file with a J2EE applica-
tion deployment descriptor. J2EE applications are typically engineered to be
distributed across multiple computing tiers.
J2EE product An implementation that conforms to the J2EE platform specifica-
tion.
J2EE Product Provider A vendor that supplies a J2EE product.
J2EE server The runtime portion of a J2EE product. A J2EE server provides Web
and/or EJB containers.
JAR Java ARchive A platform-independent file format that permits many files to
be aggregated into one file.
JavaTM 2 Platform, Standard Edition (J2SE platform) The core Java technol-
ogy platform.
JavaTM 2 Platform, Enterprise Edition (J2EE platform) An environment for
developing and deploying enterprise applications. The J2EE platform consists
of a set of services, application programming interfaces (APIs), and protocols
that provide the functionality for developing multitiered, Web-based applica-
tions.
JavaTM 2 SDK, Enterprise Edition (J2EE SDK) Sun’s implementation of the
J2EE platform. This implementation provides an operational definition of the
J2EE platform.
JavaTM Message Service (JMS) An API for using enterprise messaging systems
such as IBM MQ Series, TIBCO Rendezvous, and so on.
Java Naming and Directory InterfaceTM (JNDI) An API that provides naming
and directory functionality.
JavaTM Transaction API (JTA) An API that allows applications and J2EE serv-
ers to access transactions.
JavaTM Transaction Service (JTS) Specifies the implementation of a transaction
manager which supports JTA and implements the Java mapping of the OMG
Object Transaction Service (OTS) 1.1 specification at the level below the API.
GLOSSARY 323
JavaBeansTM component A Java class that can be manipulated in a visual builder
tool and composed into applications. A JavaBeans component must adhere to
certain property and event interface conventions.
Java IDL A technology that provides CORBA interoperability and connectivity
capabilities for the J2EE platform. These capabilities enable J2EE applica-
tions to invoke operations on remote network services using the OMG IDL
and IIOP.
JavaMailTM An API for sending and receiving email.
JavaServer PagesTM (JSP) An extensible Web technology that uses template
data, custom elements, scripting languages, and server-side Java objects to
return dynamic content to a client. Typically the template data is HTML or
XML elements, and in many cases the client is a Web browser.
JDBCTM An API for database-independent connectivity between the J2EE plat-
form and a wide range of data sources.
JMS See Java Message Service.
JNDI See Java Naming and Directory Interface.
JSP See JavaServer Pages.
JSP action A JSP element that can act on implicit objects and other server-side
objects or can define new scripting variables. Actions follow the XML syntax
for elements with a start tag, a body and an end tag; if the body is empty it can
also use the empty tag syntax. The tag must use a prefix.
JSP action, custom An action described in a portable manner by a tag library
descriptor and a collection of Java classes and imported into a JSP page by a
taglib directive. A custom action is invoked when a JSP page uses a custom
tag.
JSP action, standard An action that is defined in the JSP specification and is
always available to a JSP file without being imported.
JSP application A stand-alone Web application, written using the JavaServer
Pages technology, that can contain JSP pages, servlets, HTML files, images,
applets, and JavaBeans components.
JSP container A container that provides the same services as a servlet container
and an engine that interprets and processes JSP pages into a servlet.
GLOSSARY324
JSP container, distributed A JSP container that can run a Web application that is
tagged as distributable and is spread across multiple Java virtual machines
that might be running on different hosts.
JSP declaration A JSP scripting element that declares methods, variables, or both
in a JSP file.
JSP directive A JSP element that gives an instruction to the JSP container and is
interpreted at translation time.
JSP element A portion of a JSP page that is recognized by a JSP translator. An
element can be a directive, an action, or a scripting element.
JSP expression A scripting element that contains a valid scripting language
expression that is evaluated, converted to a String, and placed into the implicit
out object.
JSP file A file that contains a JSP page. In the Servlet 2.2 specification, a JSP file
must have a .jsp extension.
JSP page A text-based document using fixed template data and JSP elements that
describes how to process a request to create a response.
JSP scripting element A JSP declaration, scriptlet, or expression, whose tag syn-
tax is defined by the JSP specification, and whose content is written according
to the scripting language used in the JSP page. The JSP specification
describes the syntax and semantics for the case where the language page
attribute is "java".
JSP scriptlet A JSP scripting element containing any code fragment that is valid
in the scripting language used in the JSP page. The JSP specification
describes what is a valid scriptlet for the case where the language page
attribute is "java".
JSP tag A piece of text between a left angle bracket and a right angle bracket that
is used in a JSP file as part of a JSP element. The tag is distinguishable as
markup, as opposed to data, because it is surrounded by angle brackets.
JSP tag library A collection of custom tags identifying custom actions described
via a tag library descriptor and Java classes.
JTA See Java Transaction API.
JTS See Java Transaction Service.
GLOSSARY 325
method permission An authorization rule that determines who is permitted to
execute one or more enterprise bean methods.
module A software unit that consists of one or more J2EE components of the
same container type and one deployment descriptor of that type. There are
three types of modules: EJB, Web, and application client. Modules can be
deployed as stand-alone units or assembled into an application.
mutual authentication An authentication mechanism employed by two parties
for the purpose of proving each other’s identity to one another.
ORB Object Request Broker. A library than enables CORBA objects to locate and
communicate with one another.
OS principal A principal native to the operating system on which the J2EE plat-
form is executing.
OTS Object Transaction Service. A definition of the interfaces that permit
CORBA objects to participate in transactions.
naming context A set of associations between distinct, atomic people-friendly
identifiers and objects.
naming environment A mechanism that allows a component to be customized
without the need to access or change the component’s source code. A con-
tainer implements the component’s naming environment, and provides it to
the component as a JNDI naming context. Each component names and
accesses its environment entries using the java:comp/env JNDI context. The
environment entries are declaratively specified in the component’s deploy-
ment descriptor.
passivation The process of transferring an enterprise bean from memory to sec-
ondary storage. (See activation.)
persistence The protocol for transferring the state of an entity bean between its
instance variables and an underlying database.
POA Portable Object Adapter. A CORBA standard for building server-side appli-
cations that are portable across heterogeneous ORBs.
principal The identity assigned to an user as a result of authentication.
privilege A security attribute that does not have the property of uniqueness and
that may be shared by many principals.
GLOSSARY326
primary key An object that uniquely identifies an entity bean within a home.
realm See security policy domain. Also, a string, passed as part of an HTTP
request during basic authentication, that defines a protection space. The pro-
tected resources on a server can be partitioned into a set of protection spaces,
each with its own authentication scheme and/or authorization database.
re-entrant entity bean An entity bean that can handle multiple simultaneous,
interleaved, or nested invocations which will not interfere with each other.
Reference Implementation See Java 2 SDK, Enterprise Edition.
remote interface One of two interfaces for an enterprise bean. The remote inter-
face defines the business methods callable by a client.
remove method Method defined in the home interface and invoked by a client to
destroy an enterprise bean.
resource adapter A system-level software driver that is used by an EJB container
or an application client to connect to an enterprise information system. A
resource adapter is typically specific to an enterprise information system. It is
available as a library and is used within the address space of the server or cli-
ent using it. A resource adapter plugs in to a container. The application com-
ponents deployed on the container then use the client API (exposed by
adapter) or tool generated high-level abstractions to access the underlying
enterprise information system. The resource adapter and EJB container col-
laborate to provide the underlying mechanisms—transactions, security, and
connection pooling—for connectivity to the enterprise information system.
resource manager Provides access to a set of shared resources. A resource man-
ager participates in transactions that are externally controlled and coordinated
by a transaction manager. A resource manager is typically in different address
space or on a different machine from the clients that access it. Note: An enter-
prise information system is referred to as resource manager when it is men-
tioned in the context of resource and transaction management.
resource manager connection An object that represents a session with a resource
manager.
resource manager connection factory An object used for creating a resource
manager connection.
GLOSSARY 327
RMI Remote Method Invocation. A technology that allows an object running in
one Java virtual machine to invoke methods on an object running in a different
Java virtual machine.
RMI-IIOP A version of RMI implemented to use the CORBA IIOP protocol.
RMI over IIOP provides interoperability with CORBA objects implemented
in any language if all the remote interfaces are originally defined as RMI
interfaces.
role (development) The function performed by a party in the development and
deployment phases of an application developed using J2EE technology. The
roles are: Application Component Provider, Application Assembler,
Deployer, J2EE Product Provider, EJB Container Provider, EJB Server Pro-
vider, Web Container Provider, Web Server Provider, Tool Provider, and Sys-
tem Administrator.
role (security) An abstract logical grouping of users that is defined by the Appli-
cation Assembler. When an application is deployed, the roles are mapped to
security identities, such as principals or groups, in the operational environ-
ment.
role mapping The process of associating the groups and/or principals recognized
by the container to security roles specified in the deployment descriptor. Secu-
rity roles have to be mapped by the Deployer before the component is
installed in the server.
rollback The point in a transaction when all updates to any resources involved in
the transaction are reversed.
SAX Simple API for XML. An event-driven, serial-access mechanism for access-
ing XML documents.
security attributes A set of properties associated with a principal. Security
attributes can be associated with a principal by an authentication protocol and/
or by a J2EE Product Provider.
security constraint A declarative way to annotate the intended protection of Web
content. A security constraint consists of a Web resource collection, an autho-
rization constraint, and a user data constraint.
security context An object that encapsulates the shared state information regard-
ing security between two entities.
GLOSSARY328
security permission A mechanism, defined by J2SE, used by the J2EE platform
to express the programming restrictions imposed on Application Component
Providers.
security permission set The minimum set of security permissions that a J2EE
Product Provider must provide for the execution of each component type.
security policy domain A scope over which security policies are defined and
enforced by a security administrator. A security policy domain has a collec-
tion of users (or principals), uses a well defined authentication protocol(s) for
authenticating users (or principals), and may have groups to simplify setting
of security policies.
security role See role (security).
security technology domain A scope over which the same security mechanism is
used to enforce a security policy. Multiple security policy domains can exist
within a single technology domain.
security view The set of security roles defined by the Application Assembler.
server principal The OS principal that the server is executing as.
servlet A Java program that extends the functionality of a Web server, generating
dynamic content and interacting with Web clients using a request-response
paradigm.
servlet container A container that provides the network services over which
requests and responses are sent, decodes requests, and formats responses. All
servlet containers must support HTTP as a protocol for requests and
responses, but may also support additional request-response protocols such as
HTTPS.
servlet container, distributed A servlet container that can run a Web application
that is tagged as distributable and that executes across multiple Java virtual
machines running on the same host or on different hosts.
servlet context An object that contains a servlet’s view of the Web application
within which the servlet is running. Using the context, a servlet can log
events, obtain URL references to resources, and set and store attributes that
other servlets in the context can use.
GLOSSARY 329
servlet mapping Defines an association between a URL pattern and a servlet. The
mapping is used to map requests to servlets.
session An object used by a servlet to track a user’s interaction with a Web appli-
cation across multiple HTTP requests.
session bean An enterprise bean that is created by a client and that usually exists
only for the duration of a single client-server session. A session bean per-
forms operations, such as calculations or accessing a database, for the client.
While a session bean may be transactional, it is not recoverable should a sys-
tem crash occur. Session bean objects can be either stateless or they can main-
tain conversational state across methods and transactions. If a session bean
maintains state, then the EJB container manages this state if the object must
be removed from memory. However, the session bean object itself must man-
age its own persistent data.
SSL Secure Socket Layer. A security protocol that provides privacy over the Inter-
net. The protocol allows client-server applications to communicate in a way
that cannot be eavesdropped or tampered with. Servers are always authenti-
cated and clients are optionally authenticated.
SQL Structured Query Language. The standardized relational database language
for defining database objects and manipulating data.
SQL/J A set of standards that includes specifications for embedding SQL state-
ments in methods in the Java programming language and specifications for
calling Java static methods as SQL stored procedures and user-defined func-
tions. An SQL checker can detects errors in static SQL statements at program
development time, rather than at execution time as with a JDBC driver.
stateful session bean A session bean with a conversational state.
stateless session bean A session bean with no conversational state. All instances
of a stateless session bean are identical.
System Administrator The person responsible for configuring and administering
the enterprise’s computers, networks, and software systems.
transaction An atomic unit of work that modifies data. A transaction encloses one
or more program statements, all of which either complete or roll back. Trans-
actions enable multiple users to access the same data concurrently.
GLOSSARY330
transaction attribute A value specified in an enterprise bean’s deployment
descriptor that is used by the EJB container to control the transaction scope
when the enterprise bean’s methods are invoked. A transaction attribute can
have the following values: Required, RequiresNew, Supports, NotSupported,
Mandatory, Never.
transaction isolation level The degree to which the intermediate state of the data
being modified by a transaction is visible to other concurrent transactions and
data being modified by other transactions is visible to it.
transaction manager Provides the services and management functions required
to support transaction demarcation, transactional resource management, syn-
chronization, and transaction context propagation.
Tool Provider An organization or software vendor that provides tools used for the
development, packaging, and deployment of J2EE applications.
URI Uniform Resource Identifier. A compact string of characters for identifying
an abstract or physical resource. A URI is either a URL or a URN. URLs and
URNs are concrete entities that actually exist; A URI is an abstract superclass.
URL Uniform Resource Locator. A standard for writing a textual reference to an
arbitrary piece of data in the World Wide Web. A URL looks like "protocol://
host/localinfo" where "protocol" specifies a protocol for fetching the object
(such as HTTP or FTP), "host" specifies the Internet name of the targeted
host, and "localinfo" is a string (often a file name) passed to the protocol han-
dler on the remote host.
URL path The URL passed by a HTTP request to invoke a servlet. The URL con-
sists of the Context Path + Servlet Path + PathInfo, where Context Path is the
path prefix associated with a servlet context that this servlet is a part of. If this
context is the default context rooted at the base of the Web server’s URL
namespace, the path prefix will be an empty string. Otherwise, the path prefix
starts with a / character but does not end with a / character. Servlet Path is the
path section that directly corresponds to the mapping which activated this
request. This path starts with a / character. PathInfo is the part of the request
path that is not part of the Context Path or the Servlet Path.
URN Uniform Resource Name. A unique identifier that identifies an entity, but
doesn’t tell where it is located. A system can use a URN to look up an entity
GLOSSARY 331
locally before trying to find it on the Web. It also allows the Web location to
change, while still allowing the entity to be found.
user data constraint Indicates how data between a client and a Web container
should be protected. The protection can be the prevention of tampering with
the data or prevention of eavesdropping on the data.
WAR file A JAR archive that contains a Web module.
Web application An application written for the Internet, including those built
with Java technologies such as JavaServer Pages and servlets, as well as those
built with non-Java technologies such as CGI and Perl.
Web application, distributable A Web application that uses J2EE technology
written so that it can be deployed in a Web container distributed across multi-
ple Java virtual machines running on the same host or different hosts. The
deployment descriptor for such an application uses the distributable ele-
ment.
Web component A component that provides services in response to requests;
either a servlet or a JSP page.
Web container An entity that implements the Web component contract of the
J2EE architecture. This contract specifies a runtime environment for Web
components that includes security, concurrency, life cycle management, trans-
action, deployment, and other services. A Web container provides the same
services as a JSP container and a federated view of the J2EE platform APIs. A
Web container is provided by a Web or J2EE server.
Web container, distributed A Web container that can run a Web application that
is tagged as distributable and that executes across multiple Java virtual
machines running on the same host or on different hosts.
Web Container Provider A vendor that supplies a Web container.
Web module A unit that consists of one or more Web components and a Web
deployment descriptor.
Web resource collection A list of URL patterns and HTTP methods that describe
a set of resources to be protected.
Web server Software that provides services to access the Internet, an intranet, or
an extranet. A Web server hosts Web sites, provides support for HTTP and
GLOSSARY332
other protocols, and executes server-side programs (such as CGI scripts or
servlets) that perform certain functions. In the J2EE architecture, a Web
server provides services to a Web container. For example, a Web container
typically relies on a Web server to provide HTTP message handling. The
J2EE architecture assumes that a Web container is hosted by a Web server
from the same vendor, so does not specify the contract between these two
entities. A Web server may host one or more Web containers.
Web Server Provider A vendor that supplies a Web server.
XML eXtensible Markup Language. A markup language that allows you to define
the tags (markup) needed to identify the data and text in XML documents.
J2EE deployment descriptors are expressed in XML.
333
Index
A
applets 26
accessing a UserTransaction 35
deploying 58
security 59
session management 59
transactions 202
application clients 19, 26
accessing a UserTransaction 35
client of EJB tier 61
client of Web tier 60
deployment 188
transactions 202
application scenarios 14
business-to-business 20
multitier 16
sample application 242–247
stand-alone client 18
Web-centric 19
archive files
EAR 168
EJB JAR 169
JAR 46
WAR 172
auditing 237
authentication 37–38, 216
basic 38, 220
call patterns 223
client certificate 38
configuration 221
context 216
delegating 217
digest 38, 220
EIS resource 224
application-managed 224
container-managed 224
form-based 38, 221
configuration 186
sample application 303
lazy 220
mechanisms 220
mutual 216, 221
role of references 225
sample application 303–306
scenarios 218
authenticators 216
authorization 37, 39, 225
consistency across components 228
declarative versus programmatic 228
enterprise information systems 161
example 232
programmatic 227
auto-registration 225
B
basic authentication
See authentication, basic.
business logic 114
business objects 113
controlling access to 117
implemented by enterprise beans 118
maintaining state 115
operating on shared data 116
participation in transactions 116
remote accessibility 117
requirements of 115–117
reusability 117
servicing multiple clients 116
C
CGI 77
class files 46
client certificate authentication
See authentication, client certificate.
client tier 6
clients
EIS. See enterprise information systems,
clients.
EJB. See EJB clients.
INDEX334
impact of deployment mechanisms 52
impact of host platform 52
impact of network service 50
impact of programming language 53
impact of security constraints 51
operating environment 50
overview 53
supporting multiple types 68
types 54
Visual Basic
See Visual Basic clients.
Web. See Web clients.
Common Gateway Interface 77
components 25
applets 26
application clients 26
EJB 28
enterprise beans 28
portability 10
Web 26
confidentiality mechanisms 235
connection factory references 180
data source 159
mail session 181
connections
See enterprise information systems,
connections.
Connector architecture 41, 161
containers 26
applet 26
APIs 29
application client 26
APIs 29
EJB 28
APIs 29
JSP 27
platform configuration 8
servlet 27
Web 27
APIs 29
credentials 218
D
data access objects 130, 276
as migration path to container-managed
persistence 133
clarifying session bean implementa-
tions 131
example 131
generated by tools 133
providing database portability 133
sample application 276
dependent objects 134, 276
deployment descriptors 33, 174
application 34
application client 34
auth-constraint element 230
common elements 176
component 34
container-transaction element 184
EJB 34
ejb-link element 179
ejb-name element 179
ejb-ref element 178, 225
ejb-ref-name element 179
ejb-ref-type element 179
env-entry element 176
error-page element 186
login-config element 186, 221
method-permission element 39, 183, 232
persistence-type element 184
res-auth element 159, 181, 224
resource-ref element 180, 224–225
res-type element 181
sample application 300
security-constraint element 186, 230
security-role element 182
security-role-ref element 182, 228
servlet element 185
servlet-mapping element 185
transport-guarantee element 222, 308
versioning 193
Web 34
deployment tools
features
name collision management 193
name space management 193
remote accessibility 192
single point of entry 191
undeployment capability 192
vendor-specific information 189
requirements 187
digest authentication
See authentication, digest.
INDEX 335
dynamic content generators
Active Server Pages 67
CGI scripts 77
JSP pages 78
servlets 77
E
EAR files 168
EJB clients 18, 61
advantages 63
deployment 62
disadvantages 64
protocols 61
security 63
transactions 62
EJB components
See enterprise beans.
EJB containers 118
EJB JAR files 169
EJB tier 6
EJBHome 119
EJBObject 120
email
sending from enterprise bean 298
enterprise applications
development challenges 3
enhancing application developer
productivity 3
ensuring choice in servers, tools, and
components 5
ensuring scalability 4
integrating with information
systems 5
maintaining security 5
enterprise beans 28, 118
accessing a UserTransaction 35
appropriate uses of 130
as COM objects 65
class 120
client view 119
implementation 121
create methods 120
deployment 187
EntityBean 120
finder methods 120
home interface 119
operations 119
implementing business objects 118
instances
creating 119
obtaining handles to 120
removing 119
master-detail relationships
implementing the master 137
modeling 136
obtaining a handle to home interface 119
packaging into EJB JAR files 170
by related functionality 171
by security profile 172
interrelated 172
with circular dependencies 172
portability 118
protected 223
protecting 231
references 177–180
remote interface 120
operations 120
sample application 275
See also entity beans.
See also session beans.
service information decoupled from
implementation 119
SessionBean 120
transaction attributes
See transaction attributes.
transactions 203–207
types 28, 118
enterprise information system tier 6
enterprise information systems 141
access objects 151
examples 152
guidelines 152
scenarios 153
accessing 146
authorization 161
capabilities 142
client API 149
clients 67
connections
establishing 154
life cycle 155
managing 155
managing by component type 156
INDEX336
Connector architecture 161
integration
role of tools 150
security architecture 157
integration scenarios 143
distributed purchasing applica-
tion 145
employee self-service applica-
tion 144
e-store application 143
limitations 142
relational databases
accessing with JDBC 146
multiple concurrent connections 156
resource signon 158
application-managed 160
container-managed 159
transactions
JTA 208
resource manager local 209
using 208
Enterprise JavaBeans (EJB)
architecture 28, 118
See also enterprise beans.
entity beans 28, 121
bean-managed persistence 124
characteristics 122
container-managed persistence 125
example 123
instances
finding 120
obtaining primary key 120
lifetime 122
persistence 124
sample application 275
state after system crash 122
error pages
invoking automatically 186
F
form-based authentication
See authentication, form-based.
front components 80–81
H
HTML 45, 55
HTTP 42
properties 55
I
identity selection 229
IDL 43
idlj compiler 43
image files 46
impersonation 216
integrity mechanisms 234
internationalization 88
data handling 89
data input 89
data storage 90
locale-independent data format-
ting 90
J
J2EE applications 34, 168
deployment tasks 187
EJB-centric 96
packaging and deployment activities 165
scenarios
See application scenarios.
supporting multiple types of clients 68
Web-centric 96
J2EE Blueprints
program 313
programming model 2
J2EE Compatibility Test Suite 9
J2EE Developer’s Guide xix
J2EE environment 6
J2EE platform 6
as complement to EJB architecture 9
benefits 10
choice in servers, tools, and
components 13
enhanced application development
productivity 11
integration with enterprise
information systems 12
INDEX 337
scalability 12
simplified security model 14
communication technologies 41
component technologies 25
data formats 45
database API 40
deployment services 33
email API 45
Internet protocols 42
messaging API 44
messaging technologies 44
naming and directory API 40
naming services 33
OMG protocols 43
remote object method invocation API 42
role of containers 7
saving application state 274
security services 37
service technologies 39
Standard Extension APIs 29
support for business logic 9
support for component portability 10
support for multiple client types 8
transaction API 40
transaction services 35
J2EE roles 30
Application Assembler 31
Application Component Provider 31
Deployer 32
J2EE Product Provider 31
packaging and deployment tasks 165–168
System Administrator 32
Tool Provider 32
J2EE SDK 9
J2EE specifications xix, 9
JAF (JavaBeans Activation Framework) 45
JAR files 46
Java IDL 43
Java Message Service (JMS) 44
Java Naming and Directory Interface
(JNDI) 40
Java Remote Method Protocol (JRMP) 42
Java Transaction API (JTA) 40, 201
Java Transaction Service (JTS) 40, 201
JavaBeans Activation Framework (JAF) 45
JavaBeans components, in JSP pages 86
JavaMail 45
JavaServer Pages (JSP) technology 27, 78
See also JSP pages.
JDBC 40
JMS (Java Message Service) 44
JNDI (Java Naming and Directory
Interface) 40
JRMP (Java Remote Method Protocol) 42
JSP pages 27, 78
as front components 81
as presentation components 82
custom tags 86–87
designing 85
error pages 186
expressions 88
JavaBeans components 86
locale-specific 94–96
page directive 88, 95
presentation components
sample application 266
scriptlets 88
tag libraries 86
taglib directive 86
templates 83
sample application 260
versus servlets 85
JTA (Java Transaction API) 40
JTA transactions
See transactions, JTA.
JTS (Java Transaction Service) 40
L
locales 88
localization 89
localized content
delivering 92
list resource bundles 92–94
locale-specific JSP pages 94–96
M
message digests 234
message signatures 234
messages
ensuring privacy of 235
preventing tampering 234
INDEX338
security threats 234
messaging
point-to-point 44
publish-subscribe 44
middle tier 6
modules
application client 34
packaging 174
EJB 34
contents 169
packaging 169
J2EE 34
types 34
Web 34
contents 172
packaging 172
mutual authentication
See authentication, mutual.
MVC architecture 21
Controller 22
in EJB-centric applications 104–107
multiple clients 69
sample application
See sample application,
Controller.
in EJB-centric applications 103
Model 21
in EJB-centric applications 104
multiple clients 68
sample application 273–278
sample application 21, 254–255
Model-View synchronization 294
support for mutiple types of clients 68
View 22
in EJB-centric applications 104
multiple clients 69
sample application 255–273
N
naming contexts 33
environment 33, 178
naming environments 33
entries 176
naming subcontexts 33
ejb 33, 177
jdbc 33, 180
mail 180
P
portability
affected by use of transactions 199
component 10
enterprise bean 118
presentation components 80, 82
principal mapping 224
principals 37
protection domains 217
R
references
connection factory 180
data source 159
mail session 181
enterprise bean 177–180
resources
protected 230
unprotected 231
RMI 42
rmic compiler 43
RMI-IIOP 43
S
sample application
adding users 309
Controller 280–283
EJB tier 281
implementation 282–296
interaction between objects 281
ModelManager 294
ModelUpdateManager 296
RequestProcessor 284
RequestToEventTrans-
lator 285
ScreenFlowManager 293
ShoppingClientController-
EJB 288
ShoppingClientController-
WebImpl 287
INDEX 339
StateMachine 289
Web tier 281
data access objects 276
deployment descriptors 300
design goals 253
email, sending from enterprise bean 298
enterprise beans 275
enterprise requirements 15
entity beans 275
functional specification 247
functionality 242
HTTPSession 274
JSP pages
cart.jsp 269
index.jsp 266
Main.jsp 283
presentation components 266
productcategory.jsp 267
ScreenDefinitions.jsp 264
template 260
template.jsp 261–264
insert tag 262, 264
Model 273–278
Model-View synchronization 294
modules 248, 250
MVC architecture 21, 254–255
obtaining xviii
persistent data 277
relationships between business objects 280
saving state 273
scenarios 242
administration 245
business-to-business 246
shopping 242
screens 256–258
home 266
product category 267
selecting 264
shopping cart 269
security APIs 310
use in EJB tier 310
use in Web tier 310
security implementation
authentication 303–306
confidentiality 308
handling unauthenticated users 306
user administration 308–309
security requirements
authorization 302
confidentiality 302
user administration 302
user authentication 302
ServletContext 274
session beans
stateful 275
stateless 275
signing in 301
signing up 301
stateless services 298
transactions 300
user interface
shopping interaction 256–258
user profiles, maintaining 308
View 255–273
security
accessor components 229
attacks on messages 234
attributes 226
capabilities 226
declarative 38
mechanisms 216
auditing 237
authentication 216
authorization 225
confidentiality 235
integrity 234
mutual authentication 216
See also authentication.
See also authorization.
permissions 226
principal mapping 224
programmatic 38
protection domains 217
roles 39, 227
mapping to group identities 227
mapping to principal identities 227
sample application 307
sample application 301–311
threats to 215
servlets 26, 77
as front components 81
as presentation components 82
limitations of embedded HTML 79
used to extend Web server 85
used to generate binary data 84
versus JSP pages 85
INDEX340
session beans 28, 125
as facade to entity beans 135
stateful 126
characteristics 126
example 127
lifetime 126
sample application 275
stateless 128
characteristics 128
example 129
sample application 275
SSL 42
T
TCP/IP 42
tiers
client 6
EJB 6
enterprise information system 6
middle 6
Web 6
transaction attributes 205
assigning 184
for entity beans 205
for session beans 205
guidelines 207
Mandatory 206
Never 206
NotSupported 206
Required 205
RequiresNew 206
Supports 206
transactions 35, 197
ACID properties 197
applets 202
application clients 202
attributes
See transaction attributes.
compensating 210
pitfalls 211
creating 35
demarcation
bean-managed 37, 204
container-managed 37, 204
benefits of 205
guidelines 207
enterprise beans 36, 203–207
setRollbackOnly 205
enterprise informations systems 208
isolation level 212
guidelines 212
J2EE platform
characteristics 198
scenarios 199
J2EE SDK 198
JTA 35, 200
benefits 201
properties 197
atomicity 197
consistency 197
durability 198
isolation 197
resource manager local 35, 209
Web components 36, 202
U
UserTransaction
accessing 35
from applets 35
from application clients 35
from enterprise beans 35
from Web components 36
V
value objects 134, 276
example 134
immutability 135
properties 134
used to conserve system resources 134
Visual Basic clients 19, 65
limitations 66
W
WAR files 172
Web applications 75
types 96
Web clients
INDEX 341
applets 58
See also applets.
browsers 58
content format 55
plug-ins 59
stand-alone 60
Java 60
non-Java 61
transport protocols 55
types 57
Web components 26, 75
accessing a UserTransaction 36
as front components 80–81
as presentation components 80, 82
deployment 188
limitations on transactions 36
packaging into WAR files 173
cross-dependent servlets 173
cross-linked static content 173
roles 80
using transactions 202
Web containers 76
Web resources 220
confidentiality across absolute links 236
confidentiality across relative links 237
protected 220
protecting 230
Web tier 6
X
XML 17, 20, 46, 56
guidelines 57
Matthew Scarpino
Stephen Holder
Stanford Ng
Laurent Mihalkovic
M A N N I N G
SWT/JFace
IN ACTION
How to design graphical applications with Eclipse 3.0
SWT/JFace
in Action
MATTHEW SCARPINO
STEPHEN HOLDER
STANFORD NG
AND LAURENT MIHALKOVIC
M A N N I N G
Greenwich
(74° w. long.)
For online information and ordering of this and other Manning books, please go to
www.manning.com. The publisher offers discounts on this book when ordered in quantity.
For more information, please contact:
Special Sales Department
Manning Publications Co.
209 Bruce Park Avenue Fax: (203) 661-9018
Greenwich, CT 06830 email: orders@manning.com
©2005 by Manning Publications Co. All rights reserved.
No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
in any form or by means electronic, mechanical, photocopying, or otherwise, without
prior written permission of the publisher.
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in the book, and Manning
Publications was aware of a trademark claim, the designations have been printed in initial
caps or all caps.
Recognizing the importance of preserving what has been written, it is Manning’s policy to have
the books they publish printed on acid-free paper, and we exert our best efforts to that end.
Manning Publications Co. Copyeditor: Tiffany Taylor
209 Bruce Park Avenue Typesetter: Tony Roberts
Greenwich, CT 06830 Cover designer: Leslie Haimes
ISBN 1-932394-27-3
Printed in the United States of America
1 2 3 4 5 6 7 8 9 10 – VHG – 08 07 06 05 04
v
brief contents
1 ■ Overview of SWT and JFace 1
2 ■ Getting started with SWT and JFace 13
3 ■ Widgets: part 1 27
4 ■ Working with events 48
5 ■ More widgets 78
6 ■ Layouts 109
7 ■ Graphics 133
8 ■ Working with trees and lists 167
9 ■ Tables and menus 190
10 ■ Dialogs 212
11 ■ Wizards 234
12 ■ Advanced features 253
13 ■ Looking beyond SWT/JFace: the Rich Client Platform 284
vii
contents
preface xv
acknowledgments xvi
about this book xviii
about the authors xxiii
about the title xxiv
about the cover illustration xxv
1 Overview of SWT and JFace 11.1 What is SWT/JFace? 2
Building GUIs with SWT 3
Simplifying GUI development with JFace 3
1.2 Looking under the hood 4
The old standby: Swing 4 ■ The newcomer: SWT/JFace 6
The SWT/Swing debate 9
1.3 SWT/JFace: licensing and platform support 9
The Common Public License 9 ■ Platforms supported 9
1.4 The WidgetWindow 11
1.5 Summary 12
viii CONTENTS
2 Getting started with SWT and JFace 132.1 Programming in SWT 14
The HelloSWT program 14 ■ The Display class 16
The Shell class 18
2.2 Programming in SWT/JFace 20
Model-based adapters 20 ■ The HelloSWT_JFace program 21
Coding in JFace and SWT/JFace 23
The ApplicationWindow class 23
2.3 Beginning the WidgetWindow application 24
2.4 Summary 26
3 Widgets: part 1 273.1 Introducing the Widget and Control classes 28
Understanding the Widget class 28
Working with Control objects 30
3.2 Labels 32
Styles and separators 33 ■ Label methods 33
3.3 Involving the user with buttons 34
Causing action with push buttons and SWT.PUSH 34
Moving on with arrow buttons and SWT.ARROW 35
Changing state with toggle buttons and
SWT.TOGGLE 35 ■ Choosing with check buttons
and SWT.CHECK 36 ■ Making a single choice with
radio buttons and SWT.RADIO 36
3.4 Containing components with Composites 38
Understanding the Composite class 39 ■ Groups 40
SashForms 43 ■ TabFolders 44
3.5 Updating WidgetWindow 45
Creating the Ch3_Composite class 45
Creating the WidgetWindow TabFolder 46
3.6 Summary 47
CONTENTS ix
4 Working with events 484.1 Event processing in SWT 49
Using typed listeners and events 50 ■ Adapters 54
Keyboard events 55 ■ Customizing event processing with untyped
events 58 ■ An SWT listener/event application 60
4.2 Event processing in JFace 62
Understanding actions and contributions 63 ■ Creating Action
classes 65 ■ Implementing contributions in an
ApplicationWindow 66 ■ Interfacing with contributions 69
Exploring the Action class 70
4.3 Updating the WidgetWindow 74
Building the chapter 4 Composite 74
Adding Ch4_Composite to the WidgetWindow 75
4.4 Summary 77
5 More widgets 785.1 Editing text with SWT 79
The basic Text widget 79 ■ The StyledText widget 82
5.2 JFace text support 88
Obtaining the JFace text packages 88 ■ TextViewer and
Document 89 ■ A JFace example 91
5.3 The Combo widget 100
5.4 ToolBarManager 101
ControlContribution 102 ■ Creating toolbars by hand 103
5.5 CoolBar 103
5.6 Slider 105
5.7 ProgressBar 106
5.8 ProgressIndicator 107
5.9 Summary 108
x CONTENTS
6 Layouts 1096.1 The fill layout 110
6.2 The row layout 112
Customizing individual layout cells 114
6.3 The grid layout 116
GridData 117
6.4 The form layout 119
Using FormData 120 ■ Specifying relations using
FormAttachment 120 ■ Laying out controls using a form layout 122
6.5 Custom layouts 124
Calculating the layout’s size 125 ■ Laying out the widgets 126
Updating WidgetWindow 128
6.6 Summary 132
7 Graphics 1337.1 The graphic context 134
Creating a GC object 134 ■ Drawing shapes on a Canvas 136
Painting and PaintEvents 138
Clipping and Canvas styles 139
7.2 Programming with colors 140
Color development with SWT 140
Additional color capability with JFace 144
7.3 Displaying text with fonts 145
Using fonts with SWT 145 ■ Coding with fonts 148
Improved font management with JFace 150
7.4 Incorporating images in graphics 152
Allocating images 152 ■ Coding graphics with images 154
Creating a bitmap with ImageData 155 ■ Manipulating images
with ImageData 159 ■ Managing images with JFace 163
7.5 Updating the WidgetWindow 164
Building the chapter 7 composite 164
Adding Ch7_Composite to the WidgetWindow 165
7.6 Summary 166
CONTENTS xi
8 Working with trees and lists 1678.1 Viewers and the Viewer framework 168
Providers 170 ■ Listeners 172 ■ Filters and sorters 173
8.2 Trees 176
SWT trees 176 ■ JFace TreeViewers 177
8.3 Using the List widget 180
SWT lists 180 ■ JFace ListViewers 181
8.4 Updating WidgetWindow 182
8.5 Summary 189
9 Tables and menus 1909.1 Tables 191
Understanding SWT tables 191 ■ JFace TableViewers 194
9.2 Creating menus 200
Accelerator keys 201 ■ Creating menus in SWT 201
Using JFace actions to add to menus 204
9.3 Updating WidgetWindow 205
9.4 Summary 211
10 Dialogs 21210.1 SWT dialogs 213
ColorDialog 213 ■ DirectoryDialog 214 ■ FileDialog 215
FontDialog 216 ■ MessageBox 216
10.2 JFace dialogs 218
Message dialogs 219 ■ Error dialogs 220 ■ Input
dialogs 222 ■ Progress monitor dialogs 224
Custom dialogs 228
10.3 Updating WidgetWindow 230
10.4 Summary 233
11 Wizards 23411.1 Multipage dialogs 236
IDialogPage 236 ■ IWizardPage 237 ■ WizardPage 237
xii CONTENTS
11.2 The wizard 239
IWizard 239 ■ Wizard 240
11.3 Putting it all together 241
Wizard containers 241 ■ WizardDialog 242
11.4 Combining wizards 243
WizardSelectionPage 243 ■ IWizardNode 244
11.5 Persistent wizard data 244
DialogSettings 245
11.6 Updating WidgetWindow 246
11.7 Summary 252
12 Advanced features 25312.1 Transferring data 254
The Transfer class 255 ■ Drag-and-drop capability 256
Using the clipboard 261 ■ The filesystem browser 262
12.2 Preferences 268
Preference pages 268 ■ Field editors 270 ■ Preference page
containers 273 ■ Persistent preferences 274
12.3 Label decorators 276
ILabelDecorator 276 ■ DecoratingLabelProvider 277
An example 277
12.4 The Browser widget 280
12.5 Summary 283
13 Looking beyond SWT/JFace: the Rich Client Platform 28413.1 Understanding RCP workbenches 285
Entering data with editors 285 ■ Displaying information with
views 287 ■ Combining editors and views with perspectives 288
13.2 RCP: Looking under the hood 288
Creating and configuring an RCP project 288 ■ Building the
application class 290 ■ Adding a WorkbenchAdvisor 291
13.3 Adding views and perspectives 294
Building views 294 ■ Arranging workbench windows with a
perspective 295 ■ Executing an RCP application 296
Reviewing the RCP process 297
CONTENTS xiii
13.4 Populating forms with Eclipse Forms widgets 299
Using FormToolkit and the Eclipse Forms containers 299
Firing text-based events with Hyperlinks 302
13.5 Building a standalone RCP application 306
Exporting RCPExample to an application directory 306
Adding plug-ins to the application directory 307
Executing the application 308
13.6 Summary 308
appendix A Creating projects with SWT/JFace 311
appendix B OLE and ActiveX in SWT/JFace 324
appendix C Changeable GUIs with Draw2D 362
appendix D The Graphical Editing Framework (GEF) 388
index 461
xv
preface
We developed this book with one primary goal in mind: to introduce the SWT and
JFace toolsets as simply and as thoroughly as possible. Although the available doc-
umentation covers many aspects of the two libraries, we were disappointed by the
amount (particularly in graphics) that has gone undocumented. So, we came
together in late 2003 to create an approachable book that covers both the high-level
theory and the low-level details of the combined SWT/JFace development tools.
Thanks to the hard work of the folks at eclipse.org, SWT and JFace have
recently received quite a bit of attention and debate within the Java community.
Most of this discussion has focused on the relative merits of Swing as a standard
component of the Java 2 platform, versus SWT as a nonstandard library that uses
native code—an approach foreign to the “write once run anywhere” mantra
embraced by most Java developers. Although Swing has many strengths, we
believe that SWT and JFace together provide a compelling alternative for develop-
ing the user interface of many types of applications.
We wrote this book not only for Swing developers but also for new Java users
who want to build applications that reach beyond the command line. Toward this
end, we present code samples and also do our best to explain the general theories
behind graphical user interface construction. In particular, we’ve gone into great
depth concerning the Model-View-Controller paradigm, which greatly improves
both the reliability and maintainability of graphical applications.
Our goal is to share our SWT experience with you, help you decide if SWT and
JFace make sense for your project, and help you to make effective use of these
technologies.
xvi
acknowledgments
The authors would like to acknowledge and thank the people who made this book
a reality:
First, we'd like to express our appreciation to Marjan Bace, publisher of Man-
ning, for this opportunity, and to his staff, Clay Andres, Susan Capparelle, and
Dave Roberson, for their support throughout the process. Our heartfelt thanks go
to Jacquelyn Carter, our beleaguered and ever-patient developmental editor who
put up with all our whining and last-minute changes. We particularly want to rec-
ognize the hard work put in by the production team: Mary Piergies, Tiffany Tay-
lor, and Tony Roberts. Their efforts have provided the professionalism and polish
that has kept this book to its high production standard.
Next, we want to extend our sincere appreciation to our diligent reviewers: Phil
Hanna, Christophe Avare, Frank Jania, Ted Neward, Dan Dobrin, Ryan Lowe,
Steve Gutz, Carl Hume, Ed Burnette, Charles Bundy, and Robert McGovern. Their
feedback and encouragement helped us tremendously and in many cases guided
the direction of the book’s content. We’re particularly grateful for the technical
reviewing of Phil Hanna. There’s nothing worse than a programming book with
poor code, and his exacting tests ensured that our code will work as promised.
We also want to thank the Eclipse.org community in general. Not only have
they produced a quality product, but this book wouldn’t be possible without their
dedication to technical support. Their programmers have promptly and thor-
oughly answered our many questions, and their documentation has provided a
great deal of assistance. Of course, we’re also indebted to the Eclipse developers
ACKNOWLEDGMENTS xvii
for making their code open source, thereby giving us the means to look under the
hood and discover exactly how the SWT/JFace mechanisms function.
Finally, we’d like to thank you for purchasing our book. We hope you enjoy it
as much as we’ve enjoyed creating it, and we wish you the best of luck coding with
SWT/JFace!
xviii
about this book
This book is written with the intermediate to advanced Java programmer in mind.
We assume that you’re familiar with the basics of Java syntax and comfortable con-
sidering design alternatives where there may not be a single choice that is supe-
rior in all situations.
Having some experience with developing graphical applications, whether in
Java or any other language, will be helpful but isn’t necessary. We define all terms
as they’re introduced and attempt to point out the purpose behind each widget as
well as discuss the technical details of how to use it. However, this isn’t a book
about user interface design, so we won’t attempt to cover the myriad details that
go into assembling a compelling user experience out of the widgets we present.
We assume that most readers have some experience with Swing, but such expe-
rience isn’t necessary to fully enjoy this book. We attempt to draw comparisons to
Swing where we feel that doing so imparts additional understanding for Swing vet-
erans, but these comparisons are secondary to the main discussion of each topic.
We have made sure you can understand every topic in this book without having
programmed a single line of Swing code.
Roadmap
This book is structured around the development of a sample application—the
Widget Window—that shows off the details of each component included in SWT
and JFace. The application consists of a series of tabs, one for each chapter. At the
end of each chapter, we present code that you can drop into the overall project to
ABOUT THIS BOOK xix
add another tab. Where the initial chapters develop the foundation of the appli-
cation, the code for the later chapters can stand on its own without needing that
from the preceding chapters. We hope this approach lets you focus on the topics
that are of particular interest to you, using the framework of the Widget Window
application to play with the code and see the effects of different parameters on
each component.
Beyond a general introduction to the tools, we cover several specific aspects of
SWT/JFace:
■ The relationship between SWT and JFace—When you first approach these two
libraries, it’s difficult to know when to use one over the other, or why JFace
exists. We explain the seeming redundancies between the two libraries and
demonstrate the trade-offs in coding with one or the other.
■ Rules of thumb concerning GUI development—Having used these tools exten-
sively, we’ve found a number of routines that simplify the process of creat-
ing GUIs. We’ve also encountered a number of places where SWT/JFace’s
operation differs from its documentation. In each case, we provide explana-
tions and practical examples to help you avoid these pitfalls and create reli-
able SWT/JFace applications.
■ Cross-platform development—Between SWT and JFace, you can find many dif-
ferent ways to build the same user interface. However, some methods trans-
late well across operating systems, and some don’t. Throughout this book,
we present screenshots on multiple windowing platforms to show you how
your application will appear.
■ Practical code examples—When we came up with the example code in this
book, we held two priorities in mind: We kept them concise, for hands-on
readers; and we made them modular, so you can use them in SWT/JFace
applications you build in the future.
■ Toolsets that build on SWT/JFace—We’re excited to present the first thorough
walkthrough of the Draw2D and Graphical Editor Framework (GEF)
toolsets. These libraries, which build on the capabilities of SWT and JFace,
greatly extend the power and flexibility of GUI design.
Chapter 1, “Overview,” presents the history of SWT and JFace and places these tech-
nologies in context. We present an overview of the history of graphical user inter-
face development using Java and discuss the organization of the various classes
and packages within SWT and JFace.
Chapter 2, “Getting started with SWT/JFace,” shows you how to set up a project to
use SWT and JFace, either within the Eclipse IDE or as a standalone project built
xx ABOUT THIS BOOK
from the command line. After showing how to implement a traditional “Hello
World” application using SWT and JFace, we introduce the basic framework on
which the Widget Window will be built.
Chapter 3, “Widgets: part 1,” discusses the inheritance hierarchy used by the SWT
and JFace classes. We also discuss several concepts common to all widgets within
SWT and show how to use some basic, common widgets such as buttons and labels.
Chapter 4, “Working with events,” explains how to enable your application to
react appropriately when the user takes an action such as clicking a button on the
screen. We show the details of low-level event classes in both SWT and JFace and
discuss the higher-level Action framework that makes handling events easier.
Chapter 5, “More widgets,” dives back in to the discussion of individual compo-
nents provided by SWT. Most important, we discuss how to let users edit text
within your application, and we cover a variety of useful widgets that are often
used in user interfaces.
Chapter 6, “Layouts,” takes a break from the details of individual widgets to dis-
cuss ways to organize widgets on the screen. After covering the built-in layout
managers provided by SWT, we show how to create a custom layout manager if the
default ones don’t meet the needs of your application.
Chapter 7, “Graphics,” covers low-level SWT facilities for drawing graphics by
hand. In addition, we show how to programmatically manipulate colors, fonts,
and images from within SWT.
Chapter 8, “Working with trees and lists,” introduces the Viewer framework, a set
of classes and interfaces provided by JFace to make working with data easier. We
use this discussion of viewers and their related classes to show you how to easily
work with tree and list widgets.
Chapter 9, “Tables and menus,” continues the Viewer framework discussion from
chapter 8 and includes several advanced features of the framework. We show how
these features enable you to create tables that users can easily and intuitively edit.
The chapter ends with a discussion of menus and how they tie into the action
classes from chapter 4.
Chapter 10, “Dialogs,” covers ways to create dialog boxes in both SWT and JFace.
We discuss the dialog boxes provided by SWT and JFace and show how to create
your own dialogs when necessary.
Chapter 11, “Wizards,” shows how to use the framework provided by JFace to
create a wizard that guides the user through a series of steps.
Chapter 12, “Advanced features,” covers a variety of miscellaneous features. These
are important topics to understand in order to fully master SWT and JFace, but
they aren’t essential to get a basic application running. We discuss subjects such as
ABOUT THIS BOOK xxi
implementing drag and drop, interacting with the operating system’s clipboard,
and embedding a web browser in your application.
Chapter 13, “Looking beyond SWT/JFace: the Rich Client Platform,” shows how to
build custom workbench applications that contain editors and views. In addi-
tion, this chapter presents the new Eclipse Forms toolset for designing form-like
applications.
Appendix A, “Creating projects with SWT/JFace,” shows how set up a Java project
that uses SWT and JFace. Specifically, it covers how to find the necessary libraries
and set up common IDEs such as Eclipse.
Appendix B, “OLE and ActiveX in SWT/JFace,” covers facilities provided by SWT for
integrating with the Windows operating system. Obviously, the techniques we dis-
cuss in this appendix are relevant only to developers willing to tie themselves closely
to one operating system; as such, they may not be of interest to some readers.
Appendix C, “Changeable GUIs with Draw2D,” shows a framework you can use to
create custom widgets for use in SWT. We cover the creation of a custom widget
used in appendix D.
Appendix D, “The Graphical Editing Framework (GEF),” covers the most complicated
topic in this book and requires knowledge of almost every aspect of JFace as well as
the Eclipse Workbench. GEF is a powerful framework that you can use to create to
create powerful graphical editors for your applications. This appendix uses the cus-
tom widget developed in appendix C to create a flowchart editor application.
If you have any questions or concerns about our content, visit the www.man-
ning.com/scarpino web site. From there, we can answer questions and provide
further explanations. We also provide our example code for download.
Conventions
Throughout this book, the text follows certain conventions. Method and variable
names appear in monotype font in the text. Code snippets that illustrate a tech-
nique in context without necessarily covering every detail required to get the
code to compile are also presented in monotype font, as are full code listings. Any
code listing (preceded by a “Listing X.Y” header) can be typed in, compiled, and
run as is.
We also present several UML diagrams in this book. These diagrams are in the
spirit of what Martin Fowler refers to as “UML as sketch”—they aren’t full-blown,
comprehensive diagrams that cover every member variable and private method of
the classes in question. Rather, they’re intended to convey essential information
about the relationship between certain classes and interfaces at a high level. The
text and code samples around each diagram discuss the low-level details necessary
to make effective use of the classes presented in the diagrams.
xxii ABOUT THIS BOOK
Source code downloads
Source code for the programming examples in this book is available for download
from the publisher's web site at www.manning.com/scarpino.
Author Online
Purchase of SWT/JFace in Action includes free access to a private web forum run by
Manning Publications where you can make comments about the book, ask techni-
cal questions, and receive help from the authors and from other users. To access
the forum and subscribe to it, point your web browser to www.manning.com/scar-
pino. This page provides information on how to get on the forum once you are
registered, what kind of help is available, and the rules of conduct on the forum.
Manning's commitment to our readers is to provide a venue where a meaning-
ful dialog between individual readers and between readers and the authors can
take place. It is not a commitment to any specific amount of participation on the
part of the authors, whose contribution to the AO remains voluntary (and
unpaid). We suggest you try asking the authors some challenging questions lest
their interest stray!
The Author Online forum and the archives of previous discussions will be
accessible from the publisher's web site as long as the book is in print.
xxiii
about the authors
MATT SCARPINO has more than 10 years of software design and engineering experi-
ence. He uses Eclipse to build editing software for reconfigurable computing and
has submitted code for Eclipse’s graphical library. He lives in Fort Worth, Texas.
STEPHEN HOLDER is a software engineer who has worked as a consultant for several
large commercial and government agencies on enterprise-level Java projects,
including writing Eclipse plug-ins to streamline the development process. He cur-
rently resides in Tustin, California.
STANFORD NG is the cofounder of Nuglu, LLC and is currently working on improv-
ing back-end systems at Automotive.com, a top-5 automotive e-commerce site. He
is also a co-conspirator with Dr. Robert Nideffer behind the International award-
winning Proxy/MAM research project. He lives in Irvine, California.
LAURENT MIHALKOVIC is a technology consultant with 10 years’ experience design-
ing solutions in C/C++/Java/COM. He currently lives between Vancouver and
Toronto, Canada.
xxiv
about the title
By combining introductions, overviews, and how-to examples, the In Action books
are designed to help learning and remembering. According to research in cogni-
tive science, the things people remember are things they discover during self-
motivated exploration.
Although no one at Manning is a cognitive scientist, we are convinced that for
learning to become permanent it must pass through stages of exploration, play,
and, interestingly, retelling of what is being learned. People understand and
remember new things, which is to say they master them, only after actively explor-
ing them. Humans learn in action. An essential part of an In Action guide is that it
is example-driven. It encourages the reader to try things out, to play with new
code, and to explore new ideas.
There is another, more mundane, reason for the title of this book: our readers
are busy. They use books to do a job or to solve a problem. They need books that
allow them to jump in and jump out easily and learn just what they want just when
they want it. They need books that aid them in action. The books in this series are
designed for such readers.
xxv
about the cover illustration
The figure on the cover of SWT/JFace in Action is a "Femme Patagonne," a woman
from Patagonia, an area of breathtaking natural beauty in the southern regions of
Argentina and Chile. From the towering tips of the Andes to the sweeping vistas of
the central plains to the pristine beaches on both coasts, Patagonia is a land of
stark contrasts. Sparsely populated even today, it has become the ultimate destina-
tion for modern-day adventurers.
The illustration is taken from a French travel book, Encyclopedie des Voyages by
J. G. St. Saveur, published in 1796. Travel for pleasure was a relatively new phe-
nomenon at the time and travel guides such as this one were popular, introducing
both the tourist as well as the armchair traveler to inhabitants of faraway places.
The diversity of the drawings in the Encyclopedie des Voyages speaks vividly of the
uniqueness and individuality of the world’s towns and provinces just 200 years
ago. This was a time when the dress codes of two regions separated by a few dozen
miles identified people uniquely as belonging to one or the other. The travel
guide brings to life a sense of isolation and distance of that period and of every
other historic period except our own hyperkinetic present.
Dress codes have changed since then and the diversity by region, so rich at the
time, has faded away. It is now often hard to tell the inhabitant of one continent
from another. Perhaps, trying to view it optimistically, we have traded a cultural
and visual diversity for a more varied personal life. Or a more varied and interest-
ing intellectual and technical life.
xxvi ABOUT THE COVER ILLUSTRATION
We at Manning celebrate the inventiveness, the initiative, and the fun of the
computer business with book covers based on the rich diversity of regional life two
centuries ago brought back to life by the pictures from this travel guide.
1
Overview of SWT
and JFace
This chapter covers
■ The purpose of SWT and JFace
■ The reasons for their creation
■ How the two libraries differ from Swing
■ Licensing and platform support
2 CHAPTER 1
Overview of SWT and JFace
In March 2004, the Java Developer’s Journal announced the results of its Readers’
Choice Award for Best Java Component. More than 15,000 developers voted for
one of many Java toolsets, including offerings from such established names as
Oracle and Apple. But in the end, Eclipse’s Standard Widget Toolkit (SWT) won
handily, just as it did in 2003. Despite their late entry into the field of Java develop-
ment, Eclipse and SWT have also won awards and recognition from JavaWorld,
JavaPro, and LinuxWorld.
This well-earned applause goes a long way in showing the impact these tools have
made on Java development. Java programmers around the world have embraced
the power and versatility of SWT and JFace, deploying new plug-ins and standalone
applications with each passing day. The goal of this book is to show you how this
toolset functions and how you can use these tools for your own applications.
In particular, you’ll be able to
■ Develop SWT/JFace-based applications with hands-on code examples
■ Create customized graphics with SWT’s built-in graphical context
■ Understand the structure and methodology behind the SWT/JFace API
■ Further your knowledge of GUI (graphical user interface) design
■ Build and deploy SWT/JFace applications for Eclipse and standalone usage
Most important, GUI development should be fun! No other branch of program-
ming provides the same satisfaction as watching a new graphical interface spring
to life. Therefore, we’ll intersperse the theory of SWT and JFace with example
code showing practical GUI development.
But before we start programming, we need to show you what this new technol-
ogy is all about and what tasks it will help you perform.
1.1 What is SWT/JFace?
Although we refer to SWT and JFace as tools or toolsets, they’re essentially software
libraries. They consist of packages that contain Java classes and interfaces. But
what makes these components so special is that you can combine them to form
GUIs. And not just any GUIs, either! Your applications will run quickly, make effec-
tive use of computer memory, and, like chameleons, assume the look and feel of
whichever Java-supported operating system they run on. No other GUI-building
library can say that.
Although SWT and JFace accomplish the same goal, they follow different phi-
losophies in creating user interfaces. Our favorite analogy involves automobile
What is SWT/JFace? 3
transmissions. SWT development is like using a standard transmission: It gives you
greater control and access to the system internals, but it’s more complicated to
use. JFace, on the other hand, resembles an automatic transmission: It does most
of the work for you, but you lose flexibility.
Of course, the truth is more complicated than any analogy. So, let’s investigate
these two libraries in greater depth.
1.1.1 Building GUIs with SWT
Every operating system contains a number of graphical components that make up
its default user interface. These include buttons, windows, menus, and everything
else you see on your computer screen. The goal of SWT is to give you, the Java pro-
grammer, direct access to these components so that you can configure and posi-
tion them however you like.
You don’t have to worry about the end user’s operating system. When you add
an SWT Button object to your application, it will look and act like a Windows but-
ton on Windows, a Macintosh button on Macintosh, and a Linux button on a
Linux system. Users will think that you wrote the GUI specifically for their
machines, and they’ll have no idea that you wrote the code only once using SWT.
In addition to graphical components, SWT also provides access to events. This
means you can keep track of what buttons your users have clicked and which
menu items they’ve selected. This powerful capability makes it possible to receive
and respond to nearly every form of user input, and we’ll spend a great deal of
time showing how this works.
Finally, if you want to add graphics to your application, SWT provides a large
set of tools for creating images, working with new fonts, and drawing shapes. This
feature not only allows you to build new graphics, but also lets you control how,
when, and where they’re displayed in your GUI. This book will show you how SWT
manages colors, drawings, fonts, and images, and will present a great deal of
example code.
SWT provides a wealth of capabilities for building user interfaces, but as you’ll
see in this book, the code can become lengthy and complex. For this reason, the
Eclipse designers built a second library for GUI development: JFace.
1.1.2 Simplifying GUI development with JFace
Rather than write the same SWT code over and over again, the designers of the
Eclipse Workbench created JFace. This library provides shortcuts around many of
the tasks that can be time-consuming using SWT alone. But JFace is not a replace-
ment for SWT, and many GUIs will need features from both toolsets.
4 CHAPTER 1
Overview of SWT and JFace
An important example of JFace’s increased efficiency involves events. In many
user interfaces, you may have different events, such as button clicks, keystrokes, or
menu selections, that all perform the same function. In SWT, each event needs to
be received and handled separately. But JFace allows you to combine them into a
single object, so you can concern yourself with the event’s response instead of the
component that triggered it. This simple but powerful concept makes it possible to
add context menus, toolbars, and palettes to your GUIs without adding a lot of code.
JFace is also helpful when you’re building large GUIs that require multiple win-
dows and graphics. It provides registry classes that help you organize SWT compo-
nents and manage their memory allocation. For example, in SWT, you need to
specifically create and deallocate every Font and Image in your application. But
with JFace, you can use built-in FontRegistry and ImageRegistry objects to take
care of these tedious concerns for you.
Now that you understand the basic characteristics behind these two libraries,
we need to dig a little deeper and show you the concepts behind their design.
This discussion will explain why SWT/JFace GUIs are so fast, why they can take the
appearance of whatever operating system they run on, and why they were created
in the first place.
1.2 Looking under the hood
Adding components, events, and graphics to a user interface isn’t a new idea.
Therefore, to see why the SWT/JFace toolset has caused such a stir, you need to
understand what its designers were thinking. This means investigating the princi-
ples behind Java GUI development and how these libraries make use of them.
But before we can investigate SWT/JFace in depth, we need to introduce
Swing. SWT and JFace were created in response to this library, and by understand-
ing the contrast between the two design philosophies, you’ll better appreciate
how SWT and JFace function. Further, in addition to recognizing the trade-offs
between Swing and SWT/JFace, you’ll be able to participate in the passionate
debates concerning the two.
1.2.1 The old standby: Swing
When Sun released the Swing library in 1998, the Java community was delighted.
Finally, Sun had backed up its “Write Once, Run Anywhere” credo with a toolset
capable of building platform-independent user interfaces. Swing quickly became
the most popular tool for creating GUIs in Java.
Looking under the hood 5
But as time went by, many developers became discontented. The qualities that
made Swing so attractive initially also made for complex development and slow
operation. For this reason, Java GUIs have found little use in desktop applications.
Swing rendering
In order to ensure consistent appearance and operation across operating systems,
Swing takes complete control of rendering its user interfaces. That is, the Java Vir-
tual Machine (JVM) specifies every pixel of its components and controls their
behavior. It still communicates with the underlying platform, but instead of using
the operating system’s prebuilt objects, it creates everything from scratch.
Because these components are implemented at a high level, they’re referred to
as lightweight components. These components look the same on any operating sys-
tem that supports the JVM. This cross-platform look-and-feel is shown graphically
in figure 1.1, and it looks and behaves identically whether it’s running on Win-
dows, Macintosh, or *nix platforms.
But this approach has drawbacks. Because the JVM micromanages every aspect
of the GUI’s appearance and behavior, the application runs more slowly than if it
relied on the operating system. Also, most users like the way their operating sys-
tem looks and prefer that their Java applications resemble their other platform-
specific (or native) applications.
Swing automatic garbage collection
Keeping with Java’s promise of reliable computing, Swing uses Java’s automatic
garbage collection (AGC) for its applications. This process spawns a thread, or dae-
mon, that runs beneath the application layer and deallocates memory for objects
that are no longer needed. It activates during program execution and functions
independently of the developer. AGC is an important capability: If programmers
don’t free their data, then other applications won’t be able to reclaim memory for
their objects.
The main advantage of AGC is that developers can concentrate on code design
instead of keeping track of every object’s lifetime. The downside involves the
unpredictable nature of the garbage-collection thread. The deallocation process
Figure 1.1
This application will act and appear
similarly on every platform supported
by Swing.
6 CHAPTER 1
Overview of SWT and JFace
leaves you no idea as to when it will take place. Also, AGC capabilities change from
one JVM to the next and from one platform to the next. Therefore, given the
time-intensive nature of creating and disposing objects within large applications,
programs may behave erratically from system to system.
Swing design architecture
Swing directs the GUI design process through an implementation of Model-View-
Controller (MVC) architecture. MVC decomposes a user interface component
into three parts: its state information, its displayed appearance, and its ability to
react to outside events. These aspects are called the Model, View, and Controller,
respectively. The Swing designers modified this methodology and created the
Model-Delegate architecture, shown in figure 1.2. This architecture combines the
component’s View and Controller aspects into a UI-Delegate. So, for each element
of the user interface—button, frame, and label—Swing allocates memory for a
model that contains the component’s state and the UI-Delegate, which controls its
appearance and response to events.
By separating model information from appearance, Swing provides a program-
ming methodology that ensures flexible, reusable code. But this capability also
produces multiple objects for each widget that appears on the screen. As GUIs
become more complex, this additional allocation and disposal can place a large
burden on the processor.
1.2.2 The newcomer: SWT/JFace
The designers of Eclipse responded strongly to Swing’s complexity and execution
issues. They wanted a tool that would enable a Java user interface to run on a
desktop with the same performance as a native application. In fact, they wanted it
so badly that they created their own libraries: SWT and JFace.
Model
holds state
information
UI-Delegate
Controller
reacts to input
View
provides display
Figure 1.2
The design architecture of Swing
GUIs. This diagram shows the
relationship between classic MVC
and Swing’s Model-Delegate
method.
Looking under the hood 7
Both Swing and SWT/JFace create Java-based, platform-independent GUIs. But
their methods differ in nearly every other respect.
SWT/JFace rendering
The most prominent aspect of SWT/JFace involves its direct access to the operat-
ing system. Rather than reinventing graphics for its GUIs, it uses heavyweight compo-
nents from the underlying platform. This decision makes possible the speed and
appearance of SWT/JFace user interfaces, as shown in figure 1.3.
The communication between SWT/JFace and the operating system is per-
formed using the Java Native Interface (JNI). We’ll explore this topic in greater
depth in the next chapter, but a short description here is helpful. Since the origi-
nal creators of Java knew that its applications would eventually need to access leg-
acy code and operating systems, they provided a library of methods to call
procedures in other languages (such as C and Fortran) from within a Java class.
SWT/JFace relies on JNI to manage the operating system’s rendering instead of
performing all the work by itself.
SWT/JFace resource management
Another important characteristic of SWT/JFace is that it doesn’t rely on automatic
garbage collection. At first, it may seem as though this will result in buggy code.
However, you need to be careful when accessing operating system resources, and
non-deterministic memory disposal can cause more problems than it solves.
There are two reasons behind Eclipse’s decision to remove AGC from SWT/JFace:
■ The process of automatically deallocating memory during program opera-
tion is unpredictable, giving no indication when a freed resource will be
Figure 1.3 Example Eclipse GUIs for Windows XP and Linux (GTK). By using heavyweight components,
they take the appearance of their host operating system.
8 CHAPTER 1
Overview of SWT and JFace
available. If an irregularity occurs during the deallocation process, the pro-
cess may not finish. This is a minor concern when you’re dealing with sim-
ple data structures. But when these objects make up a large graphical
application, memory allocation and deallocation become important tasks
whose behavior you should fully understand.
■ Using AGC with operating system resources is difficult. Since Swing builds
its lightweight components at such a high level, this isn’t as large a concern.
However, automatic disposal of low-level resources, such as SWT’s widgets, is
error-prone and erratic across different platforms. If these objects take too
much time to be deleted, the memory leaks can crash the program. Or, if
these resources are deallocated in the wrong order, then the system’s opera-
tion can grind to a halt.
To prevent the errors associated with automatic object disposal, SWT/JFace lets
you determine when your resources should be deallocated. The toolset simplifies
this process by providing dispose() methods within the component classes. Also,
once you have freed a parent resource, its child resources will automatically be
disposed of. As you’ll see in future chapters, this means that few explicit dealloca-
tion calls are necessary within most applications. You might call SWT/JFace’s
resource management semi-automatic.
Simplicity of design and development
GUI generation in Swing is performed with a Model-Delegate architecture, which
creates different objects to represent different aspects of the GUI components.
But this complexity isn’t suitable for all cases. Developers building simple button-
and-label interfaces, as well as those just ascending the learning curve, don’t need
this sophistication. At the other extreme, programmers building complex graphi-
cal editors and computer-aided design tools need more separation of GUI func-
tions in order to allow for different views and designs.
SWT and JFace make no rules regarding the design architecture of their com-
ponents. This means that you can build GUIs with as much sophistication or sim-
plicity as you prefer. Because Eclipse is easily extensible and the source code is
always available, you can add whatever tools or modifications you like. In fact, a
number of plug-ins have been developed to provide MVC wrappers for SWT/
JFace components.
SWT/JFace: licensing and platform support 9
1.2.3 The SWT/Swing debate
Any casual web search for SWT and Swing will bring up a number of heated argu-
ments regarding which toolset is superior. This controversy is unnecessary and coun-
terproductive. SWT was created as an alternative to Swing, not as a replacement.
Our goal in writing this section wasn’t to praise one tool over the other, but to
explain how and why they work. Infighting between Java developers can only
harm the effort to build freely available, platform-independent applications. The
world is big enough for both SWT and Swing, and we hope the two camps will be
able to put aside their differences and concentrate on improving the Java commu-
nity as a whole.
1.3 SWT/JFace: licensing and platform support
Before continuing with the code, we’d like to touch on two important concerns
regarding building applications with SWT/JFace. The first involves the lack of
strings attached to Eclipse and its development libraries, outlined in the Common
Public License. This is important, and you should understand it if you’re looking
to build commercial applications. The second concern deals with the platforms
currently supported by Eclipse in general and SWT/JFace in particular.
1.3.1 The Common Public License
The Eclipse consortium has released Eclipse to the public under the terms of the
Common Public License (CPL). This license is fully compliant with the Open
Source Initiative (OSI) licensing scheme and allows full commercial use of the
software by granting royalty-free source code and worldwide redistribution rights.
This means anyone can use the source code, modify it, and sell the resulting prod-
uct. More information is available at www.eclipse.org/legal/main.html.
Although some components of the platform are distributed under specific
licenses, the SWT and JFace toolsets are governed by the CPL. This makes it possi-
ble to develop commercial SWT/JFaces applications for all supported platforms.
1.3.2 Platforms supported
At the time of this writing, SWT/JFace development is available for a number of
operating systems. Because it relies on particular windowing system functions,
some platforms have multiple SWT implementations. Table 1.1 lists the operating
systems and user interfaces supported by SWT/JFace.
10 CHAPTER 1
Overview of SWT and JFace
On Linux, KDE support isn’t yet available. However, SWT/JFace applications can
run under the KDE desktop provided that the GTK runtime libraries are also
installed on the desktop. KDE is built on top of the Trolltech Qt toolkit, which is
distributed under a more restrictive licence than the CPL. Should a KDE version of
the SWT library be developed in the future, all existing SWT/JFaces applications
would support it and inherit the native KDE look.
Support for Microsoft Pocket PC 2002 is one of the hidden treasures of SWT.
The SWT distribution provides support for the StrongARM processor in both
Pocket PC 2002 and Smartphone 2002 devices. Thanks to its great flexibility, the
SWT Pocket PC version can be run against both the familiar J2SE (the standard dis-
tribution of Java) and the J2ME Connected Limited Device Configuration (CLDC)
profile for embedded devices. Coverage of how to build the SWT library for the
CDLC profile and use it in conjunction with the IBM J9 VM is beyond the scope of
the book. If you’re interested in exploring embedded development, visit the SWT
newsgroup at the Eclipse Consortium web site (news://news.eclipse.org/
eclipse.platform.swt).
Support for the Windows operating systems includes an unforeseen bonus: You
can embed ActiveX controls directly inside SWT container widgets. The Eclipse
platform uses this facility to include support for web browsing by embedding the
Table 1.1 Platforms supported by SWT/JFace
Operating system User interface
Microsoft Windows XP, 2000, NT, 98, ME Windows
Microsoft Windows PocketPC 2002 Strong ARM Windows
Microsoft Windows PocketPC 2002 Strong ARM (J2ME) Windows
Red Hat Linux 9 x86 Motif, GTK 2.0
SUSE Linux 8.2 x86 Motif, GTK 2.0
Other Linux x86 Motif, GTK 2.0
Sun Solaris 8 SPARC Motif
IBM PowerPC Motif
HP-UX 11i hp9000 PA-RISC Motif
QNX x86 Photon
Mac OS Carbon
The WidgetWindow 11
Microsoft WebBrowser control. You can find further details on ActiveX support in
appendix B, “OLE and ActiveX in SWT/JFace.”
1.4 The WidgetWindow
The best way to learn about the SWT/JFace toolset is to build GUIs that use its
classes. With this priority in mind, we struggled to come up with an overarching
project that would touch on the various aspects of SWT/JFace development. At
first, we wanted to build something exciting, such as a web-enabled database dis-
play. But we decided that this would incorporate too much irrelevant code and
place too large a burden on our hands-on readers.
So, we’ve opted for a simple application that incorporates as many GUI ele-
ments as possible while minimizing the amount of code. We feel that a TabFolder
object (described in chapter 3) will be the clearest manner of presenting the
information in this book. Then, with each following chapter, we’ll add a new tab
whose contents show the chapter’s subject. The fully designed application is
shown in figure 1.4. Not the savviest at marketing, we call it the WidgetWindow.
Development of the WidgetWindow application serves a number of purposes. Of
course, it provides a single application for integrating the different components
within the SWT and JFace libraries. But it also gives you a repository of reusable
SWT/JFace code. Because it’s a single project with multiple classes, as opposed to
multiple projects with single classes, the WidgetWindow will ensure that you can
reuse each part for your own user interfaces.
Figure 1.4 The WidgetWindow application. This overarching project will
incorporate all the GUI and graphical elements presented in this book.
12 CHAPTER 1
Overview of SWT and JFace
1.5 Summary
The contents of the SWT and JFace libraries are effective for building user inter-
faces, but by themselves, they don’t constitute anything groundbreaking. There
are still buttons, containers, labels, and menus that can be positioned and
manipulated just as in other toolsets. Instead, the philosophy behind the toolset
makes it revolutionary.
SWT/JFace may not conform to every rule of Java ideology, but it fulfills the
goals of open-source software to a much greater extent than Java, with its pseudo-
proprietary development. Not only doesn’t SWT/JFace require any licences or roy-
alties, but it also allows you, the developer, to charge these fees for software that
you develop. If you have developed a new operating system and need a develop-
ment tool to draw programmers to your platfrom, you can’t do much better than
tailoring SWT and JFace for your system. If you’re building a new programming
language and want something more than a command-line compiler and linker,
the Eclipse platform, with SWT and JFace, is ideally suited to your task.
When Java developers debate the merits of SWT/JFace over those of other
toolsets, they consider the capabilities available now or within the next six
months. This mindset overlooks the fact that SWT/JFace, like Eclipse, is developed
in a truly bazaar-like fashion, with companies and individuals providing improve-
ments from across the world. If the abundance of programmer hours can be cor-
related with future improvement, then SWT/JFace will be the hands-down victor
as its evolution continues.
Historically, software development has never been IBM’s strong suit. There-
fore, we’d like to express our appreciation to whichever lateral thinker realized
that helping the open source effort is the best way to add value to IBM hardware.
Given the freedom and extensibility of Eclipse and SWT/JFace and the enthusiasm
of its developers, we feel confident that this toolset will continue to benefit the
open source development community in years to come.
But enough backslapping. Let’s start building applications!
13
Getting started with
SWT and JFace
This chapter covers
■ The important classes of SWT: Display and Shell
■ An SWT programming example
■ The important class of JFace: ApplicationWindow
■ An SWT/JFace programming example
14 CHAPTER 2
Getting started with SWT and JFace
GUI programming is one of the most rewarding aspects of software development,
but when you rely on graphics instead of the command line, there are important
questions to be asked. How can your program access the widgets, containers, and
events of the operating system? What software classes represent the different com-
ponents in a GUI, and how can you manipulate them?
The goal of this chapter is to answer the first question and begin answering the
second. We’ll discuss the fundamental classes of both the SWT and JFace libraries
and how they access operating system resources. This chapter presents two main
code examples—HelloSWT.java and HelloSWTJFace.java—that show how to use
the Standard Widget Toolkit (SWT) with and without the JFace library. We’ll exam-
ine these programs and draw conclusions about their underlying structures.
This chapter will also begin adding code to the WidgetWindow project. This is a
graphical interface that will combine all the SWT and JFace topics discussed in this
book. We’ll build its frame here and update it in each chapter that follows.
Because each chapter adds to this application, we recommend that you follow its
development closely.
2.1 Programming in SWT
Although we’ll use JFace shortly, this section focuses on programming with SWT
alone. First, we’ll present the code for a basic GUI and examine its structure.
Then, this section will describe the two fundamental classes of the toolset: Display
and Shell. These classes provide the foundation on which widgets, containers,
and events can be added.
NOTE In order to compile and execute the code in this book, you need to add
the SWT/JFace Java libraries to the project and make the native graphic li-
brary available. This procedure is fully documented in appendix A, “Cre-
ating Projects with SWT/JFace.”
2.1.1 The HelloSWT program
Before we explore SWT theory in detail, it will be helpful to prove in advance that
it works. For this purpose, we present our first SWT GUI, HelloSWT.java, in
listing 2.1. We encourage you to add this class to the com.swtjface.Ch2 package
and execute the application.
Programming in SWT 15
package com.swtjface.Ch2;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class HelloSWT
{
public static void main (String [] args)
{
Display display = new Display();
Shell shell = new Shell(display);
Text helloText = new Text(shell, SWT.CENTER);
helloText.setText("Hello SWT!");
helloText.pack();
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Although HelloSWT is a simple GUI, most SWT applications consist of the same
three-part structure:
The first part begins by creating an instance of the Display and Shell classes. As
we’ll show shortly, this allows the GUI to access the resources of the underlying
platform and create a primary window for viewing widgets.
The next section adds a Text widget to the shell. Although this is simple in Hello-
SWT, this section usually requires the most effort in an SWT application. It deals with
adding and configuring the building blocks necessary to provide the GUI’s func-
tion. Widgets and groups of widgets (in containers) are added as children of the
shell. Listeners and events are defined for each widget that the user can act on.
The code in this section also sets the parameters for these widgets, containers, and
events to make sure they look and act as required. In this case, the pack() methods
tell the Shell and Text components to use only as much space as they need.
The last part represents the operation of the GUI. Up to this point, all of the appli-
cation’s code has done nothing more than initialize variables. But when the
Shell’s open() method is invoked, the application’s main window takes shape
Listing 2.1 HelloSWT.java
b Allocation and
initialization
c Adding widgets
to the shell
d GUI operation
b
c
d
16 CHAPTER 2
Getting started with SWT and JFace
and its children are rendered in the display. So long as the Shell remains open,
the Display instance uses its readAndDispatch() method to keep track of relevant
user events in the platform’s event queue. When one of these actions involves clos-
ing the window, the resources associated with the Display object (such as the
Shell and its children) are deallocated.
Figure 2.1 shows an example of how the GUI should appear
(in Linux/GTK).
Congratulations! You’ve created your first graphical
user interface with the SWT library. Before moving on to an
application that uses both SWT and JFace, it’s important to
further understand the classes we’ve used and the methods
available for accessing and configuring them.
2.1.2 The Display class
Although the Display class has no visible form, it keeps track of the GUI resources
and manages communication with the operating system. That is, it concerns itself
with how its windows are displayed, moved, and redrawn. It also ensures that
events such as mouse clicks and keystroke actions are sent to the widgets that can
handle them.
Operation of the Display class
Although the Display class may only appear in a few lines of your GUI code, it’s
important to respect and understand its operation. It’s the workhorse of any SWT/
JFace application, and whether you work with SWT/JFace or SWT alone, you must
include an instance of this class in your program. This way, your interface will be
able to use the widgets and containers of the operating system and respond to the
user’s actions. Although most applications do little more than create a Display
object and invoke a few of its methods, the role played by this class is sufficiently
important to be worth describing in detail.
The main task of the Display class is to translate SWT/JFace commands from
your code into low-level calls to the operating system. This process comprises two
parts and begins once the application creates an instance of the Display class.
First, the Display object constructs an instance of the OS class, which represents
the platform’s operating system (OS). This class provides access to the computer’s
low-level resources through a series of special Java procedures called native methods.
Figure 2.1
Simple but effective:
the output of the
HelloSWT code
Programming in SWT 17
Then, like a switchboard operator, this Display object uses these methods to direct
commands to the operating system and convey user actions to the application.
As an example of a native method, the OS declaration for SetFocus() is shown
here:
public static final native int SetFocus (int hWnd);
This method sets the focus on a window according to its handle, hWnd. Because of
the native modifier, there is no Java code to specify its operation. Instead, this
keyword tells the compiler that the method’s code is written in another language
and resides in another file. In the case of HelloSWT.java and all SWT/JFace appli-
cations, this other language is C and the other file is the native graphics library
you included in your project. The C code in the graphic library corresponding to
the SetFocus() method is presented here:
JNIEXPORT jint JNICALL OS_NATIVE(SetFocus)
(JNIEnv *env, jclass that, jint arg0) {
jint rc;
NATIVE_ENTER(env, that, "SetFocus\n")
rc = (jint)SetFocus((HWND)arg0);
NATIVE_EXIT(env, that, "SetFocus\n")
return rc;
}
As shown, the C implementation of the Java SetFocus() method calls the operat-
ing system function SetFocus(). This isn’t a coincidence; this exact matching of
SWT commands and operating system calls makes GUI debugging a straightfor-
ward process. As long as you can riddle out the Application Programming Inter-
face (API) for your operating system, you can determine what is happening in
your code. This example uses the Windows operating system, but the process is
similar for all platforms supported by Eclipse.
Another important point to consider is that, if any features in your operating
system aren’t incorporated into SWT, you can use the Java Native Interface to add
them yourself. All it requires is a native Java method in the SWT package and a C
function in the native graphics library that calls the operating system.
Methods of the Display class
Table 2.1 identifies and describes a number of methods that belong to the Display
class. This isn’t a full listing, but it shows the methods vital for SWT/JFace GUIs to
function and those necessary to implement particular capabilities in an application:
18 CHAPTER 2
Getting started with SWT and JFace
The first two methods must be used in any SWT-based GUI. The first, Display(),
creates an instance of the class and associates it with the GUI. The second, get-
Current(), returns the primary thread of the application, the user-interface thread.
This method is generally used with the dispose() method to end the operation
of the Display.
The next two methods in the table enable the application to receive notifica-
tions from the operating system whenever the user takes an action associated with
the GUI. Event processing, handlers, and listeners will be fully discussed in
chapter 4. However, it’s important to understand the readAndDispatch() method,
which accesses the operating system’s event queue and determines whether any of
the user’s actions are related to the GUI. Using this method, the HelloSWT class
knows whether the user has decided to dispose of the Shell. If so, the method
returns TRUE, and the application ends. Otherwise, the Display object invokes its
sleep() method, and the application continues waiting.
Although the Display class is important, there is no way to directly see the
effects of its operation. Instead, you need to use classes with visual representa-
tions. The most important of these is the Shell class.
2.1.3 The Shell class
Just as the Display class provides window management, the Shell class functions
as the GUI’s primary window. Unlike the Display object, a Shell instance has a
visual implementation, as shown in figure 2.1. The Shell class accesses the operat-
ing system through the OS class to an extent, but only to keep track of opening,
activating, maximizing, minimizing, and closing the main window.
The main function of the Shell class is to provide a common connection point
for the containers, widgets, and events that need to be integrated into the GUI. In
this respect, Shell serves as the parent class to these components. Figure 2.2
shows the relationship between an application’s operating system, Display, Shell,
and their widgets.
Table 2.1 Important methods of the Display class and their functions
Display method Function
Display() Allocates platform resources and creates a Display object
getCurrent() Returns the user-interface thread
readAndDispatch() Display object interprets events and passes them to receiver
sleep() Display object waits for events
Programming in SWT 19
Every SWT/JFace application bases its widgets on a main Shell object, but other
shells may exist in an application. They’re generally associated with temporary
windows or dialog boxes, which will be discussed further in chapter 10. Because
these shells aren’t directly attached to the Display instance, they’re referred to as
secondary shells. Shells that are attached to the Display are called top-level shells.
The Shell instance created in the HelloSWT application has a number of prop-
erties associated with it that allow users to alter its state or read information.
These characteristics make up the component’s style. You can control a Shell’s
style by adding a second argument to its constructor. Since the only argument in
HelloSWT’s Shell declaration is the display, it receives the default style for top-level
windows, called SHELL_TRIM. This combines a number of individual style elements
and tells the application that the window should have a title bar (SWT.TITLE) and
that the user can minimize (SWT.MIN), maximize (SWT.MAX), resize (SWT.RESIZE),
and close (SWT.CLOSE) the shell. The other default shell style, DIALOG_TRIM,
ensures that dialog shells have title bars, a border around the active area
(SWT.BORDER), and the ability to be closed.
Within your GUIs, you can set the style bits of the shell, or another widget, to
whatever you prefer, and combine them with the | operator. In addition to the
properties mentioned, you can also specify the shell’s modality, which restricts the
user’s ability to alter the shell’s state. A modal dialog box commands the user’s
attention by blocking all actions except those related to the dialog. It can’t be
moved or resized, and the user can only close or cancel it using the buttons pro-
vided. Finally, since not every platform can render these properties in GUI compo-
nents, you must understand that SWT treats style settings as guidelines instead of
strict rules.
Operating system
OS class
Display class
Shell class
Widgets
Figure 2.2
The class communication structure
of an SWT user interface
20 CHAPTER 2
Getting started with SWT and JFace
2.2 Programming in SWT/JFace
With a clear understanding of SWT, learning JFace is straightforward. Although
applications using both SWT and JFace have very different structures than those
coded with SWT alone, the concepts underlying both libraries are similar. Like the
preceding part, this section will provide a basic example of SWT/JFace code and
explain its structure. Further, we’ll delve into an important class provided in the
JFace library: ApplicationWindow.
In chapter 1, we explained how JFace was constructed to simplify SWT develop-
ment. We can now go into further depth by showing how its main classes work.
2.2.1 Model-based adapters
Eclipse documentation uses two terms to refer to JFace classes that work with SWT
widgets: helper classes and model-based adapters. We’ve chosen to use the latter term
in this book. This may be confusing because, in Java, an adapter is a class that pro-
vides additional event-handling capability to a widget. However, no self-respecting
programmer will use helper classes, so we’ll call them model-based adapters, or
JFace adapters.
These adapters can be split into four categories, shown in table 2.2. We’ll fur-
ther elaborate on each in future chapters, but we’ll briefly describe them here.
The first and most widely used category of model-based adapters includes the
Viewer classes, fully described in chapter 9. In SWT, the information and appear-
ance of a GUI component are bound together. However, viewers separate these
aspects and allow for the same information to be presented in different forms. For
example, the information in an SWT tree can’t be separated from the tree object.
But the same information in a JFace TreeViewer can be displayed in a TableViewer
or a ListViewer.
The next category involves Actions and Contributions, which are described in
chapter 4. These adapters simplify event handling, separating the response to a
Table 2.2 Categories of JFace adapters
Adapter classification Function
Viewers Separate a widget’s appearance and information
Actions and contributions Simplify and organize event-handling procedures
Image and font registries Manage the allocation/deallocation of fonts and images
Dialogs and wizards Extend the capability of SWT Dialogs for user interaction
Programming in SWT/JFace 21
user’s command from the GUI events that result in that response. This can be best
explained with an example. In SWT, if four different buttons will close a dialog box,
then you must write four different event-handling routines even though they
accomplish the same result. In JFace, these four routines can be combined in an
action, and JFace automatically makes the four buttons contributors to that action.
The third category involves image and font registries, which are further
explained in chapter 7. In SWT, it’s important to keep the number of allocated
fonts and images to a minimum, since they require operating system resources.
But with JFace registries, these resources can be allocated and deallocated when
needed. Therefore, if you’re using multiple images and fonts, you don’t need to
be concerned with manual garbage collection.
The last group comprises JFace dialogs and wizards, described in chapters 10
and 11. These are the simplest adapters to understand, since they extend the
capability of SWT dialogs. JFace provides dialogs that present messages, display
errors, and show the progress of ongoing processes. In addition, JFace provides a
specialized dialog called a wizard, which guides the user through a group of tasks,
such as installing software or configuring an input file.
2.2.2 The HelloSWT_JFace program
The best way to learn about JFace is to write a program that uses its library. The
code for the HelloSWT_JFace class is shown in listing 2.2. The output is similar to
that of HelloSWT, but the program structure is very different.
package com.swtjface.Ch2;
import org.eclipse.jface.window.*;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
public class HelloSWT_JFace extends ApplicationWindow
{
public HelloSWT_JFace()
{
super(null);
}
protected Control createContents(Composite parent)
{
Text helloText = new Text(parent, SWT.CENTER);
helloText.setText("Hello SWT and JFace!");
parent.pack();
return parent;
}
Listing 2.2 HelloSWTJFace.javaHelloSWTJFace.java
b Window allocation
c Window
presentation
22 CHAPTER 2
Getting started with SWT and JFace
public static void main(String[] args)
{
HelloSWT_JFace awin = new HelloSWT_JFace();
awin.setBlockOnOpen(true);
awin.open();
Display.getCurrent().dispose();
}
}
Although the code for HelloSWTJFace.java is slightly longer than that of Hello-
SWT.java, its structure is more clearly separated between the three class methods:
The first method, HelloSWT_JFace(), constructs an instance of the main class. Any
configuration or communication actions that need to be performed during allo-
cation should be coded here. Because this is unnecessary for HelloSWT_JFace, this
class only invokes the constructor of its superclass.
The createContents() method deals with designing the presentation of the win-
dow. Since the visual aspect of an ApplicationWindow can’t be directly accessed,
this method associates a widget container called a Composite to control the GUI’s
appearance. This container object serves as the parent of any GUI components
that need to be added to the application. After all the widgets are created, config-
ured, and added to the parent, createContents() returns the Composite to the
main window for display.
The final part of this application, framed by the main() method, takes care of the
actual operation of the GUI. After allocating resources for the ApplicationWindow,
this method configures the window to appear until closed by invoking the set-
BlockOnOpen() method with a TRUE argument. Then, the ApplicationWindow’s
open() method is called, displaying the window according to the Composite
returned by the createContents() method. The code after the open() method
only functions after the window is closed. Then, the program deallocates the
GUI’s Display instance by using its dispose() method. Because every widget in
HelloSWT_JFace is a child of the display, this disposal also deallocates every GUI
component in the program.
Once the code is compiled and the application is run, the result should look like
the window shown in figure 2.3.
d Window
operation
b
c
d
Programming in SWT/JFace 23
2.2.3 Coding in JFace and SWT/JFace
At this point, it’s helpful to contrast the code behind HelloSWT.java, programmed
with SWT alone, and that of HelloSWTJFace.java, which uses both SWT and JFace.
The main difference is that SWT combines the GUI’s appearance and operation in
its Shell class, whereas SWT/JFace splits these aspects. This modular structure pro-
motes code reuse and enables one developer to design the window’s view while
another determines its behavior. The appearance is controlled by the Composite
configured in the createContents() method, and the operation is performed
mainly through the instance of the ApplicationWindow class. Because this class is
so crucial in SWT/JFace applications, it’s important to examine its function in
greater detail.
2.2.4 The ApplicationWindow class
Although we’ve just mentioned how the ApplicationWindow in HelloSWT_JFace
differs from the Shell object in HelloSWT, both applications rely on Shell and
Display objects to communicate with the operating system. An SWT/Face applica-
tion still needs a separate Display instance, but the ApplicationWindow creates its
own Shell whenever it’s constructed with a null argument. This class relationship
is shown in figure 2.4. Although this may seem like an unnecessary complication,
the benefits of using JFace windows become apparent when you’re building large
user interfaces.
Like the model-based adapters mentioned in the beginning of this section, the
ApplicationWindow serves as a JFace adapter on the Shell class and provides two
main benefits. First, as mentioned, the ApplicationWindow separates the GUI’s
appearance from its behavior. Second, it provides a number of additional ways to
configure the window that are useful for designers. Although the Shell class has
methods that change its size and style, those of the ApplicationWindow class allow
for much more useful customization. These methods, which include those from
the Window class, are listed in table 2.3.
As shown in the table, the methods of an ApplicationWindow object make GUI
programming much more convenient. You can quickly configure the window to
include menu bars, toolbars, and status lines. These methods can also set the
Figure 2.3
The HelloSWTJFace.java code is very different from
that of HelloSWT.java, but the results are similar.
24 CHAPTER 2
Getting started with SWT and JFace
application’s exception handler and default image. In SWT, these capabilities
need to be provided for and configured for each different shell you create. In
JFace, this is performed automatically.
2.3 Beginning the WidgetWindow application
Although the HelloSWT and HelloSWT_JFace classes are helpful for learning the
basics of SWT/JFace programming, the toolset offers a great deal more functional-
ity that we need to explore. Rather than rewrite the same code in multiple
projects, we thought it would be best to build a single project and add classes to it
with each chapter.
Table 2.3 Configuration methods of the ApplicationWindow class
ApplicationWindow method Function
addMenuBar() Configures the window with a top-level menu
addToolBar() Adds a toolbar beneath the main menu
addStatusLine() Creates a status area at the bottom of the window
setStatus(String) Displays a message in the status area
getSeparator() Returns the line separating the menu from the window
setDefaultImage(Image) Displays an image when the application has no shell
setExceptionHandler
(IExceptionHandler)
Configures the application to handle exceptions according to the
specified interface
Operating system
OS class
Display class
Shell created by the Application Window
Widgets
ApplicationWindow class
Composite Class
Figure 2.4
JFace’s ApplicationWindow uses
a separate Composite object to
control its appearance.
Beginning the WidgetWindow application 25
To reduce the complexity of the WidgetWindow’s design, we decided to use both
SWT and JFace. In this chapter, we’ll create the basic window, shown in listing 2.3.
We strongly recommend that you add this class to your com.swtjface.Ch2 package.
package com.swtjface.Ch2;
import org.eclipse.swt.widgets.*;
import org.eclipse.jface.window.*;
public class WidgetWindow extends ApplicationWindow
{
public WidgetWindow()
{
super(null);
}
protected Control createContents(Composite parent)
{
getShell().setText("Widget Window");
parent.setSize(400,250);
return parent;
}
public static void main(String[] args)
{
WidgetWindow wwin = new WidgetWindow();
wwin.setBlockOnOpen(true);
wwin.open();
Display.getCurrent().dispose();
}
}
Figure 2.5 presents the unexciting but important output of the WidgetWindow class.
Listing 2.3 WidgetWindow.java
Figure 2.5
The blank-slate WidgetWindow
application
26 CHAPTER 2
Getting started with SWT and JFace
2.4 Summary
Although you’ll have to wait until the next chapter to build something fun and
exciting, you should have a solid grasp of the internals of SWT and JFace at this
point. These libraries make it possible to access platform-specific resources in a
platform-independent manner, and it’s important to understand the objects that
make this possible.
The main object is the Display, which works behind the scenes to communi-
cate with the operating system. This communication enables your SWT/JFace
applications to use native components and process events. Although the Display
has no appearance itself, other widgets require its operation to take shape.
SWT provides the Shell class as an overall container for GUI applications and
dialog boxes. The Shell forms the GUI’s parent window and makes it possible for
child widgets to communicate with the Display. Using style bits, you can custom-
ize the Shell’s appearance and behavior.
In contrast, JFace applications use an ApplicationWindow as their main con-
tainer. Unlike Shells, ApplicationWindows have no built-in form. This means you
can specify what your top-level window should look like. Also, these objects pro-
vide methods for easily integrating other features, such as menus, toolbars, and
status lines.
As you can see from the Shell and ApplicationWindow classes, the SWT and
JFace libraries provide similar capabilities. This redundancy played a large role in
determining the structure of this book. At first, we thought it would be best to
present these toolsets in two separate parts: one covering SWT and the other cov-
ering SWT/JFace. But we realized that this approach wasn’t feasible. First, because
JFace provides so few widgets and containers of its own, most of the code between
the two parts would be repeated. Second, as we’ll show in later chapters, trying to
build complex functionality with SWT requires a great deal of code, and the pro-
cess is simplified by incorporating JFace.
Therefore, this book presents SWT and SWT/JFace development side by side.
For the sake of being thorough and explaining basic concepts, we show how to
implement GUI features in SWT. But when it comes to adding capability to the
WidgetWindow application, we strongly recommend coding with both libraries.
Doing so will not only improve your understanding of SWT and JFace, but also
increase your appreciation for combining the two tools.
However, the best way to increase your appreciation is to start building real
GUIs with real widgets. Let’s see how they work!
27
Widgets: part 1
This chapter covers
■ Widgets and controls
■ Labels
■ Buttons
■ Composites
■ Updating WidgetWindow
28 CHAPTER 3
Widgets: part 1
To the less enlightened, the term widget may suggest a gadget or gizmo—a mecha-
nism that may or may not serve a useful purpose. But in studying SWT and JFace,
you need to take widgets very seriously. These are the paints in your palette and
the ingredients in your cupboard. Your understanding of the subject will deter-
mine how well your applications appear and perform.
The Eclipse designers define a widget as “any UI object that can be placed
inside another widget.” However, rather than use this recursive definition, we’ve
come up with our own: A widget is “any object in a graphical user interface that
displays information and/or allows the user to interface with an application.”
We’ve used the word object on purpose, since every widget in an SWT/JFace GUI
is the visual representation of an instance of a class. The goal of this chapter is to
present many of these classes and show how you can configure their appearance.
In particular, this chapter will cover three of the most important widget classes in
SWT. We’ll start with one of the most common widgets, the Label. Then, we’ll add
input capability to a label and learn about the Button class. Finally, we’ll discuss
Composites, which are widgets capable of containing other widgets.
But first, we need to examine the Widget class, which resides at the top of the
widget hierarchy, and its most important subclass, Control.
3.1 Introducing the Widget and Control classes
Although our widget definition may be helpful from a conceptual standpoint, it’s
useless for writing programs. Therefore, this section will begin describing the
classes behind these concepts. We’ll start with the Widget class and its associated
methods. Then, we’ll focus on the Control class and the many ways its methods
make our lives as GUI designers easier.
3.1.1 Understanding the Widget class
As the antecedent of all the widgets described in this book, the Widget class is very
important when you’re learning about SWT and JFace. It’s the superclass of all
classes that display information and allow user interface in SWT and JFace. How-
ever, not only is it an abstract class, but Eclipse.org strongly recommends against
creating subclasses due to the complexity involved. Therefore, you won’t be inher-
iting from Widget or using it directly in your code. Instead, this class is important
because it unifies all widgets under one structure.
Introducing the Widget and Control classes 29
The methods in the Widget class represent the basic capabilities inherent in
any SWT/JFace widget. Table 3.1 presents an important subset of these methods
and their functions.
The setData() method allows an application to attach information to a widget in
the form of an Object. This may be particularly useful if a widget must be shared
across different classes and must contain information beyond that normally pro-
vided by its class. It may also be helpful if a widget has a global scope and must
provide information across procedures that can’t directly communicate with each
other. This method works by associating a String value to the Object, which will
be deallocated when the widget is disposed of.
The next four methods allow an application to obtain information about the
referenced Widget. The first, getData(), returns all the data associated with the
widget through the setData() method, whereas the second only returns the
String value of the data. The next method in the table, getStyle(), returns an
int value that represents the appearance settings for the particular widget object.
The fourth method in the table, getDisplay(), returns the Display object associ-
ated with the GUI; the final method, toString(), returns a String value corre-
sponding to the class of the widget.
These capabilities are important, but GUI designers need much more to con-
figure widgets for practical applications. For this reason, we need to investigate
the Control class.
Table 3.1 Important methods of the Widget class and their functions
Widget method Function
setData(String, Object) Attaches an object to the widget, accessible through String
getData() Returns the objects associated as data within the widget
getData(String) Returns the data object corresponding to the String
getStyle() Returns an int corresponding to the widget’s style
getDisplay() Returns the Display object associated with the widget
toString() Returns a String representing the widget class
dispose() Deallocates the widget and its resources
isDisposed() Returns a boolean value regarding the widget’s deallocation
30 CHAPTER 3
Widgets: part 1
3.1.2 Working with Control objects
As we mentioned in chapter 2, SWT/JFace uses widgets provided by the operating
system to render its graphical applications. Since different platforms offer differ-
ent sets of GUI components, SWT can fully support only a subset of these widgets.
Objects in the Control class have a direct counterpart in the operating system that
you can access through the class’s handle field. However, SWT still provides a num-
ber of widgets outside the Control class. This structure is displayed in figure 3.1.
The majority of the widgets you’ll be working with, such as Labels, Buttons,
and Composites, are members of the Control class. As a result, because of their
associated handles, you can manipulate and configure these objects using a num-
ber of methods unavailable to the general Widget class. Although we won’t cover
all of them here, we’ll present two categories of methods that allow you to obtain
and specify the characteristics of a given Control object (see tables 3.2 and 3.3).
One of the most fundamental properties of a Control object is its size. The first
method in table 3.2, getSize(), returns this value in the form of a Point. The next
two methods set the widget’s size either with the width and height or with a Point
instance representing these dimensions.
The rest of the methods in the table deal with a Control’s preferred size. These
are the minimum dimensions the Control needs in order to display its contents,
which may comprise images, text, or other widgets. These coordinates can be
obtained through the computeSize() method. Then, the program can resize the
widget to these dimensions using the pack() method. You can also use both of
these methods with a boolean argument to tell the layout manager that the wid-
get’s properties have changed.
Widget
DropTargetControlCaret TrackerScrollBar Menu
ProgressBarLabel ScrollableButtonSash Scale Slider
CompositeList Text
Item
Figure 3.1 The Widget class and its primary subclasses
Introducing the Widget and Control classes 31
NOTE Due to differences in resolution and platform rendering, we recommend
that you use pack() instead of setSize() whenever possible. Doing so will
ensure that your container will tailor its appearance to its contents, whose
size may be controlled by the operating system. Also, you should invoke
pack() only after the widgets have been added to the container.
The getLocation() method in table 3.3 returns a Point containing the coordi-
nates of the Control relative to the widget that surrounds it. These coordinates
can be specified with the setLocation() method. The next two methods refer to a
widget’s bounds, which incorporate both its size and location. The getBounds()
Table 3.2 Methods for acquiring and manipulating a Control’s size
Control method Function
getSize() Returns a Point object representing the widget’s size
setSize(int, int) Sets the widget’s size based on the given length and width
setSize(Point) Sets the widget’s size according to a Point object
computeSize(int, int) Returns the dimensions needed to fully display the widget
computeSize(int, int, boolean) Returns the dimensions needed to fully display the widget,
and indicates whether its characteristics have changed
pack() Resizes the widget to its preferred size
pack(boolean) Resizes the widget to its preferred size, and indicates
whether its characteristics have changed
Table 3.3 Methods for setting and determining a Control’s location
Control method Function
getLocation() Returns the widget’s location relative to its parent
setLocation(int, int) Sets the widget’s location relative to its parent
getBounds() Returns the widget’s size and location relative to its parent
setBounds(int, int, int, int) Sets the widget’s size and location relative to its parent
toControl(int, int) Converts display-relative coordinates to a control-relative
Point
toControl(Point) Converts a display-relative Point to a control-relative Point
toDisplay(int, int) Converts display-relative coordinates to a control-relative
Point
toDisplay(Point) Converts a display-relative Point to a control-relative Point
32 CHAPTER 3
Widgets: part 1
method returns the Control’s x and y coordinates and its width and height. Simi-
larly, the setBounds() method requires four integers to represent these quantities.
When describing any location, you need a point of reference. For the getLoca-
tion() method, this point is the upper-left corner of the widget’s container, which
is generally its Shell. For a Shell object, the getLocation() method returns its
coordinates relative to the user’s console, represented by the Display object. This
is shown graphically in figure 3.2.
Using the dimensions shown in the figure, shell.getLocation() returns
(72, 66), and button.getLocation() returns (60, 40).
Using the last methods in the table, Controls can also obtain their locations rel-
ative to the Display object. In this case, the application converts coordinates rela-
tive to the Shell, called control-relative coordinates, to those relative to the Display,
called display-relative coordinates. This translation is performed by the toDisplay()
method. The reverse process, which converts display-relative coordinates to con-
trol-relative coordinates, is performed through the toControl() method.
Although we haven’t described all (or even half) of the methods associated
with the Control class, we’ve presented enough to show how you can manipulate
these objects in a user interface. Now all you need to know is what concrete Con-
trol subclasses you can add to your applications.
3.2 Labels
The Label class is the simplest of the Control classes. Labels display static informa-
tion in a GUI, such as a String or Image, and receive no user input. Because
they’re used so frequently, you need to become familiar with their properties.
This section will describe the styles and methods behind Labels, and how they’re
used in code.
Figure 3.2
Different controls use different points of reference.
Labels 33
3.2.1 Styles and separators
Fonts and Images will be fully explained in chapter 7; we’ll focus here on the dif-
ferent methods of displaying basic information in Labels. The fundamental
parameter in determining how a Label appears is its style, an integer value speci-
fied during construction. This is similar to the style of the Shell class, described in
chapter 2.
The text-related styles of a Label object deal with the String’s alignment and
are represented by the values SWT.CENTER, SWT.LEFT, and SWT.RIGHT. In addition,
you can configure Labels to display only a line—a separator—by setting the
SWT.SEPARATOR style. These separators can be configured to appear horizontally or
vertically (SWT.VERTICAL, SWT.HORIZONTAL) and shadowed or unshadowed
(SWT.SHADOW_IN, SWT.SHADOW_OUT, and SWT.SHADOW_NONE).
Figure 3.3 shows how these different styles look inside a
simple Shell.
To give you an idea how Labels (both text and separator
Labels) are coded in an application, consider the following
code:
Label shadow_label = new Label(shell, SWT.CENTER);
shadow_label.setText("SWT.SHADOW_OUT");
shadow_label.setBounds(30,60,110,15);
Label shadow_sep = new Label(shell, SWT.SEPARATOR |
SWT.SHADOW_OUT);
shadow_sep.setBounds(30,85,110,5);
The first label declaration creates a Label object with center-aligned text. The
next two methods set the label’s display String, size, and location in the Shell.
The next declaration uses the SWT.SEPARATOR style to create a separator and com-
bines the SWT.SHADOW_OUT and SWT.HORIZONTAL styles to control its appearance.
The only Label-specific method in the code sample is setText(), which tells
the object which String to display. However, there are other methods worth
examining when working with Labels.
3.2.2 Label methods
Table 3.4 lists the primary methods for manipulating Label objects in a GUI. As
you can see, most are straightforward.
Figure 3.3
Different separator
styles provided by
the Label class
34 CHAPTER 3
Widgets: part 1
It’s important to remember that an application can set text alignment after con-
structing the Label. Also, when we discuss Image objects in a later chapter, the
getImage() and setImage() methods will prove very helpful.
Labels are useful and frequently used in GUIs. But they’re boring. They would
be much more interesting if users had an opportunity to act. SWT provides this capa-
bility by adding an interface aspect to a Label and calling the combination a Button.
3.3 Involving the user with buttons
Outside of the menu, GUI users interface more with buttons than with any other
type of component. Button objects are also the simplest interface components
because they’re strictly binary; they’re either on or off. The Buttons presented in
this chapter won’t be able to react to the user’s selection. But once we discuss the
SWT/JFace event model in the next chapter, you’ll be able to associate these
objects with the Listeners and Adapters needed to react to user action.
Like Shells and Labels, a Button’s appearance in the GUI depends on the style
bits used during their creation. Five of the available styles result in Buttons that
look and act very differently from one another; we present them in the following
subsections.
3.3.1 Causing action with push buttons and SWT.PUSH
The most common type of Button in a GUI is the push button, whose style is spec-
ified by the SWT.PUSH constant. This is the default style for the Button class. As with
a Label object, a Button’s text is specified with the setText() method and
acquired with the getText() method. It’s simple to create and configure a push
button, as shown in this code sample:
Table 3.4 Methods for acquiring and manipulating a Control’s visibility
Label method Function
getText() Returns the String associated with the Label
setText(String) Associates a String object with the Label for display
getAlignment() Returns an int representing the Label’s text alignment
setAlignment(int) Specifies text alignment according to an SWT constant
getImage() Returns the Image object associated with the Label
setImage(Image) Associates an Image object with the Label
Involving the user with buttons 35
Button push = new Button(shell, SWT.PUSH);
push.setText("PUSH");
push.pack();
In addition to setting a Button’s text, an application can also control the align-
ment and appearance of the String in the Button. The Button’s constructor can
combine any one of the SWT.LEFT, SWT.CENTER, and SWT.RIGHT styles with SWT.PUSH
using the | operator. After the Button is allo-
cated, you can use its setAlignment()
method. These different alignments are
shown in figure 3.4.
Figure 3.4 also shows another style avail-
able for any Button that appears as a raised
surface. This is the SWT.FLAT style, which low-
ers the Button to the GUI’s plane.
3.3.2 Moving on with arrow buttons and SWT.ARROW
Sometimes a simple picture is more appropriate than text for describing a But-
ton’s purpose. A common picture is the arrow, which tells a user that he can navi-
gate through a document, graphic, or map. An arrow button is simple to create,
and you can specify the arrow’s direction by combining the SWT.ARROW style with
any one of the SWT.UP, SWT.DOWN, SWT.LEFT, and SWT.RIGHT constants. Here’s a
short code example:
Button push = new Button(shell, SWT.ARROW | SWT.RIGHT);
push.setText("RIGHT");
push.pack();
These styles are shown graphically in figure 3.5. Like
push buttons, arrow buttons can also appear flat using
the SWT.FLAT style.
Of course, if you want to customize the picture shown
on a Button object, the setImage() method will attach an
Image object for display. You’ll create and manipulate
these images in chapter 7.
3.3.3 Changing state with toggle buttons and SWT.TOGGLE
Push buttons and arrow buttons are used to perform actions, but sometimes all
you need is a component to keep track of a binary state. SWT provides this capa-
bility using toggle buttons, which specify the SWT.TOGGLE style during allocation.
Toggle buttons function similarly to push buttons, but they keep track of the
Figure 3.4
Push buttons with SWT.LEFT,
SWT.CENTER, SWT.RIGHT, and
SWT.FLAT styles
Figure 3.5
Left, up, down, and right,
but no rewind or fast-
forward
36 CHAPTER 3
Widgets: part 1
application’s state information instead of performing a rou-
tine. Also, once clicked, a toggle button remains pressed
until selected again (see figure 3.6).
The toggle button is the first component we’ve discussed
that maintains a change in appearance when selected. In this
case, an application can set the Button’s state using the set-
Selection(boolean) method, where the boolean value selects
the button if true and deselects it when false. The two other
buttons that share this capability are the check button and
the radio button, which are described next.
3.3.4 Choosing with check buttons and SWT.CHECK
Check buttons work similarly to toggle buttons but are generally incorporated
into lists. The user can select one or more options by marking check buttons in a
collection. Because of their square selection area, these components are generally
called checkboxes. For easier processing, we recommend using check buttons in an
array, as shown in the following code:
Button[] checks = new Button[2];
checks[0] = new Button(shell, SWT.CHECK);
checks[0].setText("Choice 1");
checks[0].setLocation(10,5);
checks[0].pack();
checks[1] = new Button(shell, SWT.CHECK);
checks[1].setText("Choice 2");
checks[1].setLocation(10,30);
checks[1].pack();
By creating an array, an application can loop
through the check button values by invoking the
getSelection() method on each Button. Also, if the
program needs to set any of the choices in advance,
the setSelection() method marks the default
options. In figure 3.7, the setSelection() method
has been used to mark the first and third choices in
the Shell.
3.3.5 Making a single choice with radio buttons and SWT.RADIO
Sometimes a GUI only wants a single selection. In these situations, the open-
ended nature of check buttons, which allow the user to pick as many or as few
Figure 3.6
Toggle buttons keep
track of user
preferences instead
of performing an
action.
Figure 3.7
Check buttons let the user
select zero or more options
from a group.
Involving the user with buttons 37
options as desired, is unacceptable. You need a capability similar to buttons on a
radio, where selecting one immediately deselects the others. Appropriately, this
capability is made possible by using what SWT/JFace calls radio buttons, which are
created with the SWT.RADIO style.
Collecting radio buttons in arrays
Like check buttons, radio buttons are usually placed in a collection. A common
method for manipulating these Button objects involves placing them in arrays;
this technique allows the application to cycle through each object to acquire and
set its parameters, as shown in the following code:
Button[] radios = new Button[3];
radios[0] = new Button(shell, SWT.RADIO);
radios[0].setSelected(true);
radios[0].setText("Choice 1");
radios[0].setLocation(10,5);
radios[0].pack();
radios[1] = new Button(shell, SWT.RADIO);
radios[1].setText("Choice 2");
radios[1].setLocation(10,30);
radios[1].pack();
radios[2] = new Button(shell, SWT.RADIO);
radios[2].setText("Choice 3");
radios[2].setLocation(10,55);
radios[2].pack();
for (int i=0; i 0)
{
Point selectionRange = styledText.getSelectionRange();
StyleRange style = new StyleRange(selectionRange.x,
selectionRange.y,
null, null,
doBold ? SWT.BOLD
: SWT.NORMAL);
styledText.setStyleRange(style);
}
}
After toggleBold() switches the current text mode, it checks whether there is cur-
rently selected text. If so, it ensures that the selected text matches the new mode.
getSelectionRange() returns a Point object whose x field represents the offset of
the start of the current selection; the y field holds the length of the selection. We
use these values to create a StyleRange, and we apply it to the currently selected text.
Finally, there remains the question of how the text is made bold in the first
place. We once again use an ExtendedModifyListener:
Editing text with SWT 85
public void modifyText(ExtendedModifyEvent event)
{
if(doBold)
{
StyleRange style = new StyleRange(event.start,
event.length,
null, null,
SWT.BOLD);
styledText.setStyleRange(style);
}
}
modifyText() is called after text has been newly inserted. If bold mode is currently
on (toggled by pressing F1), we use the information about the recent modifica-
tion included in the event to create a new StyleRange with bold text attributes and
apply it to the document. Calling setStyleRange() applies our new style to the
document. StyledText tracks the styles of adjacent text and, where possible, com-
bines multiple smaller ranges into a single larger range.
A StyledText example
Our detailed StyledText example (listing 5.2) demonstrates how you can use the
events published by StyledText to implement undo/redo functionality. The exam-
ple presents a text area with scrollbars, where the user may type. Pressing F1
undoes the last edit, and pressing F2 redoes the last undone edit. Notice that cut,
copy, and paste functionality is provided automatically with no explicit code
required on our part; it’s tied to the standard keyboard shortcuts for our platform.
ExtendedModifyListener differs from ModifyListener, which is also present on
StyledText, in the amount of information that is sent as part of the event.
Whereas ExtendedModifyListener is provided with details about exactly what was
done, ModifyListener is given notification that an edit occurred without details of
the exact modification.
In the interest of keeping the code shorter, this example makes the assump-
tion that all edits occur at the end of the buffer. Inserting text anywhere else in
the buffer will therefore cause undo/redo to behave strangely. Tracking actual
edit locations, as well as style information, is left as an exercise for the reader.
package com.swtjface.Ch5;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.swt.SWT;
Listing 5.2 Ch5Undoable.java
86 CHAPTER 5
More widgets
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
public class Ch5Undoable extends Composite
{
private static final int MAX_STACK_SIZE = 25;
private List undoStack;
private List redoStack;
private StyledText styledText;
public Ch5Undoable(Composite parent)
{
super(parent, SWT.NONE);
undoStack = new LinkedList();
redoStack = new LinkedList();
buildControls();
}
private void buildControls()
{
this.setLayout(new FillLayout());
styledText = new StyledText(this, SWT.MULTI | SWT.V_SCROLL);
styledText.addExtendedModifyListener(
new ExtendedModifyListener() {
public void modifyText(ExtendedModifyEvent event)
{
String currText = styledText.getText();
String newText = currText.substring(event.start,
event.start + event.length);
if( newText != null && newText.length() > 0 )
{
if( undoStack.size() == MAX_STACK_SIZE )
{
undoStack.remove( undoStack.size() - 1 );
}
undoStack.add(0, newText);
}
} } );
styledText.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e)
{
switch(e.keyCode)
{
case SWT.F1:
undo(); break;
case SWT.F2:
redo(); break;
B ExtendedModifyListener
c KeyListener
Editing text with SWT 87
default:
//ignore everything else
}
} } );
}
private void undo()
{
if( undoStack.size() > 0 )
{
String lastEdit = (String)undoStack.remove(0);
int editLength = lastEdit.length();
String currText = styledText.getText();
int startReplaceIndex = currText.length() - editLength;
styledText.replaceTextRange(startReplaceIndex,
editLength, "");
redoStack.add(0, lastEdit);
}
}
private void redo()
{
if( redoStack.size() > 0 )
{
String text = (String)redoStack.remove(0);
moveCursorToEnd();
styledText.append(text);
moveCursorToEnd();
}
}
private void moveCursorToEnd()
{
styledText.setCaretOffset(styledText.getText().length());
}
}
This is the key section of this example: An ExtendedModifyListener is added to the
StyledText object so that we can track edit events. The ExtendedModifyListener is
called each time the text is edited. The event that’s passed contains information
about the newly inserted text. In the example, we use the start offset and length to
retrieve the new text from the StyledText and save it in case the user wants to
undo her edit later. The event also provides information about the text that was
replaced, if any, in the replacedText field. A more robust implementation could
save this text along with the new edit and reinsert it if the edit was undone.
A KeyListener listens for keypresses, which are reported using a KeyEvent. We
check the keyCode field to see if it matches one of the keys we’re interested in.
d Undo
e Redo
b
C
88 CHAPTER 5
More widgets
Constants for the keys are defined in the SWT class. Additionally, we can query the
state of modifier keys such as Ctrl or Alt by masking the stateMask field of the
event against the appropriate constants defined in the SWT class.
Undo pops the top entry of the undo stack, which holds a record of all edits that
have been made. We then use replaceTextRange() to replace the last n characters
in the buffer with the empty string, where n is the length of the edit we retrieved
from the stack.
To redo an edit, we pop the top entry off the redo stack. It’s then inserted at the
end of the document using append().
The following lines added to WidgetWindow will let you test the undoable editor:
TabItem chap5Undo = new TabItem(tf, SWT.NONE);
chap5Undo.setText("Chapter 5 Undoable");
chap5Undo.setControl(new Ch5Undoable(tf));
There are some complexities to editing text in SWT, but once you understand the
events that are broadcast by the widget, it isn’t difficult to add basic types of valida-
tion or control logic to your application. Certain features, however, are difficult to
implement with the facilities provided by SWT. JFace text editing, although more
complex, is also more powerful; it offers a host of new options that we’ll discuss in
the next section.
5.2 JFace text support
As an alternative to using the StyledText control provided by SWT, JFace offers an
extensive framework for text editing. More than 300 classes and interfaces are
spread between 7 jface.text packages and subpackages. Rather than try to cover
them all in the limited space we have available, we’ll provide an overview of the
key classes in org.eclipse.jface.text and develop a small example showing
some of the advanced capabilities available.
5.2.1 Obtaining the JFace text packages
Before you can use the JFace text packages, you need to extract a couple of
jar files from your Eclipse installation: text.jar, located in $ECLIPSE_HOME/
plugins/org.eclipse.text_x.y.z; and jfacetext.jar, in $ECLIPSE_HOME/plugins/
org.eclipse.jface.text_x.y.z. Make sure both of them are in your classpath
before you try any of the examples in this section.
d
e
JFace text support 89
5.2.2 TextViewer and Document
JFace text support is implemented by a core set of classes and augmented by a
variety of extensions that add specific advanced features. We’ll discuss the core
first and then provide an overview of the available extensions.
Two interfaces form the core of JFace’s text support: IDocument and IText-
Viewer. Each has a default implementation provided by JFace.
An instance of IDocument holds the actual text that’s being edited. The primary
implementation of IDocument is the class Document, although AbstractDocument
provides a partial implementation that you can extend if you decide to write your
own. In addition to standard methods to set or retrieve text, IDocument also allows
for listeners to receive notification of content edits through the IDocumentLis-
tener interface.
IDocument also supports several more advanced features:
■ Positions—You can assign a “sticky” marker known as a Position to a
region of text. A Position object is given an offset and a length of text when
it’s assigned to the document. As the document’s text is updated, the Posi-
tion is kept in sync with the text changes so that it always points to the same
section of text, no matter how it moves in the document. You can use this to
implement features such as bookmarks, which allow the user to jump to a
marked location in the document. The base Position class offers little
beyond basic tracking of an offset and length; you’ll usually need to subclass
it in order to build useful behavior for your application.
■ Partition content types—Conceptually, a document is composed of one or
more partitions represented by the ITypedRegion interface. Each partition
can have a different content type, such as plain text, rich text, or HTML. To
use this feature, you need to create an IDocumentPartitioner and assign it
to your document. The document partitioner is then responsible for
responding to queries about the content type of specific locations in the
document, and it must implement computePartitioning() to return an
array of all the ITypedRegions present in the document. It isn’t necessary to
implement your own document partitioner; if you don’t assign one, the
entire document will be treated as a single region with type IDocu-
ment.DEFAULT_CONTENT_TYPE.
■ Searching—IDocument provides search facilities to clients through the
search() method. Although it doesn’t support regular expressions or other
patterns in the search, it does give you control over the search start location,
direction, and case sensitivity and whether to match whole words only.
90 CHAPTER 5
More widgets
ITextViewer is intended to turn a standard text widget into a document-based text
widget. The default implementation is TextViewer, which uses a StyledText
under the hood to display data. ITextViewer supports listeners for both text mod-
ifications and visual events, such as changes in the currently visible region of text
(known as the viewport). Although the default implementation of ITextViewer,
TextViewer, allows direct access to the StyledText if you wish to modify the dis-
play, it’s intended that you use TextPresentation instead; it collects the various
StyleRanges present in the document.
ITextViewer also supports a number of different types of plug-ins that can be
used to modify the behavior of the widget. The functionality that can be custom-
ized includes undo support, through IUndoManager; how to react to double
clicks, through ITextDoubleClickStrategy; automatic indentation of text, sup-
plied by IAutoIndentStrategy; and text to display when the mouse is left on a
section of the document, through ITextHover. You use each of these plug-ins by
assigning an appropriate instance of the interface to the text viewer and then
calling activatePlugins().
Finally, a variety of subpackages of org.eclipse.jface.text provide useful
extensions; they’re summarized in table 5.2.
Table 5.2 The subpackages of org.eclipse.jface.text provide a variety of advanced
functionality.
Package Description
org.eclipse.jface.text.contentassist Provides a framework for automatic completion of text
as it’s being typed, such as is found in many Java
IDEs. IContentAssistant and IContentAssis-
tantProcessor work together to provide IComple-
tionProposals at appropriate times.
org.eclipse.jface.text.formatter Provides utilities to format text. IContentFormatter
registers instances of IFormattingStrategy with
different content types. When text needs formatting,
the appropriate formatting strategy is given a String
representing the text to be modified.
org.eclipse.jface.text.presentation Used to update the visual appearance of the docu-
ment in response to changes. After a change, an
IPresentationDamager is used to calculate the
region of the document that needs to be redrawn, and
that information is given to an IPresentationRe-
pairer along with a TextPresentation to reset the
styles on the damaged region.
continued on next page
JFace text support 91
5.2.3 A JFace example
We’ll now build a simple text editor that uses some of TextViewer’s features.
Inspired by a feature in OpenOffice and other word processors, this editor tracks
individual words as the user types. At any time, the user can press F1 to obtain a
list of suggested completions for the word he’s currently typing, drawn from the
list of all words he has typed so far that start with the text currently under the
cursor.
To implement this functionality, we’ll use the classes in org.eclipse.jface.
text.contentassist. We’ve created a utility class called WordTracker, which is
responsible for tracking the user’s most recently typed words and is capable of
suggesting completions for a string. An instance of IContentAssistProcessor,
RecentWordContentAssistProcessor, presents the possible completions to the
framework. Finally, CompletionTextEditor is our main class: It configures the
TextViewer and attaches the appropriate listeners. We’ll discuss each of these
classes in detail, followed by the complete source code.
A ContentAssistant is responsible for suggesting possible completions to the
user. Each ContentAssistant has one or more instances of IContentAssistPro-
cessor registered; each processor is associated with a different content type.
org.eclipse.jface.text.reconciler Used to synchronize a document with an external
store of its text. The default Reconciler runs period-
ically in the background, delegating to instances of
IReconcilingStrategy as it finds dirty regions that
need to be kept in sync.
org.eclipse.jface.text.rules Defines classes to scan and match text based on con-
figurable IRules. This framework is used to imple-
ment the presentation package and document
partitioner and includes built in rules to match com-
mon occurrences such as words, numbers,
whitespace, or ends of lines.
org.eclipse.jface.text.source Used to attach visual markers to text, such as the red
Xs used in Eclipse to denote compilation errors. To
employ these features, you must use ISource-
Viewer instead of ITextViewer, which it extends.
You’ll then need to subclass Annotation to draw
appropriate images.
Table 5.2 The subpackages of org.eclipse.jface.text provide a variety of advanced func-
tionality. (continued)
Package Description
92 CHAPTER 5
More widgets
When the TextViewer requests suggestions, the ContentAssistant delegates to the
assist processor that is appropriate for the content type of the current region of
the document.
You can often use ContentAssistant as is. However, we need to define an ICon-
tentAssistProcessor. The processor’s main responsibility is to provide an array of
possible completions when computeCompletionProposals() is called. Our imple-
mentation is straightforward: Given the current offset of the cursor into the docu-
ment, it looks for the first occurrence of whitespace to determine the current
word fragment, if any, by moving backward through the document one character
at a time:
while( currOffset > 0
&& !Character.isWhitespace(
currChar = document.getChar(currOffset)) )
{
currWord = currChar + currWord;
currOffset--;
}
Once it has the current word, it requests completions from the WordTracker and
uses those completions to instantiate an array of ICompletionProposal in the
buildProposals() method:
int index = 0;
for(Iterator i = suggestions.iterator(); i.hasNext();)
{
String currSuggestion = (String)i.next();
proposals[index] = new CompletionProposal(
currSuggestion,
offset,
replacedWord.length(),
currSuggestion.length());
index++;
}
Each proposal consists of the proposed text, the offset at which to insert the text,
the number of characters to replace, and the position where the cursor should be
afterward. The ContentAssistant will use this array to display choices to the user
and insert the proper text once she chooses one.
In this example, we always activate the ContentAssistant programmatically by
listening for a keypress. However, IContentAssistProcessor also contains meth-
ods that allow you to specify a set of characters that will serve as automatic
triggers for suggestions to be displayed. You implement the getCompletion-
ProposalAutoActivationCharacters() method to return the characters that you
JFace text support 93
wish to serve as triggers. Listing 5.3 shows the complete implementation of the
IContentAssistProcessor.
package com.swtjface.Ch5;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.text.*;
import org.eclipse.jface.text.contentassist.*;
public class RecentWordContentAssistProcessor
implements IContentAssistProcessor
{
private String lastError = null;
private IContextInformationValidator contextInfoValidator;
private WordTracker wordTracker;
public RecentWordContentAssistProcessor(WordTracker tracker)
{
super();
contextInfoValidator = new ContextInformationValidator(this);
wordTracker = tracker;
}
public ICompletionProposal[] computeCompletionProposals(
ITextViewer textViewer,
int documentOffset)
{
IDocument document = textViewer.getDocument();
int currOffset = documentOffset - 1;
try
{
String currWord = "";
char currChar;
while( currOffset > 0
&& !Character.isWhitespace(
currChar = document.getChar(currOffset)) )
{
currWord = currChar + currWord;
currOffset--;
}
List suggestions = wordTracker.suggest(currWord);
ICompletionProposal[] proposals = null;
if(suggestions.size() > 0)
{
proposals = buildProposals(suggestions, currWord,
documentOffset - currWord.length());
lastError = null;
Listing 5.3 RecentWordContentAssistProcessor
B Find current word
94 CHAPTER 5
More widgets
}
return proposals;
}
catch (BadLocationException e)
{
e.printStackTrace();
lastError = e.getMessage();
return null;
}
}
private ICompletionProposal[] buildProposals(List suggestions,
String replacedWord,
int offset)
{
ICompletionProposal[] proposals =
new ICompletionProposal[suggestions.size()];
int index = 0;
for(Iterator i = suggestions.iterator(); i.hasNext();)
{
String currSuggestion = (String)i.next();
proposals[index] = new CompletionProposal(
currSuggestion,
offset,
replacedWord.length(),
currSuggestion.length());
index++;
}
return proposals;
}
public IContextInformation[] computeContextInformation(
ITextViewer textViewer,
int documentOffset)
{
lastError = "No Context Information available";
return null;
}
public char[] getCompletionProposalAutoActivationCharacters()
{
//we always wait for the user to explicitly trigger completion
return null;
}
public char[] getContextInformationAutoActivationCharacters()
{
//we have no context information
return null;
}
public String getErrorMessage()
{
c Build proposals
JFace text support 95
return lastError;
}
public IContextInformationValidator getContextInformationValidator()
{
return contextInfoValidator;
}
}
We move backward through the document a character at a time until we hit
whitespace or the beginning of the document.
Each proposal contains the text to propose, as well as information about where to
insert the text into the document. Theoretically, you could insert the proposed
text wherever you wish, although doing so could be confusing for the user if the
text isn’t inserted at the cursor’s current position.
WordTracker is a utility class used to maintain and search a list of words (see
listing 5.4). Our implementation isn’t particularly efficient, but it’s simple and fast
enough for our purposes. Each word is added to a List, and when suggestions are
needed, the List is traversed looking for any item that starts with the given
String. WordTracker doesn’t contain any SWT or JFace code, so we won’t examine
it in detail.
package com.swtjface.Ch5;
import java.util.*;
public class WordTracker
{
private int maxQueueSize;
private List wordBuffer;
private Map knownWords = new HashMap();
public WordTracker(int queueSize)
{
maxQueueSize = queueSize;
wordBuffer = new LinkedList();
}
public int getWordCount()
{
return wordBuffer.size();
}
public void add(String word)
Listing 5.4 WordTracker.java
b
c
96 CHAPTER 5
More widgets
{
if( wordIsNotKnown(word) )
{
flushOldestWord();
insertNewWord(word);
}
}
private void insertNewWord(String word)
{
wordBuffer.add(0, word);
knownWords.put(word, word);
}
private void flushOldestWord()
{
if( wordBuffer.size() == maxQueueSize )
{
String removedWord =
(String)wordBuffer.remove(maxQueueSize - 1);
knownWords.remove(removedWord);
}
}
private boolean wordIsNotKnown(String word)
{
return knownWords.get(word) == null;
}
public List suggest(String word)
{
List suggestions = new LinkedList();
for( Iterator i = wordBuffer.iterator(); i.hasNext(); )
{
String currWord = (String)i.next();
if( currWord.startsWith(word) )
{
suggestions.add(currWord);
}
}
return suggestions;
}
}
Ch5CompletionEditor brings together the components we’ve discussed. In build-
Controls(), we instantiate and configure a TextViewer. The ContentAssistant is
created, and our custom processor is assigned to the default content type:
JFace text support 97
final ContentAssistant assistant = new ContentAssistant();
assistant.setContentAssistProcessor(
new RecentWordContentAssistProcessor(wordTracker),
IDocument.DEFAULT_CONTENT_TYPE);
assistant.install(textViewer);
Once the assistant has been configured, it’s installed on the viewer. Note that the
assistant is given the viewer to install itself to, instead of the viewer receiving a Con-
tentAssistant as you might expect.
To be notified about edits, we use an ITextListener, which is similar to the
ExtendedModifyListener used by StyledText:
textViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent e)
{
if(isWhitespaceString(e.getText()))
{
wordTracker.add(findMostRecentWord(e.getOffset() - 1));
}
}
});
Listening for keystrokes here uses the same listener classes that StyledText did.
When we find the completion trigger key, we programmatically invoke the con-
tent assistant:
case SWT.F1:
assistant.showPossibleCompletions();
ContentAssistant does all the work from this point on, displaying the possible
completions and inserting the selected one into the document; see listing 5.5.
package com.swtjface.Ch5;
import java.util.StringTokenizer;
import org.eclipse.jface.text.*;
import org.eclipse.jface.text.contentassist.ContentAssistant;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
public class Ch5CompletionEditor extends Composite
{
private TextViewer textViewer;
private WordTracker wordTracker;
Listing 5.5 Ch5CompletionEditor
98 CHAPTER 5
More widgets
private static final int MAX_QUEUE_SIZE = 200;
public Ch5CompletionEditor(Composite parent)
{
super(parent, SWT.NULL);
wordTracker = new WordTracker(MAX_QUEUE_SIZE);
buildControls();
}
private void buildControls()
{
setLayout(new FillLayout());
textViewer = new TextViewer(this, SWT.MULTI | SWT.V_SCROLL);
textViewer.setDocument(new Document());
final ContentAssistant assistant = new ContentAssistant();
assistant.setContentAssistProcessor(
new RecentWordContentAssistProcessor(wordTracker),
IDocument.DEFAULT_CONTENT_TYPE);
assistant.install(textViewer);
textViewer.getControl().addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e)
{
switch(e.keyCode)
{
case SWT.F1:
assistant.showPossibleCompletions();
break;
default:
//ignore everything else
}
}
});
textViewer.addTextListener(new ITextListener() {
public void textChanged(TextEvent e)
{
if(isWhitespaceString(e.getText()))
{
wordTracker.add(findMostRecentWord(e.getOffset() - 1));
}
}
});
}
protected String findMostRecentWord(int startSearchOffset)
{
int currOffset = startSearchOffset;
char currChar;
String word = "";
try
B Assign an IDocument instance
c Assign content
assist processor
d Display completions
e Capture new words
JFace text support 99
{
while(currOffset > 0
&& !Character.isWhitespace(
currChar = textViewer.getDocument()
.getChar(currOffset)
))
{
word = currChar + word;
currOffset--;
}
return word;
}
catch (BadLocationException e)
{
e.printStackTrace();
return null;
}
}
protected boolean isWhitespaceString(String string)
{
StringTokenizer tokenizer = new StringTokenizer(string);
//if there is at least 1 token, this string is not whitespace
return !tokenizer.hasMoreTokens();
}
}
Each TextViewer needs an IDocument to store its text. Here we use the default
Document class, which is sufficient for most needs. You must set the document on a
TextViewer before it’s used, or NullPointerExceptions will be generated.
Each ContentAssistant can have a variety of IContentAssistProcessors assigned;
the appropriate one will be selected based on the content type of the document.
Here we assign our processor to the default content type, which is defined in the
IDocument interface.
When we detect that the proper key has been pressed, we programmatically
invoke the ContentAssistant.
We examine each edit as it’s made. When we find an edit that consists only of
whitespace, we assume that a new word has been added, retrieve it from the Docu-
ment, and store it in our WordTracker.
Here we cycle backward through the document one character at a time, starting
from the current editing position. When we find whitespace, we grab the word for
the WordTracker.
f Find last word
b
c
d
e
f
100 CHAPTER 5
More widgets
To see this in action, add the following to WidgetWindow:
TabItem chap5Completion = new TabItem(tf, SWT.NONE);
chap5Completion.setText("Chapter 5 Completion Editor");
chap5Completion.setControl(new Ch5CompletionEditor(tf));
As you can see, SWT and JFace provide a wide variety of text-editing options.
Although we’ve only touched on the possibilities offered by JFace, by understand-
ing the overall design you should be able to use the extensions without much
trouble. Now we’ll move on to several less complicated widgets, starting with
combo boxes.
5.3 The Combo widget
The Combo control is used to create a combo box. Typically, the Combo control lets the
user select an option from a list of choices. There are three styles of Combo controls:
■ Simple—Contains an editable text field at the top and a list box with the
choices on the bottom. This is the default combo style.
■ Drop-down—An editable text field with an arrow at the right side. Clicking
the arrow reveals a list of choices and allows the user to select one.
■ Read-only—A drop-down combo whose text field can’t be edited. This style is
used when you want to limit the choices the user can input. The read-only
combo defaults to an empty selection, so most of the time you’ll call
select( 0 ) to default the combo to the first choice available.
These styles are set via the usual STYLE.* attributes in the constructor and, slightly
unexpectedly, are mutually exclusive. Figure 5.1 shows the available styles of com-
bos; you can use the code in listing 5.6 to generate these results.
Figure 5.1
Combo styles, from left to right: simple,
drop-down, and read-only
ToolBarManager 101
package com.swtjface.Ch5;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
public class Ch5ComboComposite extends Composite {
public Ch5ComboComposite(Composite parent) {
super(parent, SWT.NONE);
buildControls();
}
protected void buildControls() {
setLayout(new RowLayout());
int[] comboStyles = { SWT.SIMPLE,
SWT.DROP_DOWN,
SWT.READ_ONLY };
for (int idxComboStyle = 0;
idxComboStyle < comboStyles.length;
++idxComboStyle) {
Combo combo = new Combo(this,
comboStyles[idxComboStyle]);
combo.add("Option #1");
combo.add("Option #2");
combo.add("Option #3");
}
}
}
Run this example by adding the following code to WidgetWindow:
TabItem chap5Combos = new TabItem(tf, SWT.NONE);
chap5Combos.setText("Chapter 5 Combos");
chap5Combos.setControl(new Ch5ComboComposite(tf));
5.4 ToolBarManager
The ToolBarManager is a JFace class that simplifies the construction of toolbars by
making use of the action framework we discussed in chapter 4. It’s the toolbar
equivalent of the MenuManager, and the interfaces are similar. This class is also
derived from the ContributionManager class. As such, objects implementing
either the IAction or IContribution interface can be added to the ToolBarMan-
ager. The ToolBarManager will generate the appropriate SWT Controls when
Listing 5.6 Ch5ComboComposite.java
102 CHAPTER 5
More widgets
required, so you don’t have to get involved with the gritty details. Most of the time
you’ll be adding Action objects to the ToolBarManager, which will then automati-
cally generate instances of the Toolbar and ToolItem classes that we discuss later.
You can easily add a toolbar to your application by calling the ApplicationWin-
dow’s createToolBarManager() method. Unlike its MenuManager counterpart, cre-
ateToolBarManager() requires a style parameter. This style parameter determines
the style of buttons to be used by the ToolBar: either flat or normal pushbuttons.
As we mentioned earlier, it’s handy to use the same Actions to generate items on
both the menu and the toolbar—for example, actions such as OpenFile are nor-
mally found on both. By reusing Actions, you simplify the code and ensure that
menu and toolbar are always in sync.
5.4.1 ControlContribution
In addition to the ContributionItems that MenuManager works with, there is a new
ContributionItem that can only be used with a ToolBarManager: the ControlCon-
tribution. This is a cool class that wraps any Control and allows it to be used on a
ToolBar. You can even wrap a Composite and throw it onto the toolbar.
To use the ControlContribution class, you must derive your own class and
implement the abstract createControl() method. The following code snippet
demonstrates a simple implementation of such a class. We create a custom Con-
trolContribution class that can be used by the JFace ToolBarManager:
toolBarManager.add(new ControlContribution("Custom") {
protected Control createControl(Composite parent) {
SashForm sf = new SashForm(parent, SWT.NONE);
Button b1 = new Button(sf, SWT.PUSH);
b1.setText("Hello");
Button b2 = new Button(sf, SWT.PUSH);
b2.setText("World");
b2.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
System.out.println("Selected:" + e);
}
});
return sf;
}
});
Note that you must implement the SelectionListeners on your controls if you
want anything to happen. For all intents and purposes, the ControlContribution
class lets you place anything you want on the ToolBar.
CoolBar 103
5.4.2 Creating toolbars by hand
Although it’s often easiest to create a toolbar by using a ToolBarManager, you may
occasionally wish to create one manually, if it’s simple or if you aren’t using JFace.
In this case, you’ll need to use two classes: ToolBar and ToolItem.
ToolBar
The Toolbar is a composite control that holds a number of ToolItems. The ToolBar
is rendered as a strip of small iconic buttons, typically 16-by-16 bitmap graphics.
Each of these buttons corresponds to a ToolItem, which we’ll discuss in the next sec-
tion. By clicking the button, the user triggers an action represented by the ToolItem.
A ToolBar may be oriented either horizontally or vertically, although it’s hori-
zontal by default. In addition, it’s possible for ToolItems to wrap around and form
additional rows.
Typically, ToolBars are used to organize and present sets of related actions. For
example, there might a ToolBar representing all text operations with buttons for
paragraph alignment, typeface, font size, and so on.
ToolItem
The ToolItem represents a single item in a ToolBar. Its role with respect to the
ToolBar is similar to that of the MenuItem to a Menu. Unlike MenuItems, ToolItems
aren’t text but iconic in nature. As such, an image should always be assigned to a
ToolItem. A ToolItem on a ToolBar ignores the text label and displays only a small
red square if no image is assigned. When the user selects a ToolItem from the
menu, it broadcasts the event to any registered SelectionListeners. Your applica-
tion should register a listener with each ToolItem and use that listener to perform
whatever logic corresponds to the menu item.
5.5 CoolBar
The CoolBar control is like the ToolBar control with upgraded functionality. The
primary distinction between the two is that the items on a CoolBar can be reposi-
tioned and resized at runtime. Each of these items is represented by a CoolItem
control, which can contain any sort of control. The most common uses of a Cool-
Bar are to hold toolbars or buttons.
The next snippet shows the creation of a CoolBar that holds multiple toolbars.
Each child ToolBar contains items that are grouped together by function. In this
case, we have one ToolBar with file functions, another with formatting functions,
and a third with search functions, each of which is wrapped in a CoolItem control
104 CHAPTER 5
More widgets
and contained in a single parent CoolBar. This example is representative of a typi-
cal CoolBar; there are many ways to layer and organize controls to create striking
user interfaces. Figure 5.2 shows what the toolbars look like before moving them
around; notice that initially, the file and search items are next to each other.
The code to create the CoolBar looks like this:
String[] coolItemTypes = {"File", "Formatting", "Search"};
CoolBar coolBar = new CoolBar(parent, SWT.NONE);
for(int i = 0; i < coolItemTypes.length; i++)
{
CoolItem item = new CoolItem(coolBar, SWT.NONE);
ToolBar tb = new ToolBar(coolBar, SWT.FLAT);
for(int j = 0; j < 3; j++)
{
ToolItem ti = new ToolItem(tb, SWT.NONE);
ti.setText(coolItemTypes[i] + " Item #" + j);
}
}
Notice that each CoolItem has a handle on the left side: Double-clicking the han-
dle expands the CoolItem to the full width of the CoolBar, minimizing the other
CoolItems if necessary. By clicking the handle and dragging it, the user can move a
CoolItem to different parts of the CoolBar. To create additional rows, drag a Cool-
Item below the current CoolBar. To reorder a CoolItem, drag it to the new posi-
tion—other CoolItems will be bumped out of the way to accommodate it.
Figure 5.3 shows our example after we’ve repositioned the CoolItems.
Figure 5.2 The initial toolbars, controlled by a CoolBar. Notice that the File and
Search items are adjacent.
Figure 5.3 The same toolbars have been repositioned by the user.
Slider 105
5.6 Slider
The Slider control is similar to the scrollbars you see on a window. Although it
seems logical to assume that scrollbars are implemented with Slider controls,
they’re different. Scrollbars are associated with the item they’re scrolling and
aren’t available for use outside of that context. This is where the Slider comes in.
You can use the Slider as a control to select any value along an integral range.
This range is set via the setMinimum() and setMaximum() methods.
The rectangular slider you can click and drag is officially referred to as the
thumb. You set the size of the thumb via setThumb(); it should be an integral num-
ber. Visually, the size of the thumb is depicted realistically as a percentage of the
entire range. Thus, if the range is from 0 to 100 and the size of the thumb is 10,
then the thumb will take up 10% of the Slider control.
NOTE Some operating systems have native scrollbars that feature a constant-
sized thumb. On these platforms, the size of the thumb is ignored for vi-
sual purposes but used in other calculations.
Arrows at each end move the thumb by a set amount referred to as the increment.
You specify this increment via the setIncrement() method. Clicking the area
between the thumb and an endpoint arrow causes the thumb to jump by a larger
set amount. This amount is referred to as the page increment and is set via the set-
PageIncrement() method. Figure 5.4 shows a typical slider; notice that it appears
similar to a vertical scrollbar.
There is also a convenience method called setValues() that takes in all these
values at once. The method signature is as follows:
void setValues( int selection, int minimum, int maximum, int thumb,
int increment, int pageIncrement)
The selection is the starting point for the thumb. This is again represented by an
integral number that specifies a value along the range of the Slider. The example
in listing 5.7 demonstrates a Slider control with a range of 400 to 1600, as might
be needed to represent a standardized test score.
Figure 5.4 A typical Slider control
106 CHAPTER 5
More widgets
package com.swtjface.Ch5;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Slider;
public class Ch5Slider extends Composite {
public Ch5Slider(Composite parent) {
super(parent, SWT.NONE);
setLayout(new FillLayout());
Slider slider = new Slider(this, SWT.HORIZONTAL);
slider.setValues(1000, 400, 1600, 200, 10, 100);
}
}
The code sets the selection to 1000, the minimum to 400, the maximum to 1600,
the thumb size to 200, the increment value to 10, and the page increment to 100.
The Slider also takes a style attribute that lets you specify whether it should be
vertical or horizontal. By default, a horizontal Slider is constructed.
The following code adds the slider example to WidgetWindow:
TabItem chap5Slider = new TabItem(tf, SWT.NONE);
chap5Slider.setText("Chapter 5 Slider");
chap5Slider.setControl(new Ch5Slider(tf));
5.7 ProgressBar
The ProgressBar control lets you convey the progress of a lengthy operation. Its sim-
plified counterpart, the ProgressIndicator, is recommended in most cases. Occa-
sionally, you may need more control than a ProgressIndicator allows; if you decide
that you need to use a ProgressBar directly, you’re taking responsibility for chang-
ing the display of the bar yourself. The following code snippet shows an example:
//Style can be SMOOTH, HORIZONTAL, or VERTICAL
ProgressBar bar = new ProgressBar(parent, SWT.SMOOTH);
bar.setBounds(10, 10, 200, 32);
bar.setMaximum(100);
...
for(int i = 0; i < 10; i++) {
//Take care to only update the display from its
//own thread
Display.getCurrent().asyncExec(new Runnable() {
public void run() {
Listing 5.7 Ch5Slider.java
b Create Slider
b
ProgressIndicator 107
//Update how much of the bar should be filled in
bar.setSelection((int)(bar.getMaximum() * (i+1) / 10));
}
});
}
As you examine this code, note that in addition to needing to calculate the
amount to update the bar, the call to setSelection() causes the widget to be
updated every time. This behavior is unlike that of ProgressIndicator or Pro-
gressMonitorDialog, which will update the display only if it has changed by an
amount that will be visible to the end user.
As you can see, more work is involved with using ProgressBars than the other wid-
gets we’ve discussed, and in general we recommend avoiding them unless you have
no choice. However, a ProgressBar may occasionally be necessary—for example, if
you need to unfill the bar, there is no way to do it with the higher-level controls.
5.8 ProgressIndicator
The ProgressIndicator widget allows you to display a progress bar without worry-
ing much about how to fill it. Like the ProgressMonitorDialog, it supports
abstract units of work—you need only initialize the ProgressIndicator with the
total amount of work you expect to do and notify it as work is completed:
ProgressIndicator indicator = new ProgressIndicator(parent);
...
indicator.beginTask(10);
...
Display.getCurrent()display.asyncExec(new Runnable() {
public void run() {
//Inform the indicator that some amount of work has been done
indicator.worked(1);
}
});
As this example shows, there are two steps to using a ProgressIndicator. First you
let the indicator know how much total work you intend to do by calling begin-
Task(). The control won’t be displayed on the screen until this method is called.
Then you call worked() each time some work has been completed. As we discussed
in chapter 4, there are several threading issues to pay attention to here. Doing the
actual work in the UI thread will cause the display to lock up and defeats the pur-
pose of using a ProgressIndicator in the first place. However, you aren’t allowed
to update widgets from a non-UI thread. The solution is to use asyncExec() to
schedule the code that updates the widget to be run from the UI thread.
108 CHAPTER 5
More widgets
The ProgressIndicator also provides an animated mode, where the total
amount of work isn’t known. In this mode, the bar continually fills and empties
until done() is called. To use animated mode, call beginAnimatedTask() instead of
beginTask(); there is no need to call the worked() method. Assuming your work is
being correctly done in a non-UI thread, this implies that you don’t have to worry
about the asyncExec() call, either.
5.9 Summary
SWT and JFace provide many options for editing text. The SWT controls are fairly
easy to use, but implementing anything beyond simple text editing using them
can quickly become painful. The JFace controls, on the other hand, offer enough
power to create sophisticated text editors, such as the one in Eclipse. However,
they’re much more complicated to understand and use.
We’ve now covered many useful widgets. We’ve discussed creating combo
boxes and toolbars, combining controls with coolbars, adding sliders to a control,
and several ways of displaying the progress of a task to the user. As you may have
noticed, the code examples have also become more complex and closer to how
real-world usage may look. The points we’ve discussed in relation to threading
issues are important to keep in mind always, not just when you’re using progress
bars or indicators.
In the next chapter, we’ll cover layouts and explain how you can control the
overall presentation of controls in a GUI application.
109
Layouts
This chapter covers
■ Fill layouts
■ Row layouts
■ Grid layouts
■ Form layouts
■ Creating custom layouts
110 CHAPTER 6
Layouts
We’ve used layouts throughout the course of this book. Now that you have a firm
grasp of widgets and controls, we’ll delve into the complexities of how to use lay-
outs to arrange widgets into a pleasant interface.
Layouts are associated with a composite and help organize the controls within
it. One way to think about the process is to imagine each widget as a book and the
layout as shelving. You can stack books up on the shelf or lay them side by side in
a horizontal row. Layouts can consist of partitions to separate the books or new
layers to hold them more efficiently. Unlike real-world shelving, SWT layouts are
dynamic: the container and its contents can be resized, reflowed, and laid out
according to rules you specify. These rules are known as constraints in SWT.
Building a wooden bookshelf can be a lot of work, taking days or weeks.
Although creating a UI can also be time consuming, the many options available in
SWT’s layouts can make the job much easier. You may not ever make a nice oak
bookshelf, but this chapter will show you how to exercise your imagination in cre-
ating virtual cabinets.
NOTE Before we get into the details, it’s worth taking a moment to compare
SWT’s approach with Swing’s design. Swing also has layouts, such as the
ubiquitous BorderLayout. Unfortunately, SWT’s layouts typically differ
from the Swing layouts, and knowledge of Swing doesn’t ease the learn-
ing curve much. The layout algorithms have a tangibly different feel.
SWT’s approach minimizes layouts, using attributes and modifiers on
widgets to control their position. By contrast, Swing uses a recursive ap-
proach that nests layouts. The drawback is that the nesting can quickly
become deep, leading to inefficiency and high resource costs. Compared
to Swing, SWT layouts require you to do more advance planning and map
where the Controls will go, often breaking out paper and pencil to sketch
your ideas in advance. With Swing, it’s possible to use a divide-and-
conquer approach, laying out small sections at a time and then nesting
them to form the overall GUI. Ultimately, the two toolkits chose to em-
phasis different strengths: design-time simplicity versus runtime simplici-
ty. Neither holds a marked advantage, but this difference shapes our
approach as GUI designers.
6.1 The fill layout
Our desks are often littered with books stacked in gigantic piles; this system is sim-
ple, easy, and useful in many cases. The fill layout is the layout equivalent of a stack
of books. It’s a simple layout that takes the child controls and lays them out at
The fill layout 111
equal intervals to fill the space in a composite. By default, the controls are stacked
side by side, from left to right. Each control is given the space it needs, and any
leftover space in the composite is divided among the child controls.
Figure 6.1 shows buttons in a FillLayout; the code in listing 6.1 demonstrates
how to create this layout. You add a series of buttons to a composite, and the lay-
out resizes them to take up all the available space.
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6FillLayoutComposite extends Composite {
public Ch6FillLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
FillLayout layout = new FillLayout( SWT.VERTICAL);
setLayout(layout);
for (int i = 0; i < 8; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Sample Text");
}
}
}
Notice the setLayout() method call. This method in Composite is used to associ-
ate a layout with the composite that will be used to arrange all the child controls.
Without this call, SWT won’t know how to size or position any of the child con-
trols, so nothing will be displayed. (If you’re having trouble getting your widgets
to appear, forgetting to set a layout is a common cause.)
Listing 6.1 Ch6FillLayoutComposite.java
Figure 6.1
Buttons in a
FillLayout, before
resizing
112 CHAPTER 6
Layouts
Resizing the window changes the buttons to look like figure 6.2. There is little vis-
ible difference between the two images, because the FillLayout always expands
the buttons to fill all available space.
You can call the FillLayout constructor with no parameters or with a single
style parameter. The default constructor uses the SWT.HORIZONTAL style, in which
case the layout arranges child controls from left to right. Using SWT.VERTICAL
causes the controls to be arranged from top to bottom.
Add the following code to WidgetWindow to see how the FillLayout works:
TabItem fillLayoutItem = new TabItem(tf, SWT.NONE);
fillLayoutItem.setText("Chapter 6 FillLayout");
fillLayoutItem.setControl(new Ch6FillLayoutComposite(tf));
Like a stack of books, the fill layout is good only for simple situations. As you
gather more books—or controls, in the case of JFace/SWT—the stack becomes
unmanageable. Books get lost in the clutter, and your eyes become distracted. To
organize more effectively, you need the GUI equivalent of a bookcase.
6.2 The row layout
If the fill layout is like a stack of books, then the row layout is a basic bookcase.
Instead of being limited to one pile, you can organize controls into a number of
rows, much like shelves. Since the row layout arranges child controls into single
row by default, you need to pass in SWT.WRAP to get the functionality of additional
rows. The row layout provides additional customization options by giving you
access to margin and spacing options. (Note that the name row layout is a bit of a
misnomer, because you can choose to use either a horizontal row or a vertical row.
The vertical row layout is therefore really a column layout.)
Let’s see how having multiple rows can facilitate user interfaces that have a
large number of controls. The code for the WidgetWindow pane in figure 6.3 is
Figure 6.2
The same buttons,
after resizing
The row layout 113
almost the same as for the fill layout, but the child controls are laid out differently.
The code to produce this layout appears in listing 6.2.
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6RowLayoutComposite extends Composite {
public Ch6RowLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
setLayout(layout);
for (int i = 0; i < 16; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Sample Text");
}
}
}
Add the next three lines to WidgetWindow, and resize the window showing the
buttons:
TabItem rowLayoutItem = new TabItem(tf, SWT.NONE);
rowLayoutItem.setText("Chapter 6 RowLayout");
rowLayoutItem.setControl(new Ch6RowLayoutComposite(tf));
As you can see, instead of using all available space for each child, the row layout
combines multiple buttons into each row. The layout does so dynamically, so
Listing 6.2 Ch6RowLayoutComposite.java
Figure 6.3 Buttons positioned by a RowLayout, before resizing
114 CHAPTER 6
Layouts
when you reduce the width of the window, the buttons shift downward, as
figure 6.4 shows.
Much of the other behavior in a RowLayout is specified through property val-
ues. We’re mainly concerned with the following properties:
■ wrap—A boolean value that defaults to true. You’ll probably want to keep
the default. Switching it off will result in all the controls staying on a single
row, with the controls cut off at the end of the visible edge of the parent
composite.
■ pack—A boolean value that defaults to true. This property keeps child con-
trols the same size, which typically is desirable in the context of a row layout.
You get even rows of controls by setting pack; on the other hand, keeping
pack off lets controls retain their natural sizing.
■ justify—A boolean value that defaults to false. This property distributes
controls evenly across the expanse of the parent composite. If justify is on
and the parent is resized, then all the child controls pick up the slack and
redistribute themselves evenly across the empty space.
6.2.1 Customizing individual layout cells
You’ve seen how to control the overall behavior of the layout. However, it’s also
possible to tinker with each individual child control’s sizing in the layout by using
Figure 6.4 After resizing, the RowLayout rearranges the buttons into two columns.
The row layout 115
the RowData class. Many layouts use the layout data mechanism. The idea is that
you can help guide the parent layout by associating hints with each control using
the setLayout() method, which takes an instance of LayoutData. An examination
of the class hierarchy reveals that RowData is derived from LayoutData and there-
fore all the layouts have the potential to understand the associated layout data. In
practice, though, you need to use the exact layout data class that each layout
expects in order to get tangible results. Layouts will ignore hints from layout data
they don’t recognize. By convention, for each layout class that supports data for
individual children, there is a data class whose name matches: FooLayout has a
data class called FooData, and so on.
Creating row data hints for the row layout is simple. All the information is
passed in through the row data’s constructor. Let’s expand our WidgetWindow
example to give more room for the first couple controls. Add the line in bold in
listing 6.3 to the existing code.
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6RowLayoutComposite extends Composite {
public Ch6RowLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
setLayout(layout);
for (int i = 0; i < 16; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Sample Text");
button.setLayoutData(new RowData(200 + 5 * i, 20 + i));
}
}
}
The figures have illustrated the effects of having row data set. Remember, the best
way to learn what these options do and how they interact is to tinker with the
code. Often, to get the result you want, you’ll need a combination of style hints,
properties, and layout data.
Listing 6.3 Ch6RowLayoutComposite.java
116 CHAPTER 6
Layouts
6.3 The grid layout
The grid layout builds on the row layout model by allowing you to explicitly create
multiple rows and columns. In effect, the grid layout offers a nicely partitioned
bookcase with multiple shelves and clean divisions on each shelf to further orga-
nize your controls. Factor in a flexible grid data object, and the end result is that
the grid layout is the most useful and widely used layout. Figure 6.5 shows a series
of buttons, this time controlled by a GridLayout.
Listing 6.4 demonstrates a simple grid layout example in the WidgetWindow
framework. We create a GridLayout with four columns and allow the layout to cre-
ate as many rows as necessary.
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6GridLayoutComposite extends Composite {
public Ch6GridLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
GridLayout layout = new GridLayout(4,false);
setLayout(layout);
for (int i = 0; i < 16; ++i) {
Button button = new Button(this, SWT.NONE);
button.setText("Cell " + i);
}
}
}
Listing 6.4 Ch6GridLayoutComposite.java
Figure 6.5
Buttons controlled by a GridLayout
GridLayout
constructor
The grid layout 117
Note that the constructor takes two parameters: the number of columns and a
boolean to indicate whether the columns should take up an even amount of
space. By passing false, you tell the layout to only use the minimum amount of
space needed for each column.
You can run the composite by adding the following lines to WidgetWindow:
TabItem gridLayoutItem = new TabItem(tf, SWT.NONE);
gridLayoutItem.setText("Chapter 6 GridLayout");
gridLayoutItem.setControl(new Ch6GridLayoutComposite(tf));
6.3.1 GridData
At first, the notion of having a grid may seem contrary to a flexible layout. The key
to using the grid layout is understanding that a single child control can span more
than one grid cell at a time. You do this through layout data. In this case, let’s turn
to the GridData object, which provides additional hints for the GridLayout on how
to lay out a Control.
Using GridData styles
GridData is in many ways similar to the RowData object that we examined in the
previous section. The constructor takes a series of style constants, which when
combined determine how the layout will position an individual widget. These
styles fall into three categories: FILL, HORIZONTAL_ALIGN, and VERTICAL_ALIGN.
The various FILL styles determine whether the cell should be expanded to fill
available space. Valid values include FILL_HORIZONTAL, which indicates that the
cell should be expanded horizontally; FILL_VERTICAL, to expand the cell verti-
cally; and FILL_BOTH, which effectively causes the cell to fill all the space available.
The ALIGN styles, on the other hand, determine where the control should be
positioned in the cell. Values include BEGINNING, END, CENTER, and FILL. BEGIN-
NING positions the control at the left or topmost edge of the cell, whereas END
puts the control at the right or bottommost edge. CENTER centers the control, and
FILL causes the control to expand to fill all available space.
Table 6.1 summarizes the available style combinations for a GridData object.
Using GridData size attributes
Unlike RowData, GridData also has a number of public attributes that can be set
to control its behavior. Several of these are boolean values that are automatically
managed when the different styles are set, so it isn’t typically necessary to manipu-
late them directly. Some, however, are integer values used to precisely control the
size of individual cells. These attributes are summarized in table 6.2.
118 CHAPTER 6
Layouts
Of particular importance are the horizontalSpan and verticalSpan attributes.
As we mentioned earlier, by setting a certain control to cover more than one cell,
you can make your UI look less like a spreadsheet so it’s more visually appealing.
Figure 6.6 demonstrates this concept. We’ve created a grid layout with three
Table 6.1 Style combinations for GridData
Style Constant Description
FILL_HORIZONTAL Expand the cell to fill any empty space horizontally. Implies
HORIZONTAL_ALIGN_FILL.
FILL_VERTICAL Expand the cell to fill any empty space vertically. Implies
VERTICAL_ALIGN_FILL.
FILL_BOTH Expand the cell both vertically and horizontally. Equivalent to
FILL_HORIZONTAL | FILL_VERTICAL.
HORIZONTAL_ALIGN_BEGINNING Align the cell’s contents at the leftmost edge of the cell.
HORIZONTAL_ALIGN_END Align the cell’s contents at the rightmost edge of the cell.
HORIZONTAL_ALIGN_CENTER Center the cell’s contents horizontally.
HORIZONTAL_ALIGN_FILL Expand the cell’s contents to fill all empty horizontal space in
the cell.
VERTICAL_ALIGN_BEGINNING Align the cell’s contents at the top of the cell.
VERTICAL_ALIGN_END Align the cell’s contents at the bottom of the cell.
VERTICAL_ALIGN_CENTER Center the cell’s contents vertically.
VERTICAL_ALIGN_FILL Expand the cell’s contents to fill all empty vertical space in
the cell.
Table 6.2 GridData size attributes
Attribute Description Default Value
widthHint Minimum width for the column. SWT.DEFAULT desig-
nates that there is no minimum width.
SWT.DEFAULT
heightHint Minimum height for the row. SWT.DEFAULT designates
that there is no minimum height.
SWT.DEFAULT
horizontalIndent Number of pixels to be placed between the control
and the left edge of the cell.
0
horizontalSpan Number of columns in the grid that this cell should
cover.
1
verticalSpan Number of rows in the grid that this cell should cover. 1
The form layout 119
columns and three rows. The text area in the lower-left corner has been config-
ured to cover two columns and two rows, allowing it to expand to cover much
more area than the buttons. Note that button 2 along the top and buttons 4 and 5
on the right have been set to FILL_HORIZONTAL and FILL_VERTICAL, respectively.
For reference, the snippet of code that configures the text area is shown here:
Text t = new Text(this, SWT.MULTI);
GridData data = new GridData(GridData.FILL_BOTH);
data.horizontalSpan = 2;
data.verticalSpan = 2;
t.setLayoutData(data);
We set both span attributes to 2 and tell the GridData that we wish to expand as
much as possible in both directions.
6.4 The form layout
You’ve seen a steady progression in capability as we’ve discussed the fill layout, the
row layout, and finally the grid layout. Those layouts share the same underlying
layout algorithm—laying out controls in rows and columns—albeit in varying
degrees of complexity. The form layout is a departure from that path. Instead of
partitioning sections, the form layout lets you create a UI based on gluing
together controls relative to each other or the parent composite.
This makes it much easier to create resizable forms with controls of differing
sizes. A typical dialog box, for example, has a large central text area and two but-
tons located just below and to the right. In this case, the most natural way to think
of how the controls should be positioned is by envisioning them relative to each
other. It’s easier to say “the buttons should be below the text area, and the Cancel
button should be to the right of the Ok button” and let SWT worry about the
details than to try to calculate how many rows and columns each control should
Figure 6.6
A more advanced GridLayout.
The text area covers two
columns and two rows. All the
other controls are contained in
one cell each.
120 CHAPTER 6
Layouts
span. Figure 6.7 shows an example of this setup; in the following sections, we’ll
discuss the elements necessary to create it.
The FormLayout class is fairly simple. The only configuration options come
from attributes that control the height and width of the margins around the edge
of the layout, and the spacing attribute, which lets you specify the amount of
space (in pixels) to be placed between all controls. Similar to the layouts we exam-
ined previously, you configure individual controls using instances of FormData.
6.4.1 Using FormData
A FormData instance is typically associated with each child control in a composite.
Even more so than with other layouts, it’s important to provide configuration data
for each child, because the whole idea of a form layout is to specify positions of
child controls relative to each other. If a given control doesn’t have a FormData
instance describing it, it will default to being placed in the upper-right corner of
the composite, which is rarely what you want.
The width and height attributes specify the dimensions of a control in pixels.
More important are the top, bottom, right, and left attributes, each of which
holds an instance of FormAttachment. These attachments describe the control’s
relations to other controls in the composite.
6.4.2 Specifying relations using FormAttachment
Understanding the FormAttachment class is the most important part of using a
form layout. As mentioned earlier, each instance of FormAttachment describes
the positioning of one side of a control. You can use FormAttachment two differ-
ent ways.
First, you can specify a FormAttachment using a percentage of the parent com-
posite. For example, if the left side of a FormData is set to a FormAttachment
Figure 6.7
A FormLayout has been used to position
the two buttons relative to the text area.
The form layout 121
with 50%, then the left edge of the control will be placed at the horizontal middle
of the parent. Likewise, setting the top edge to 75% positions the control three
quarters of the way down the composite. Table 6.3 summarizes the FormAttach-
ment constructors that can be used to specify percentages.
Specifying FormAttachments in terms of percentages can be useful, but you
shouldn’t use this approach often. Specifying all your controls using percentages
isn’t much different from assigning them absolute pixel positions: It quickly
becomes difficult to visualize the positions of each element; and when the com-
posite is resized, it’s unlikely that the controls will still be in the positions you
desire. The point of using a FormLayout is to position controls relative to each
other, which the second form of FormAttachment allows.
The second series of FormAttachment constructors are based on passing in
other controls. They’re used to position the edge of one control next to another.
By setting the right attribute of the FormData for button1 to a FormAttachment
constructed with button2, you’re saying that button1 should always be posi-
tioned such that button2 is immediately to its right. Laying out most or all of your
controls in this fashion has several benefits. The intent of your layout code
becomes easier to understand: Instead of your having to guess which controls are
meant to be next to each other based on percentages or pixels, it becomes obvi-
ous that, for example, control foo should always be below bar. Second, the form
layout is also aware of your intent. However the composite may be resized, it will
always be able to maintain the correct relative positions.
Again, there are several different forms of the FormAttachment constructor
for specifying relative positions; they’re summarized in table 6.4.
Table 6.3 Percentage-based FormAttachment constructors
Constructor signature Description
FormAttachment(int numerator) Assumes a denominator of 100, meaning that the argument will
be treated as a percentage. Only available in SWT 3.0.
FormAttachment(int numerator,
int offset)
Assumes a denominator of 100, meaning that the argument will
be treated as a percentage. The offset is the number of pixels
that the control should be offset from the percentage position.
FormAttachment(int numerator,
int denominator, int offset)
The numerator divided by the denominator gives the percentage
used to position the control. The offset is the number of pixels
that the control should be offset from the percentage position.
122 CHAPTER 6
Layouts
6.4.3 Laying out controls using a form layout
Now that we’ve discussed the classes that work together to drive a form layout,
we’ll look at the code we used to produce the screenshot in figure 6.7. Listing 6.5
creates a text area and two buttons. The text control is anchored to the top and
left edges of the composite. Both buttons are placed below the text control, and
the Ok button is placed to the left of the Cancel button.
package com.swtjface.Ch6;
import org.eclipse.swt.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.layout.*;
public class Ch6FormLayoutComposite extends Composite {
public Ch6FormLayoutComposite(Composite parent) {
super(parent, SWT.NONE);
FormLayout layout = new FormLayout();
setLayout(layout);
Text t = new Text(this, SWT.MULTI);
FormData data = new FormData();
data.top = new FormAttachment(0, 0);
data.left = new FormAttachment(0, 0);
data.right = new FormAttachment(100);
data.bottom = new FormAttachment(75);
t.setLayoutData(data);
Button ok = new Button(this, SWT.NONE);
ok.setText("Ok");
Table 6.4 FormAttachment constructors that accept relative positions
Constructor signature Description
FormAttachment(Control control) Attach the current widget to the adjacent side of the
control parameter.
FormAttachment(Control control, int
offset)
Attach the current widget to the adjacent side of the
control parameter, offset by the number of pixels in
the offset parameter.
FormAttachment(Control control, int
offset, int alignment)
alignment must be one of SWT.TOP, SWT.BOTTOM,
SWT.LEFT, SWT.RIGHT, or SWT.CENTER. Attach the
current widget to the side of the control parameter
specified by alignment, offset by the number of pix-
els in the offset parameter.
Listing 6.5 Ch6FormLayoutComposite.java
b Text goes at upper left
The form layout 123
Button cancel = new Button(this, SWT.NONE);
cancel.setText("Cancel");
data = new FormData();
data.top = new FormAttachment(t);
data.right = new FormAttachment(cancel);
ok.setLayoutData(data);
data = new FormData();
data.top = new FormAttachment(t);
data.right = new FormAttachment(100);
cancel.setLayoutData(data);
}
}
Here we position the text widget, which is the main control that everything else
will be positioned relative to. By setting both the top and left fields to FormAt-
tachments with a percentage of 0, we anchor the text widget to the upper-left cor-
ner. The right field is 100, so the text widget expands horizontally to fill the
available area; and the bottom field’s value of 75 causes it to take up the top three
quarters of the available area.
The Ok button must follow two rules: It should always be immediately below the
text area and immediately to the left of the Cancel button. We specify this using
the top and right fields of the FormData, giving each a FormAttachment
instance with a reference to the appropriate control.
After positioning the Cancel button below the text area, we force it to the right
side of the composite by using a FormAttachment with a percentage of 100.
However you resize the window, the buttons and the text area always maintain
their correct positions.
You may have noticed that although we use the line
data.right = new FormAttachment(cancel);
when we set up the data for the Ok button, there is no corresponding
data.left = new FormAttachment(ok);
statement for the Cancel button. The second line is implied by the first, but SWT
forbids you from creating such circular attachments. Whenever you have a control
foo that refers to control bar, bar must not refer back to foo. According to the
SWT documentation, if you create such an attachment, the result of the layout
algorithm will be undefined, although it’s guaranteed to terminate and not leave
your program stuck in an infinite loop.
C
Ok button positioned
relative to other widgets
d Cancel button on right side
b
c
d
124 CHAPTER 6
Layouts
Add the following lines to WidgetWindow to see for yourself how FormLayout
works:
TabItem formLayoutItem = new TabItem(tf, SWT.NONE);
formLayoutItem.setText("Chapter 6 FormLayout");
formLayoutItem.setControl(new Ch6FormLayoutComposite(tf));
6.5 Custom layouts
The standard layouts serve a variety of roles and are suitable for most situations.
Sometimes, though, you need to build a custom layout to deal with the exceptions
to the rule. Like a finely crafted piece of custom cabinetry, a custom layout can
make everything it contains look better.
It’s relatively rare that you’ll need to create a custom layout implementation—
the existing layouts can handle most situations, especially when they’re used with
a ResizeListener to tweak the positions of widgets after the window has been
resized. It’s only appropriate to create a new layout class if the same layout logic
will be reused in several places in your application, or if manually adjusting posi-
tions after resize events proves to be more awkward than laying them out precisely
in the first place.
To demonstrate the process of creating a custom layout manager, we’ll create a
RadialLayout class that positions its widgets in a circle. You wouldn’t often use this
layout in an application, but the fairly straightforward algorithm lends itself to being
used as an example. When we’re done, the final result will look like figure 6.8.
Custom layouts are derived from the abstract Layout class. You need to write
only two methods: computeSize() and layout(). (These are the only methods
Figure 6.8
Buttons laid out using RadialLayout
Custom layouts 125
that Layout defines; it’s more of an interface than a true abstract class.) The com-
puteSize() method is called when the parent composite is instantiated to calcu-
late how much space the layout requires. This is followed by a call to layout() to
position all the controls.
6.5.1 Calculating the layout’s size
The first method we’ll examine is computeSize(). The relevant bits of this
method are as follows:
protected Point computeSize(Composite composite,
int wHint, int hHint,
boolean flushCache)
{
Point maxDimensions =
calculateMaxDimensions(composite.getChildren());
int stepsPerHemisphere =
stepsPerHemisphere(composite.getChildren().length);
int maxWidth = maxDimensions.x;
int maxHeight = maxDimensions.y;
int dimensionMultiplier = (stepsPerHemisphere + 1);
int controlWidth = maxWidth * dimensionMultiplier;
int controlHeight = maxHeight * dimensionMultiplier;
int diameter = Math.max(controlWidth, controlHeight);
Point preferredSize = new Point(diameter,
diameter);
... // code to handle case when our calculations
// are too large
return preferredSize;
}
The parameters to this method are straightforward:
■ composite—The object we’re going to populate. At the time this method is
called, it has children, but neither the composite nor the children have
been sized or positioned on the screen.
■ wHint and hHint—Suggestions for the width and height, respectively.
These values represent the largest size the layout should request. They may
also have the special value SWT.DEFAULT, which signifies that the layout is
free to use whatever sizes it decides it needs.
■ flushCache—A simple flag to tell the layout whether it’s safe to use any
cached values that it may be maintaining. In our example, we don’t cache
anything, so it’s safe to ignore this flag.
126 CHAPTER 6
Layouts
The purpose of computeSize() is to calculate how large the composite we’re lay-
ing out should be. In particular, this method shouldn’t modify the sizes of any
components—the system will set the parent composite’s size when it’s ready and
call layout() when it’s time to position the children. Because our example lays
out the controls in a circle, we need to figure out an appropriate radius to fit all
the controls without having them overlap and then return a size for the composite
that will accommodate a circle of that size.
The calculations are simple. We first find the largest child by calling calcu-
lateMaxDimensions(), which asks each child for its preferred size and returns
the largest. In order to keep the code simple, we assume that each child is as large
as the largest one. (This approach works fine when you’re laying out objects that
are all approximately the same size, but it would cause trouble in a real system if
some widgets were significantly larger than the others.) Once we have a size for
our child objects, we multiply that size by half the number of children. Because
one hemisphere of the circle will contain half the child objects, this gives us the
diameter of the circle. We create a Point object representing a square of this size
(plus some padding) and return it as the preferred size of our composite.
6.5.2 Laying out the widgets
Once we’ve recommended a size for our composite, the layout() method is
called. This is our cue to position each of the children in the parent composite.
The parameters are even simpler this time. We’re given the composite that’s
being populated and the same flushCache flag as before. The logic, however, is a
bit more complex, because we have to calculate the exact position of each child
object. To do so, we use an equation you may remember from geometry:
We can easily calculate R (the radius), so for any X coordinate we might choose, Y
can be calculated as:
Starting at the leftmost point of the circle, the layout method traverses the list of
children, regularly spacing each along the X axis and using this X coordinate to cal-
culate the appropriate Y coordinate. The work is done in the calculateControl-
Positions() method, which is called by layout(). Here’s a summary of the code:
2R=YX 22 +
22 XR±=Y −
Custom layouts 127
private Point[] calculateControlPositions(Composite composite)
{
... // set up control counts, max width, etc.
Rectangle clientArea = composite.getClientArea();
int radius = (smallestDimension / 2) - maxControlWidth;
Point center = new Point(clientArea.width / 2,
clientArea.height / 2);
long radiusSquared = radius * radius;
int stepXDistance = ...
int signMultiplier = 1;
int x = -radius;
int y;
Control[] controls = composite.getChildren();
for(int i = 0; i < controlCount; i++)
{
Point currSize = controls[i].getSize();
long xSquared = x * x;
int sqrRoot = (int)Math.sqrt(radiusSquared - xSquared);
y = signMultiplier * sqrRoot;
... // translate coordinates to be relative to
// actual center, instead of the origin
positions[i] = new Point(translatedX - (currSize.x / 2),
translatedY - (currSize.y / 2) );
x = x + (signMultiplier * stepXDistance);
//we've finished the upper hemisphere, now do the lower
if(x >= radius)
{
x = radius - (x - radius);
signMultiplier = -1;
}
}
return positions;
}
This method is mostly a straightforward implementation of the algorithm men-
tioned earlier. The only tricky part is that we lay out one hemisphere at a time.
Once the X value has reached the rightmost point of the circle, we switch the X
coordinates to decrease back along the same path and reverse the sign on the Y
coordinates (which accounts for the +/- part of our equation earlier). The sign-
Multiplier variable takes care of this for us. It has the value of either 1 or –1,
and it controls both whether the X value is increasing or decreasing and whether
the Y values are positive or negative.
128 CHAPTER 6
Layouts
The other “gotcha” in this code is remembering that the equation we’re using
assumes that the center of the circle is at the origin. It’s therefore necessary to
translate each point to be relative to the actual center of the circle instead.
Once we have calculateControlPositions() working, writing layout() is
easy. We take the list of positions that we’ve calculated and apply them to the chil-
dren of the parent composite:
protected void layout(Composite composite, boolean flushCache)
{
Point[] positions = calculateControlPositions(composite);
Control[] controls = composite.getChildren();
for(int i = 0; i < controls.length; i++)
{
Point preferredSize = controls[i].computeSize(SWT.DEFAULT,
SWT.DEFAULT);
controls[i].setBounds(positions[i].x, positions[i].y,
preferredSize.x, preferredSize.y);
}
}
Because the complete class has already grown rather large, we ask each control to
calculate its preferred size and use that value, plus the positions calculated earlier,
to place each control in the composite. Giving each control a size is critical: If you
don’t set the size, the control will default to having a width and height of 0, mean-
ing that it will be invisible.
6.5.3 Updating WidgetWindow
The complete code for RadialLayout is shown in listing 6.6. The listing is long, but
we’ve already examined the complicated parts in detail, so it should be easy to follow.
package com.swtjface.Ch6;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.*;
public class RadialLayout extends Layout
{
public RadialLayout()
{
super();
}
protected Point computeSize(Composite composite,
Listing 6.6 RadialLayout.java
Custom layouts 129
int wHint, int hHint,
boolean flushCache)
{
Point maxDimensions =
calculateMaxDimensions(composite.getChildren());
int stepsPerHemisphere =
stepsPerHemisphere(composite.getChildren().length);
int maxWidth = maxDimensions.x;
int maxHeight = maxDimensions.y;
int dimensionMultiplier = (stepsPerHemisphere + 1);
int controlWidth = maxWidth * dimensionMultiplier;
int controlHeight = maxHeight * dimensionMultiplier;
int diameter = Math.max(controlWidth, controlHeight);
Point preferredSize = new Point(diameter,
diameter);
if(wHint != SWT.DEFAULT)
{
if(preferredSize.x > wHint)
{
preferredSize.x = wHint;
}
}
if(hHint != SWT.DEFAULT)
{
if(preferredSize.y > hHint)
{
preferredSize.y = hHint;
}
}
return preferredSize;
}
protected void layout(Composite composite, boolean flushCache)
{
Point[] positions = calculateControlPositions(composite);
Control[] controls = composite.getChildren();
for(int i = 0; i < controls.length; i++)
{
Point preferredSize = controls[i].computeSize(SWT.DEFAULT,
SWT.DEFAULT);
controls[i].setBounds(positions[i].x, positions[i].y,
preferredSize.x, preferredSize.y);
}
}
private Point[] calculateControlPositions(Composite composite)
{
int controlCount = composite.getChildren().length;
130 CHAPTER 6
Layouts
int stepsPerHemisphere = stepsPerHemisphere(controlCount);
Point[] positions = new Point[controlCount];
Point maxControlDimensions =
calculateMaxDimensions(composite.getChildren());
int maxControlWidth = maxControlDimensions.x;
Rectangle clientArea = composite.getClientArea();
int smallestDimension =
Math.min(clientArea.width, clientArea.height);
int radius = (smallestDimension / 2) - maxControlWidth;
Point center = new Point(clientArea.width / 2,
clientArea.height / 2);
long radiusSquared = radius * radius;
int stepXDistance =
calculateStepDistance(radius * 2, stepsPerHemisphere);
int signMultiplier = 1;
int x = -radius;
int y;
Control[] controls = composite.getChildren();
for(int i = 0; i < controlCount; i++)
{
Point currSize = controls[i].getSize();
long xSquared = x * x;
int sqrRoot = (int)Math.sqrt(radiusSquared - xSquared);
y = signMultiplier * sqrRoot;
int translatedX = x + center.x;
int translatedY = y + center.y;
positions[i] = new Point(translatedX - (currSize.x / 2),
translatedY - (currSize.y / 2) );
x = x + (signMultiplier * stepXDistance);
//we've finished the upper hemisphere, now do the lower
if(x >= radius)
{
x = radius - (x - radius);
signMultiplier = -1;
}
}
return positions;
}
private Point calculateMaxDimensions(Control[] controls)
{
Point maxes = new Point(0, 0);
for(int i = 0; i < controls.length; i++)
{
Point controlSize =
controls[i].computeSize(SWT.DEFAULT, SWT.DEFAULT);
Custom layouts 131
maxes.x = Math.max(maxes.x, controlSize.x);
maxes.y = Math.max(maxes.y, controlSize.y);
}
return maxes;
}
private int stepsPerHemisphere(int totalObjects)
{
return (totalObjects / 2) - 1;
}
private int calculateStepDistance(int clientAreaDimensionSize,
int stepCount)
{
return clientAreaDimensionSize / (stepCount + 1);
}
}
Now that we have our custom layout, using it is easy, as shown by the class in
listing 6.7.
package com.swtjface.Ch6;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class Ch6RadialLayoutComposite extends Composite
{
public Ch6RadialLayoutComposite(Composite parent)
{
super(parent, SWT.NONE);
setLayout(new RadialLayout());
for(int i = 0; i < 8; i++)
{
Button b = new Button(this, SWT.NONE);
b.setText("Cell " + (i + 1));
}
}
}
When you add this class to the WidgetWindow with the following code, it creates a
series of buttons laid out in a circle, as you saw earlier:
Listing 6.7 Ch6RadialLayoutComposite.java
132 CHAPTER 6
Layouts
TabItem radialLayoutItem = new TabItem(tf, SWT.NONE);
radialLayoutItem.setText("Chapter 6 RadialLayout");
radialLayoutItem.setControl(new Ch6RadialLayoutComposite(tf));
6.6 Summary
When you’re using SWT, choosing a layout is often an exercise of weighing flexi-
bility versus complexity. The available options range from the simple FillLay-
out, which makes all your controls as large as can be such that they all fit; to
RowLayout, which lets you position controls in rows or columns; to the more com-
plicated GridLayout and FormLayout, which allow more advanced positioning
but require more planning and more code to use. No single layout is the correct
choice for all situations, but by knowing the options that are available, you can
make appropriate trade-offs for your application. You can use simple layouts to
get quick results when the UI isn’t complicated, and advanced layouts can create a
good-looking interface when required.
In addition to the layouts, you’ll be using a variety of data classes. Each data
class is associated with a specific layout that knows how to use it. Instances of these
data classes are attached to individual controls to fine-tune the way they’re laid
out by the algorithms embedded in the layout classes.
133
Graphics
This chapter covers
■ The graphic context
■ Working with colors
■ Programming with fonts
■ Manipulating images
134 CHAPTER 7
Graphics
The main reason for the popularity of the SWT/JFace toolset is its use of the oper-
ating system’s native widgets. Most users, accustomed to their operating system,
prefer applications that resemble their environment. They want widgets that look
and operate similarly from one GUI to the next. But sometimes, a developer needs
to go beyond built-in parts and create components of his own. Customized con-
trols add a sense of individuality to a user interface, and images may be necessary
for visually oriented applications. In these situations, it’s necessary to understand
the graphics capabilities of the SWT/JFace toolset.
This chapter’s goal is to provide that understanding. To meet this goal, we’ll
proceed from general concepts to specific applications. The first section will
describe the class that makes the toolset’s graphical capability possible: the graphic
context. Then, we’ll explain how SWT works with colors and how JFace makes this
easier. The third section will show how SWT and JFace allow applications to use
text with different fonts and graphical properties. Finally, we’ll show how the SWT
and JFace libraries create and modify images, and when to use the methods of
one library over the other.
7.1 The graphic context
The graphic context functions like a drawing board on top of a Control. It lets
you add custom shapes, images, and multifont text to GUI components. It also
provides event processing for these graphics by controlling when the Control’s
visuals are updated.
In SWT/JFace, the graphic context is encapsulated in the GC class. GC objects
attach to existing Controls and make it possible to add graphics. This section will
deal with how this important class and its methods operate.
7.1.1 Creating a GC object
The first step in building a graphically oriented application is creating a graphic
context and associating it with a component. The GC constructor method per-
forms both tasks. The two available constructor methods are shown in table 7.1.
Table 7.1 The constructor methods of the GC class and their functions
Color constructor Function
GC(Drawable) Creates a GC and configures it for the Drawable object
GC(Drawable, int) Creates and configures a GC and sets the text-display style
The graphic context 135
The style constant mentioned in the second constructor determines how text
appears in the display. The two values are RIGHT_TO_LEFT and LEFT_TO_RIGHT; the
default style is LEFT_TO_RIGHT.
The first argument requires an object that implements the Drawable interface.
This interface contains methods that relate to the internals of a graphic context.
SWT provides three classes that implement Drawable: Image, Device, and Control.
Unless you create your own Drawable objects, you can only add graphics to
instances of these classes or their subclasses. A diagram describing these relation-
ships is presented in figure 7.1. Since Image objects will be covered in a later sec-
tion, we’ll discuss Devices and Controls here.
The Device class represents any mechanism capable of displaying SWT/JFace
objects. This is easier to understand if you consider its two main subclasses:
Printer, which represents print devices, and Display, which accesses a computer’s
console. The Display class, the base class of any SWT/JFace application, is
described in chapter 2. But since this chapter deals with adding graphics to indi-
vidual components, we’ll associate our GC with the third Drawable class, Control.
As we mentioned in chapter 3, a Control object is any widget that has a coun-
terpart in the underlying operating system. Instances of this class and its sub-
classes can be resized, traversed, and associated with events and graphics.
Figure 7.1 shows some of the Control subclasses provided in SWT. Although of
all them can contain graphics, only one class is particularly suited for GC objects:
Canvas, shown at the bottom of figure 7.1. This class not only provides the
Device Image
Composite Composite Button Scrollable Label
Composite
Group Canvas TabFolder
Drawable
(Interface)
Control
Figure 7.1 Only classes that implement the Drawable interface can have
graphic contexts associated with them.
136 CHAPTER 7
Graphics
containment property of a Composite, but also can be customized with a num-
ber of styles that determine how graphics are shown in its region.
Because of this, the code in this chapter will focus on creating images in Canvas
objects. Since we have a means of creating graphics (the GC class) and a means of
seeing them displayed (the Canvas class), let’s see how these classes work together.
7.1.2 Drawing shapes on a Canvas
A full graphical application, DrawExample.java, is shown in listing 7.1. It uses a GC
object to draw lines and shapes on a Canvas instance.
package com.swtjface.Ch7;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
public class DrawExample
{
public static void main (String [] args)
{
Display display = new Display();
Shell shell = new Shell(display);
shell.setText("Drawing Example");
Canvas canvas = new Canvas(shell, SWT.NONE);
canvas.setSize(150, 150);
canvas.setLocation(20, 20);
shell.open ();
shell.setSize(200,220);
GC gc = new GC(canvas);
gc.drawRectangle(10, 10, 40, 45);
gc.drawOval(65, 10, 30, 35);
gc.drawLine(130, 10, 90, 80);
gc.drawPolygon(new int[] {20, 70, 45, 90, 70, 70});
gc.drawPolyline(new int[] {10,120,70,100,100,130,130,75});
gc.dispose();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
}
Listing 7.1 DrawExample.java
Create Canvas
object in shell
Create graphic
context in Canvas
Deallocate Color
object when finished
The graphic context 137
Figure 7.2 shows the GUI created by the
DrawExample class.
This example demonstrates two important
concerns to keep in mind when you work with
GCs. First, the program constructs its Canvas
object before invoking the shell.open()
method; it creates and uses the GC object after-
ward. This sequence is necessary since open()
clears the Canvas display. This also means that
graphic contexts must be created in the same
class as the Shell object. Second, the program
deallocates the GC object immediately after its
last usage. Doing so frees up computer
resources quickly without affecting the draw-
ing process.
Along with those used in DrawExample.java, the GC class provides a number of
methods that draw and fill shapes on a Drawable object. These are listed in table 7.2.
Table 7.2 Drawing methods of the GC class
Method Function
drawArc(int x, int y, int width, int height,
int startAngle, int arcAngle)
Draws a curve with the given starting point
and parameters
fillArc(int x, int y, int width, int height,
int startAngle, int arcAngle)
Draws and fills an arc with the background
color
drawFocus(int x, int y, int width, int
height)
Draws a focus rectangle with the given
vertices
drawLine(int x1, int y1, int x2, int y2) Draws a line between coordinates
drawOval(int x, int y, int width, int height) Draws an oval with the given center point and
dimensions
fillOval(int x, int y, int width, int height) Fills an oval with the given dimensions
drawPolygon(int[] pointArray) Draws a closed figure with the given vertices
fillPolygon(int[] pointArray) Fills a closed figure with points
drawPolyline(int[] pointArray) Draws a line with multiple segments and the
specified endpoints
drawRectangle(int x, int y, int width, int
height)
Draws a rectangle with the given starting
point and coordinates
continued on next page
Figure 7.2
Creating shapes on a Canvas
using the graphic context
138 CHAPTER 7
Graphics
One problem with DrawExample is that its shapes are erased whenever the shell is
obscured or minimized. This is an important concern, since we need to make
sure the graphics remain visible despite windowing changes. For this purpose,
SWT lets you control when a Drawable object is refreshed. This updating process
is called painting.
7.1.3 Painting and PaintEvents
When a GC method draws an image on a Drawable object, it performs the painting
process only once. If a user resizes the object or covers it with another window, its
graphics are erased. Therefore, it’s important that an application maintain its
appearance whenever its display is affected by an external event.
These external events are called PaintEvents, and the interfaces that receive
them are PaintListeners. A Control triggers a PaintEvent any time its appearance
is changed by the application or through outside activity. These classes are used in
a similar manner to the events and listeners mentioned in chapter 4. The follow-
ing snippet shows an example; because a PaintListener has only one event-
handling method, no adapter class is necessary:
Canvas canvas = new Canvas(shell, SWT.NONE);
canvas.setSize(150, 150);
canvas.setLocation(20, 20);
canvas.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent pe)
{
GC gc = pe.gc;
gc.drawPolyline(new int[] {10,120,70,100,100,130,130,75});
}
fillRectangle(int x, int y, int width, int
height)
Draws and fills a rectangle with the given
coordinates
drawRectangle(Rectangle rect) Draws a rectangle based on an object
fillRectangle(Rectangle rect) Fills a rectangle based on an object
drawRoundRectangle(int x, int y, int width,
int height, int arcWidth, int arcHeight)
Creates a rounded rectangle with the given
width, height, and arc dimensions
fillGradientRectangle(int x, int y, int
width, int height, boolean vertical)
Draws and fills a rectangle with a gradient
from the foreground to the background color
Table 7.2 Drawing methods of the GC class (continued)
Method Function
The graphic context 139
});
shell.open();
An interesting aspect of using PaintListeners is that each PaintEvent object con-
tains its own GC. This is important for two reasons. First, because the GC instance is
created by the event, the PaintEvent takes care of its disposal. Second, the appli-
cation can create the GC before the shell is opened, which means that graphics can
be configured in a separate class.
SWT optimizes painting in PaintListener interfaces, and its designers strongly
recommend painting with Controls only in response to PaintEvents. If an applica-
tion must update its graphics for another reason, they recommend using the con-
trol’s redraw() method, which adds a paint request to the queue. Afterward, you
can invoke the update() method to process all the paint requests associated with
the object.
It’s important to remember that, although painting in a PaintListener is rec-
ommended for Control objects, Device and Image objects can’t use this interface.
If you need to create graphics in an image or device, you must create a separate GC
object and dispose of it when you’re finished.
7.1.4 Clipping and Canvas styles
By default, the area available for drawing with a graphic context is the same as
that of its associated Control. However, the GC provides methods that establish
bounds for its own graphical region, called the clipping region. The setClipping()
method specifies the limits for the GC’s graphics, and the getClipping() method
returns the coordinates of the clipping region.
The concept of clipping is also important when you’re dealing with Paint-
Events. Not only do these events fire whenever a Drawable object is covered by
another window, but they also keep track of the area being obscured. That is, if a
user covers part of a Canvas with a second window, the PaintEvent determines
which section has been clipped and sets its x, y, height, and width fields according
to the smallest rectangle that encloses the concealed region. This is necessary
since repainting refreshes only this clipped region, not the entire object.
If multiple sections of a Control object are obscured, then by default, the
object merges these sections into a single region and requests that it be repainted.
However, if an application requires that separate requests be made for each con-
cealed area, then the Control should be constructed with the NO_MERGE_PAINTS
style. This is the first of the styles associated with the Composite class but specifi-
cally intended for Canvas objects. The rest of these styles are shown in table 7.3.
140 CHAPTER 7
Graphics
Normally, when a user clicks a window, any keyboard input is directed to it. This
property is called focus behavior, and you can remove it from a Canvas object by con-
structing the object with the NO_FOCUS style. Similarly, when a Canvas is resized, a
PaintEvent is triggered by default and the display is repainted. You can change this
default behavior by using the NO_REDRAW_RESIZE style. It’s important to note,
though, that using this style may cause graphical artifacts during a resize operation.
Before a graphic context draws its images, its Canvas paints itself with the color
of its shell, the default background color. These paint operations can cause screen
flicker on certain displays. You can prevent this by using the NO_BACKGROUND style,
which prevents the first painting. Without a background color, the graphic con-
text must cover every pixel of the Canvas, or it will take the appearance of the
screen behind the shell.
Now that we’ve begun discussing the colors associated with graphic contexts,
let’s pursue this important topic in detail.
7.2 Programming with colors
One of the fundamental aspects of any graphical toolset is its use of colors. The
theory behind colors is straightforward, but their practical usage requires expla-
nation. This section will discuss how colors are represented in SWT and how to
allocate and deallocate them in a program. It will also discuss two classes provided
by the JFace library that simplify the process of working with colors.
7.2.1 Color development with SWT
Because monitors use light to provide color, it makes sense to use light’s primary
colors—red, green, and blue (RGB)—to represent the colors of a display. This
color system is additive, which means that colors are generated by adding red,
green, and blue elements to a black field. For example, if 24 bits are used to specify
Table 7.3 Style options for Canvas objects
Style Function
NO_MERGE_PAINTS Keeps concurrent paint requests separate
NO_FOCUS Specifies that Canvas can’t receive focus
NO_REDRAW_RESIZE Specifies that Canvas doesn’t repaint itself if
resized
NO_BACKGROUND Specifies that Canvas has no default back-
ground color
Programming with colors 141
the RGB value at a point, then black (the absence of light) is represented in hexa-
decimal as 0x000000, and white (the combination of light) as 0xFFFFFF. SWT fol-
lows this course by providing classes and methods that access and use RGB objects.
This concept may seem simple, but SWT’s designers faced a serious challenge
in implementing it on multiple platforms. The problem involved providing a stan-
dard set of colors despite variations in display resolution and color management
policy. In the end, they decided on a two-part solution.
First, SWT provides a set of 16 basic colors (called system colors) using the dis-
play’s getSystemColor() method. This method takes an integer representing one
of SWT’s color constants and returns a Color object. These constants are listed in
table 7.4 with their RGB representations.
If you want to use colors that fall outside this set, you must allocate a Color object
according to its RGB values. You do so by invoking one of two constructor methods
Table 7.4 Default system colors provided by SWT
SWT color constant Color hex value
SWT.COLOR_BLACK 0x000000
SWT.COLOR_DARK_GRAY 0x808080
SWT.COLOR_GRAY 0xC0C0C0
SWT.COLOR_WHITE 0xFFFFFF
SWT.COLOR_RED 0xFF0000
SWT.COLOR_DARK_RED 0x800000
SWT.COLOR_MAGENTA 0xFF00FF
SWT.COLOR_DARK_MAGENTA 0x800080
SWT.COLOR_YELLOW 0xFFFF00
SWT.COLOR_DARK_YELLOW 0x808000
SWT.COLOR_GREEN 0x00FF00
SWT.COLOR_DARK_GREEN 0x008000
SWT.COLOR_CYAN 0x00FFFF
SWT.COLOR_DARK_CYAN 0x008080
SWT.COLOR_BLUE 0x0000FF
SWT.COLOR_DARK_BLUE 0x000080
142 CHAPTER 7
Graphics
associated with the Color class, shown in table 7.5. If a display’s resolution is too
low to show this color, then it will use the system color with the nearest RGB value.
In both constructors, the first argument is an object of the Device class. Afterward,
the color’s RGB value is set according to three integers between 0 and 255, or an
instance of the RGB class. This RGB class, whose constructor is RGB(int, int, int),
is used to describe a color according to the values of its elements. It’s important to
remember that creating an RGB instance doesn’t create a color and that an RGB
object doesn’t require disposal.
The code in listing 7.2 creates a Canvas that displays colored two shapes. At this
point, we recommend that you create a package named com.swtjface.Ch7 in the
WidgetWindow project and add the Ch7_Colors class.
package com.swtjface.Ch7;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
public class Ch7_Colors extends Canvas
{
public Ch7_Colors(Composite parent)
{
super(parent, SWT.NONE);
setBackground(this.getDisplay().
getSystemColor(SWT.COLOR_DARK_GRAY));
addPaintListener(drawListener);
}
PaintListener drawListener = new PaintListener()
{
public void paintControl(PaintEvent pe)
{
Display disp = pe.display;
Color light_gray = new Color(disp, 0xE0, 0xE0, 0xE0);
GC gc = pe.gc;
gc.setBackground(light_gray);
Table 7.5 The constructor methods of the Color class
Color constructor Function
Color(Device, int, int, int) Allocates a color according to separate RGB values
Color(Device, RGB) Allocates a color according to a given RGB object
Listing 7.2 Ch7_Colors.java
Use system color for
Canvas background
Create Color
object based
on RGB
value
Programming with colors 143
gc.fillPolygon(new int[] {20, 20, 60, 50, 100, 20});
gc.fillOval(120, 30, 50, 50);
light_gray.dispose();
}
};
}
This code demonstrates the two ways that applications can obtain and use color.
In the constructor, the getSystemColor() method returns a basic color,
SWT.COLOR_DARK_GRAY, which doesn’t need to be disposed of. The graphic context
created by the PaintEvent allocates resources for a new color using the Color()
constructor. This color, light_gray, is created using three hexadecimal values cor-
responding to the desired amounts of red, green, and blue. After its last use, the
light_gray color is deallocated. These colors are shown in figure 7.3.
In both cases, a Display object is needed in order to generate a color. This is
done by using the getDisplay() method associated with the Canvas. But the
PaintListener interface can’t access the constructor’s members. Instead, it uses
the PaintEvent’s display field.
The two uses of setBackground() play significant roles in assigning colors. In
the class constructor, this method sets the background color of the Canvas, which
is DARK_GRAY. This method is used again to add color to the PaintEvent’s GC, which
is the color of the triangle and oval. It’s worth noting that the setForeground()
method isn’t needed at all.
Working with SWT colors is a straightforward process, but there are ways to
make it even simpler. For this purpose, JFace provides classes that reduce the work
of managing colors.
Deallocate Color object
when finished
Figure 7.3 The program uses the system color SWT.COLOR_DARK_GRAY
and creates the color light_gray according to its RGB values.
144 CHAPTER 7
Graphics
7.2.2 Additional color capability with JFace
JFace uses the same color methodology as SWT. It also provides two interesting
classes to simplify color manipulation: JFaceColors, located in the org.eclipse.
jface.resource package; and ColorSelector, located in the org.eclipse.jface.
preference package.
The JFaceColors class
The JFaceColors class contains a number of static methods that you can use to
obtain colors in an Eclipse Workbench application. getBannerBackground()
returns the color of an application’s banner, and getErrorBorder() returns the
border color of widgets that display errors. There are also methods that return
colors of different kinds of text.
The JFaceColors class also provides a useful method that can be invoked in
both SWT and JFace applications: setColors(), which you can use to set both the
foreground and background colors of a widget at once. The following code snip-
pet makes the button’s foreground color red and its background color green:
Button button = new Button(parent, SWT.NONE);
red = display.getSystemColor(SWT.COLOR_RED);
green = display.getSystemColor(SWT.COLOR_GREEN);
JFaceColors.setColors(button,red,green);
There is also a disposeColors() method, which despite its described capability of
deallocating all colors at once, can’t replace the dispose() method in the Color
class. Instead, it’s meant to perform additional tasks when the workbench disposes
of its color resources.
The ColorSelector class
Another class offered by the JFace toolset lets the user choose colors in an applica-
tion. Although the ColorSelector is part of JFace’s Preference framework, we felt
it necessary to mention its capability here. In essence, this class adds a button to
an instance of SWT’s ColorDialog class. An example is shown in figure 7.4.
The ColorSelector sets and retrieves the RGB value corresponding to the
user’s selection. The setColorValue() method sets the default selection as the dia-
log box is created. The getColorValue() method converts the user’s selection into
an RGB object that can be used to allocate the color. This is shown in the following
code snippet:
ColorSelector cs = new ColorSelector(this);
Button button = cs.getButton();
RGB RGBchoice = cs.getColorValue();
Displaying text with fonts 145
Color colorchoice = new Color(display, RGBchoice);
Colors improve the appearance of a GUI, but they don’t convey useful informa-
tion. A proper user interface needs to communicate with the user. This means
adding text, which means working with resources that control how text is pre-
sented. These resources are called fonts.
7.3 Displaying text with fonts
Like working with colors, programming with fonts is simple to understand, but
there are important details to consider. This section will present the means of
choosing, allocating, and deallocating fonts with the SWT toolset. Then, we’ll
show you how to simplify these tasks with JFace.
In keeping with its goal of maintaining a native look and feel, the SWT/
JFace toolkit relies primarily on fonts provided by the operating system.
Unfortunately, these fonts vary from one platform to another. Therefore, when
this section describes a font’s name, it means the name of one of the fonts
installed on your system.
7.3.1 Using fonts with SWT
SWT provides a number of font-related classes that perform one of three func-
tions. The first involves font management—allocating and deallocating Font
objects. The second function is implementing fonts in objects to change the
Figure 7.4
The ColorSelector allows users
to select an RGB object.
146 CHAPTER 7
Graphics
display of their text. Finally, SWT contains methods that provide measurements of
text dimensions for use in graphical applications.
Font management
Just as RGB objects contain the information needed to create Color objects, Font-
Data objects provide the basic data for creating Font instances. This data consists
of three parts, which are also the three arguments to the most common FontData
constructor method:
FontData(String name, int height, int style)
The first argument represents the name of the font, such as Times New Roman or
Arial. The height refers to the number of points in the font, and the style repre-
sents the type of font face: SWT.NORMAL, SWT.ITALIC, or SWT.BOLD.
In addition, you can customize a FontData object by specifying its locale (the
application’s geographic location and the set of characters that should be used).
A font’s locale can be determined by invoking the getLocale() method and speci-
fied with setLocale().
Neither RGB or FontData instances need to be disposed of, but Font objects
require allocation and deallocation. Table 7.6 presents the constructor methods
available for the Font class.
There is only one deallocation method for the Font class: dispose(). You should
invoke it shortly after the Font’s last usage.
Implementing fonts in objects
In SWT, fonts are generally associated with one of two GUI objects: Controls and GCs.
When you use the setFont() method associated with Controls, any text presented
with a setText() method is displayed with the specified font. Graphic contexts also
use the setFont() method, but they provide a number of different methods for
painting text in its clipping region. These methods are shown in table 7.7.
Table 7.6 Constructor methods of the Font class
Font constructor Function
Font(Device, FontData) Allocates a font according to its FontData object
Font(Device, FontData[]) Allocates a font according to an array of FontData
Font(Device, String, int, int) Allocates a font based on its name, size, and style
Displaying text with fonts 147
Because of the overloaded drawString() and drawText() methods, this table
requires some explanation. Although implementations of drawString() and
drawText() have the same argument types and functions, the difference is that
drawText() processes carriage returns and tab expansions, whereas drawString()
disregards them. Also, the two integers following the String argument represent
the coordinates of the text display.
The Boolean argument in the second and fourth methods indicates whether
the text background should be transparent. If this value is set to TRUE, then the
color of the rectangle containing the text won’t be changed. If it’s FALSE, the color
of the rectangle will be set to that of the graphic context’s background.
The third integer in the last drawText() method represents a flag that changes
the text display. These flags are as follows:
■ DRAW_DELIMITER—Displays the text as multiple lines if necessary
■ DRAW_TAB—Expands tabs in the text
■ DRAW_MNEMONIC—Underlines accelerator keys
■ DRAW_TRANSPARENT—Determines whether the text background will be the
same color as its associated object
Many of these flags are implemented in the code that follows.
Measuring font parameters
When incorporating text in GUIs, you may want to know the text’s dimensions,
which means knowing the measurements of a given font. SWT provides this
Table 7.7 Text methods of the graphic context (GC) class
Graphic context text method Function
drawString(String, int, int) Displays String with the given coordinates
drawString(String, int, int, Boolean) Displays String with the given coordinates and
background
drawText(String, int, int) Displays String with the given coordinates
drawText(String, int, int, Boolean) Displays String with the given coordinates and
background
drawText(String, int, int, int) Displays String with the given coordinates and
flags
148 CHAPTER 7
Graphics
information through its FontMetrics class, which contains a number of methods
for determining these parameters. These are shown in table 7.8.
This class has no constructor methods. Instead, the GC object must invoke its get-
FontMetrics() method. It returns a FontMetrics object for the font used in the
graphic context and lets you use the listed methods. Each returns an integer that
measures the given dimension according to the number of pixels.
Now that we’ve described the management, integration, and measurement of
fonts, it’s important to use these classes and methods in actual code.
7.3.2 Coding with fonts
The class Ch7_Fonts, shown in listing 7.3, extends Canvas and creates a graphic
context that draws text with a chosen font. When the user clicks a button, a Font-
Dialog instance opens. This dialog determines which fonts are available on the
platform and lets the user choose the name, size, and style of the text in the Can-
vas. Once the user has chosen, the graphic context displays the text dimensions
by invoking its getFontMetrics() method.
This class will be added to WidgetWindow, so we recommend placing Ch7_Fonts
in the com.swtjface.Ch7 package.
Table 7.8 Measurement methods of the FontMetrics class
FontMetrics text method Function
getAscent() Returns the distance from the baseline to the top of the characters
getAverageCharWidth() Returns the width of an average character
getDescent() Returns the distance from the baseline to the bottom of the charac-
ters
getHeight() Returns the sum of the ascent, the descent, and the leading area
getLeading() Returns the distance between the top of the characters and raised
marks
Displaying text with fonts 149
package com.swtjface.Ch7;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
public class Ch7_Fonts extends Canvas
{
static Shell mainShell;
static Composite comp;
FontData fontdata;
public Ch7_Fonts(Composite parent)
{
super(parent, SWT.BORDER);
parent.setSize(600, 200);
addPaintListener(DrawListener);
comp = this;
mainShell = parent.getShell();
Button fontChoice = new Button(this, SWT.CENTER);
fontChoice.setBounds(20,20,100,20);
fontChoice.setText("Choose font");
fontChoice.addMouseListener(new MouseAdapter()
{
public void mouseDown(MouseEvent me)
{
FontDialog fd = new FontDialog(mainShell);
fontdata = fd.open();
comp.redraw();
}
});
}
PaintListener DrawListener = new PaintListener()
{
public void paintControl(PaintEvent pe)
{
Display disp = pe.display;
GC gc = pe.gc;
gc.setBackground(pe.display.getSystemColor(SWT.COLOR_DARK_GRAY));
if (fontdata != null)
{
Font GCFont = new Font(disp, fontdata);
gc.setFont(GCFont);
FontMetrics fm = gc.getFontMetrics();
gc.drawText("The average character width for this font is " +
fm.getAverageCharWidth() + " pixels.", 20, 60);
gc.drawText("The ascent for this font is " +
fm.getAscent() + " pixels.", 20, 100, true);
Listing 7.3 Ch7_Fonts.java
Open FontDialog
box in Canvas
Create Font based
on user choice
Measure properties of
chosen font
150 CHAPTER 7
Graphics
gc.drawText("The &descent for this font is " + fm.getDescent()+
" pixels.", 20, 140, SWT.DRAW_MNEMONIC|SWT.DRAW_TRANSPARENT);
GCFont.dispose();
}
}
};
}
Once the user clicks the Choose Font button, the MouseEvent handler creates an
instance of a FontDialog and makes it visible by invoking the dialog’s open()
method. This method returns a FontData object, which is used in the DrawLis-
tener interface to create a font for the graphic context. This GC object, created by
the PaintEvent, then invokes its getFontMetrics() method to measure the param-
eters of the font.
When the graphic context sets its foreground color to SWT.COLOR_DARK_GRAY,
this usually means that all text created by the GC will be surrounded by this color.
However, as you can see in figure 7.5, only the first drawText() method is sur-
rounded by the foreground color; this is because the second and third invocations
are considered transparent and take the color of the underlying Canvas. The third
drawText() method also enables mnemonic characters, which means that an
ampersand (&) before a letter results in the display underlining this character.
This is shown in figure 7.5 by the underlined d in the third sentence.
In the DrawListener interface, a great deal of the processing is performed only
after the FontData object has been set by the FontDialog. This is necessary since
errors will result if the FontData argument is null. Also, since the graphic context
only draws its text after a PaintEvent, the MouseAdapter ends by invoking the
redraw() method, which causes the Canvas to repaint itself.
7.3.3 Improved font management with JFace
As we mentioned in section 7.3.1, one of the main functions of SWT’s graphics
is to provide font management—the allocation and deallocation of font
resources. This can be accomplished with the Font constructor and dispose()
methods, but there is no efficient way to manage multiple fonts in a single
application. JFace provides this capability with its FontRegistry class, located in
the org.eclipse.jface.resource package.
By using a FontRegistry, you don’t need to worry about the creation or dis-
posal of Fonts. Instead, the FontRegistry’s put() method lets you match a String
value with a corresponding FontData[] object. This method can be invoked multi-
ple times to add more Fonts to the registry. Then, when the application needs a
Displaying text with fonts 151
new Font to change its text display, it calls the registry’s get() method, which
returns a Font object based on the argument’s String value. This is shown in the
following example code:
FontRegistry fr = JFaceResources.getFontRegistry();
fr.put("User_choice", fontdialog.getFontList());
fr.put("WingDings", WDFont.getFontData());
Font choice = fr.get("User_choice");
Rather than create an empty registry, this code uses the preexisting FontRegistry
associated with JFace and adds two more fonts. The first font is placed in the regis-
try from the result of a FontDialog selection, and the second is taken from a font
that existed previously in the application. In the last line, the FontRegistry con-
verts the FontData[] object associated with the FontDialog into a Font instance.
Just as the FontRegistry manages the creation of this font, it also performs its dis-
posal, as well as that of every font in its registry.
The fonts in the FontRegistry include those used in the Eclipse Workbench’s
banners and dialog boxes. However, you need the JFaceResources class to access
them. The following code shows how this can be performed. It’s important to
note that the Strings used to invoke the registry’s get() method, as well as the
FontRegistry itself, are member fields in JFaceResources:
Figure 7.5 The user interface for Ch7_Fonts.java. This application
combines the many elements of SWT font manipulation.
152 CHAPTER 7
Graphics
FontRegistry fr = JFaceResources.getFontRegistry();
Font headFont = fr.get(JFaceResources.HEADER_FONT);
Font dialogFont = fr.get(JFaceResources.DIALOG_FONT);
Table 7.9 lists these fonts with their String values and functions.
Although the String value in the left column remains the same across multiple
platforms, the font to which it refers may vary. For example, on Linux, the Banner
font is Adobe Courier, Boldface, at 14 pitch. On MacOS, the default Banner font
is Lucida Grande, Bold, at 12 pitch.
Having progressed from colors to fonts, we need to discuss graphics that convey
even more information: images. After all, a picture is worth a thousand words…
7.4 Incorporating images in graphics
Although the subject of manipulating images is more complicated than fonts or
colors, there are fewer concerns with platform dependence. Different operating
systems and applications may support divergent file types, but many image for-
mats have become so prevalent that they are supported on nearly all systems. The
code examples in this section work exclusively with these common image types.
As this section will make clear, working with images is similar to working with
fonts. SWT provides classes and methods for image management and integration
in much the same way that it provides for font handling. Also, JFace provides
built-in resources and registries that reduce the amount of complexity involved
with image management.
7.4.1 Allocating images
Most applications only create Image objects to add existing image files to a user
interface. In this case, you should use the first and simplest of the Image construc-
tor methods:
Table 7.9 Fonts available in the JFace FontRegistry
Access String Font function
JFaceResources.BANNER_FONT Font used in JFace banners
JFaceResources.DEFAULT_FONT Standard JFace font
JFaceResources.DIALOG_FONT Font used in JFace dialogs
JFaceResources.HEADER_FONT Font used in JFace headers
JFaceResources.TEXT_FONT Font used for Workbench text
Incorporating images in graphics 153
Image(Device, String)
Applications seeking to present the image in a GUI invoke this method using the
Display object as the first argument and the image file’s pathname as the second. As
of the time of this writing, SWT accepts *.jpg, *.gif, *.png, *.bmp, and *.ico file types.
If the image file resides in the same directory as a known class, then an Input-
Stream can be generated by invoking the class’s getResourceAsStream() method.
With this InputStream, you can use the second constructor method:
InputStream is = KnownClass.getResourceAsStream("Image.jpg");
Image Knownimage = new Image(Display, is);
The full list of overloaded Image constructor methods is shown in table 7.10.
The third and fourth constructor methods create empty Image instances with
dimensions set by the method’s arguments. The two integers specify the x and y
parameters of the image, and the Rectangle object in the fourth method frames
the image according to its boundaries. The fifth creates an Image based on a sec-
ond Image instance and an integer flag that determines whether the image should
appear disabled or in grayscale.
The last two constructor methods construct Image instances using objects of
the ImageData class. This class provides device-independent information about an
Image object and contains methods to manipulate the image. Like the FontData
class, instances of ImageData don’t use operating system resources and don’t
Table 7.10 Constructor methods for the Image class
Constructor method Function
Image(Device, String) Creates an Image using an existing file
Image(Device, InputStream) Creates an Image using an InputStream from an exist-
ing image
Image(Device, int, int) Creates an empty Image with the given dimensions
Image(Device, Rectangle) Creates an empty Image with the dimensions of a Rect-
angle
Image(Device, Image, int) Creates an Image based on another Image and a set
parameter
Image(Device, ImageData) Creates an Image according to information in the
ImageData
Image(Device, ImageData, ImageData) Creates an Image (icon) according to an ImageData
object and a second ImageData object that determines
transparency
154 CHAPTER 7
Graphics
require deallocation. Image instances, however, need to invoke their dispose()
methods when they’re no longer in use.
The ImageData class and its ability to incorporate effects in images will be
explored in greater depth shortly. First, it’s important for you to understand how
images are integrated in applications.
7.4.2 Coding graphics with images
The process of adding an Image to a GUI begins with creating a graphic context.
This GC object then calls its drawImage() method, which takes one of two forms,
based on whether the image will be presented with its original dimensions. This
method is presented in the code that follows.
In chapter 4, we used a standard Eclipse image to show how the Action class
functions. To fully show SWT’s image capabilities, we need a larger image. There-
fore, we recommend that you copy eclipse_lg.gif from $ECLIPSE_HOME/
plugins/org.eclipse.platform_x.y.z and add it to the com.swtjface.Ch7 package.
This way, any class in the package will be able to work with this image.
However, the following snippet is presented only to demonstrate how an Image
object works in a graphic context:
public class ImageTest extends Composite
{
public ImageTest(Composite parent)
{
super(parent, SWT.NONE);
parent.setSize(320,190);
InputStream is = getClass().getResourceAsStream("eclipse_lg.gif");
final ImageData eclipseData = new ImageData(is).scaledTo(87,123);
this.addPaintListener(new PaintListener()
{
public void paintControl(PaintEvent pe)
{
GC gc = pe.gc;
Image eclipse = new Image(pe.display, eclipseData);
gc.drawImage(eclipse, 20, 20);
gc.drawText("The image height is: " + eclipseData.height +
" pixels.",120,30);
gc.drawText("The image width is: " + eclipseData.width +
" pixels.",120,70);
gc.drawText("The image depth is: " + eclipseData.depth +
" bits per pixel.",120,110);
eclipse.dispose();
}
});
}
}
Create ImageData
object from file
Create Image
from ImageData
Incorporating images in graphics 155
This code begins by constructing an ImageData object using an InputStream. In
this case, it makes sense to start with an ImageData instance since Image objects
can’t be resized or recolored. This resizing process is performed using the
scaleTo() method, which shrinks the image for the GUI. This new image is shown
in figure 7.6.
When a PaintEvent occurs, the program invokes the paintControl() method.
This method creates the window’s graphic context and an Image object based on
the ImageData. To the right of the image, three statements provide information
regarding the fields of the ImageData instance. It’s worth noting that by changing
the coordinates, you can superimpose the text (or any graphic) on the image.
The code shows how you can ue the ImageData class to obtain information
about images and change their size. However, this class is capable of much more.
But before we can discuss how ImageData creates image effects, you need to fully
understand this class and how it represents images.
7.4.3 Creating a bitmap with ImageData
The easiest way to learn about ImageData is to design, build, and display an
instance of this class. In this case, you’ll create a bitmap and use it to form an
Image. Doing so will introduce many of the fields and methods associated with the
ImageData class and provide a better idea why this class is necessary.
The first step involves determining which colors will be used. Given this book’s
grayscale presentation, we’ll restrict ourselves to shades of gray. To reduce the
amount of programming, we’ll keep the number of different colors to a mini-
mum. With this in mind, this example uses three colors—white, black, and gray—
and combines them into a racing flag bitmap. This isn’t terribly exciting, but it
will be sufficient to show you how to generate ImageData.
Figure 7.6
Although an Image object can
be displayed in a window, the
ImageData instance provides
the information.
156 CHAPTER 7
Graphics
To tell ImageData about the colors you’ll be using, you need to create an
instance of the PaletteData class. This object contains an array of the RGB values
in the image. For the image sketched in figure 7.7, this consists of three elements:
0x000000 (black), 0x808080 (gray), and 0xFFFFFF (white).
Each pixel in an image has three pieces of information: its x coordinate, or off-
set; its y coordinate, or scanline; and the pixel’s color, which is referred to as its
value or index. Because this image contains only three colors, you don’t need to
assign each pixel its full RGB value (0x000000, 0x808080, 0xFFFFFF). Instead, it’s
simpler and less memory-intensive to use the color’s index in the PaletteData
array and assign pixel values of (0, 1, 2). This simplified mapping between a
pixel’s value and color is referred to as an indexed palette. For example, because the
eclipse_lg.gif file used in the last code snippet has a depth of only 8 bits per
pixel, each pixel is assigned a value between 1 and 28 (255).
However, for images with depth greater than 8 bits per pixel, the additional
processing needed to translate between an index and its color isn’t worth the
reduced memory. These images use a direct palette, which directly assigns a pixel’s
value to its RGB value. The isDirect() method in the PaletteData class tells
whether an instance uses direct or indexed conversion.
If you understand how the PaletteData class functions, then coding a bitmap
is straightforward, as shown in listing 7.4. Because this ImageData object will be
integrated in an animated graphic, we recommend that you add this FlagGraphic
class to the com.swtjface.Ch7 package.
Pixel offset (x coordinate)
Pixel
scanline
(y coordinate)
Figure 7.7
Each pixel in an image can be identified by
its offset, scanline, and color value.
Incorporating images in graphics 157
package com.swtjface.Ch7;
import org.eclipse.swt.graphics.*;
public class FlagGraphic
{
public FlagGraphic()
{
int pix = 20;
int numRows = 6;
int numCols = 11;
PaletteData pd = new PaletteData(new RGB[]
{
new RGB(0x00, 0x00, 0x00),
new RGB(0x80, 0x80, 0x80),
new RGB(0xFF, 0xFF, 0xFF)
});
final ImageData flagData = new ImageData(pix*numCols,
pix*numRows, 2, pd);
for(int x=0; x>
IContentProvider Viewer
<>
IInputProvider
<>
ISelectionProvider
<>
IStructuredContentProvider
<>
IInputSelectionProvider
<>
ITreeContentProvider
ViewerFilter
<>
IBaseLabelProvider
ListViewer TableViewer
<>
ILabelProvider
<>
ITableLabelProvider
TreeViewer TableTreeViewer
LabelProvider
ContentViewer
StructuredViewer
AbstractTreeViewer
inputChanged() : void
getElements() : Object[]
getChildren() : Object[]
isLabelProperty() : boolean
getImage() : Image
getText() : String
getColumnImage() : Image
getColumnText() : String
Figure 8.1 An overview of the Viewer framework
170 CHAPTER 8
Working with trees and lists
instance of the appropriate widget and associates it with the new viewer. Alterna-
tively, a constructor taking only a Composite is provided, which instantiates a wid-
get as a child of the given Composite and binds it to the viewer.
Once associated with the widget, viewers typically provide several methods.
The most important of these are easy ways to add elements to and retrieve or
remove elements from the collection of data displayed by the widget. Additionally,
methods to set label providers are implemented at this level. Label providers, dis-
cussed in detail in the next section, generate suitable UI text from domain objects.
The IBaseLabelProvider interface serves as the common interface that all label
providers must implement. More specific interfaces then derive from IBaseLabel-
Provider and are used by individual widget types. The abstract ContentViewer
class defines these methods to take the IBaseLabelProvider interface; but by
implementing the methods here, you can insert checks to ensure that only imple-
mentations of IBaseLabelProvider that are appropriate to the given widget are
added, while the common logic is performed by the superclass.
Most of the methods defined in these base classes won’t be called directly by
your code. Instead, you’ll provide the viewer with a class that implements one of
the interfaces, and the viewer will call methods on your class at the appropriate
time. Table 8.1 summarizes the methods you’ll need to be familiar with to make
proper use of viewers.
8.1.1 Providers
The first subclass of Viewer, ContentViewer, adds functionality for dealing with the
data displayed by a widget, thereby providing the M (Model) in MVC. It’s the role
Table 8.1 Important viewer methods
Method Defined in…
getControl() Viewer
getSelection() Viewer
refresh() Viewer
setInput() Viewer
setContentProvider() ContentViewer
setLabelProvider() ContentViewer
addFilter() StructuredViewer
reveal() StructuredViewer
setSorter() StructuredViewer
Viewers and the Viewer framework 171
of a provider to perform application-specific work to make a piece of data avail-
able to the widget—for example, to return the text that should be displayed to
represent a given domain object in a list. There are two types of providers: Label-
Providers and ContentProviders. The class hierarchies we discuss here are both
shown in figure 8.1; you’ll probably find it helpful to refer back to the diagram as
we explore the various interfaces and classes.
Label providers
Label providers implement either ILabelProvider or ITableLabelProvider, both
of which extend IBaseLabelProvider. ILabelProvider and ITableLabelProvider
are similar in spirit, the only difference being that ITableLabelProvider deals
with table columns, whereas ILabelProvider assumes one-dimensional data.
The logic for label providers revolves around three methods. The first is isLa-
belProperty(), defined in IBaseLabelProvider. Given an object and the name of
a property, the method returns a boolean indicating whether a change to the
given property requires a corresponding update to a visible label. It isn’t manda-
tory, but properties typically conform to JavaBean naming standards: that is, if the
bean has a property name, then a getName() and possibly a setName() method is
defined for the object. isLabelProperty() is called when an object has been
updated by an Editor (see the next section) to optimize drawing operations. If
isLabelProperty() returns false, ContentViewer knows that it isn’t necessary to
redraw the widget.
Subinterfaces of IBaseLabelProvider also provide getText() and getImage()
methods in various forms. Each is given an object, and it’s the responsibility of the
provider to return the text and/or image that should be displayed for that object.
Returning null results in no text or image being displayed. The only difference
between standard label providers and table label providers is that the methods in
ITableLabelProvider take an additional parameter indicating the index of the
column being populated; the concept is otherwise exactly the same.
JFace provides a default implementation of ILabelProvider called LabelPro-
vider, which returns null for all images, along with the result of calling
toString() on the given object for the text. This can be useful for debugging or
getting a prototype running quickly, but you’ll usually need to subclass LabelPro-
vider or provide a new implementation of the interface that performs logic
appropriate to your application. The data returned by toString() typically isn’t
appealing for users to look at.
172 CHAPTER 8
Working with trees and lists
Content providers
In addition to label providers, ContentViewer concerns itself with content provid-
ers. Whereas a label provider provides the text or image to display for an element,
a content provider provides the actual elements to be displayed. IStructuredCon-
tentProvider defines the getElements() method, which is given an Object as
input and returns an array of Objects to display in the widget. When setInput() is
called on the Viewer, the object given as a parameter is passed to the content
viewer. The content provider is then responsible for using that input parameter to
return a collection of domain objects to be displayed by the widget.
A simple example is a content provider that displays information from an XML
file. It could take an input stream as a parameter, parse the XML from the stream,
and then return objects representing various elements of the XML data to be dis-
played by the viewer. It isn’t necessary to use a content provider, however; if you
add() the elements that you wish to display, it will work fine.
Two other methods on IStructuredContentProvider can often be left empty.
The first is dispose(), which the viewer calls when it’s being disposed of; you can
use this method to clean up any allocated resources that the content provider may
be hanging on to. The last method is inputChanged(Viewer viewer, Object old-
Input, Object newInput), which the viewer uses to notify the content provider
that the root input object has changed. Although many applications can safely
ignore this method, the Javadocs suggest its intended use. Suppose your applica-
tion contains domain objects that broadcast events, such as a network resource
that sends notifications when it becomes unavailable. When the viewer’s input is
changed from one of these objects to another, inputChanged() can be used to
unregister the content provider from listening to the old input object and register
for events from the new one.
8.1.2 Listeners
The various viewer classes provide support for a variety of event listeners. The
base Viewer class offers notification of help request and selection changed events.
Moving down the hierarchy, StructuredViewer adds support for double-click
events, and AbstractTreeViewer adds default selections and tree events. Events
and listeners were already discussed in detail in chapter 4; the same principles
that we talked about earlier apply here as well. Listeners are used to implement
the logic behind the application; they make up the Controller portion of MVC.
Viewers and the Viewer framework 173
8.1.3 Filters and sorters
As we mentioned earlier, it’s common to want to sort items before they are dis-
played. This sorting can be done by an infinite variety of parameters, from alpha-
betically sorting contact information in an address book to listing emails by data
received. To perform sorting or similar manipulations of data, the elements need
some sort of structure. Knowledge of this structure comes from the Structured-
Viewer class. The key functionality offered by a StructuredViewer is the ability to
run objects through a filter and sort them before they’re displayed.
Filters are an elegant idea; they help decouple the creation of a group of items
from the act of deciding which ones should be displayed. A natural first inclina-
tion would be to create only the items that should be displayed. However, this
approach lacks flexibility. For each set of objects to display, you must rewrite the
retrieval logic. Additionally, for efficiency reasons, it may make more sense to load
the entire set of objects once and cache them. Making constant round trips to a
database is a sure way to slow your application to a crawl.
In order to use a filter, you’ll load the entire collection once, either by using a
ContentProvider or by add()ing the objects. When it’s time to display the data,
you call StructuredViewer’s addFilter() method, giving it an implementation of
ViewerFilter that only accepts the items to be displayed.
For example, assume we have a list of words. The user can choose to display
only words that start with a certain string. The code is simple. It first defines a filter:
public class SubstringFilter extends ViewerFilter
{
private String filterString;
public SubstringFilter( String s )
{
filterString = s;
}
public boolean select( Viewer viewer,
Object parentElement, Object element )
{
return element.toString().startsWith( filterString );
}
}
Now we can use it on the viewer:
StructuredViewer viewer = ...
//set content provider, etc for the viewer
SubstringFilter filter = new SubstringFilter( "" );
viewer.addFilter( filter );
174 CHAPTER 8
Working with trees and lists
By default, this displays every element, because any string starts with the empty
string. When the user enters a string to filter by, these lines of code update the
display:
viewer.removeFilter( filter );
filter = new SubstringFilter( userEnteredString );
viewer.addFilter( filter );
Calling addFilter() automatically triggers refiltering of the elements, and now
only strings that start with the string entered by the user are displayed. Notice that
there was no need to worry about the original collection of objects. The viewer
still maintains the entire collection; it chooses to display only the ones for which
the filter returns true when select() is called. It’s even possible to have multiple
filters on a viewer; in this case, only items that pass all the filters are displayed.
There is one caveat to be aware of when you’re using a design that revolves
around filters: Although it’s conceptually simpler to load an entire collection and
let the filters handle selection, this approach won’t scale well if your collection
potentially contains millions of items. In this case, you’ll probably have to fall back
on the “load only what you need” method. As always, carefully consider the
demands of your specific application.
Similar in spirit to filters, StructuredViewer also allows custom sorting of its
elements using setSorter() and a ViewerSorter. After all elements have been fil-
tered, the sorter is given a chance to reorder the elements before they are dis-
played. To continue our earlier example, you could use a sorter to alphabetize the
words in the list. The default implementation of ViewerSorter sorts the labels for
each element in a case-insensitive manner. The easiest way to implement your
own ViewerSorter is to override the compare() method, which acts identically to
the compare() method in java.util.Comparator. compare() is given two objects
and returns a negative integer, zero, or a positive integer, to denote less than,
equals, or greater than, respectively.
You can use the isSorterProperty() method to avoid resorting if a given
change wouldn’t change the sort order. If you need more complex comparisons,
you can use the category() method to break elements into different categories,
each of which will be sorted independently. For example, if you have a list of
Order objects, category() could return 1 for inbound orders and 2 for outbound
orders, whereas compare() sorts based upon the order number. The list will then
group all the inbound orders together, sorted by order number, followed by all
the outbound orders, also sorted by order number. This technique is most
Viewers and the Viewer framework 175
effective if there is also a visual cue that corresponds to the different categories.
The following example shows the code used to implement such an approach:
public class OrderSorter extends ViewerSorter
{
public int category(Object element)
{
//assumes all objects are either InboundOrder
//or OutboundOrder
return (element instanceof InboundOrder) ? 1 : 2;
}
public int compare(Viewer viewer, Object e1, Object e2)
{
int cat1 = category(e1);
int cat2 = category(e2);
if( cat1 != cat2 ) return cat1 – cat2;
//Order is the superclass of both InboundOrder
//and OutboundOrder
int firstOrderNumber = ((Order)e1).getOrderNumber();
int secondOrderNumber = ((Order)e2).getOrderNumber();
return firstOrderNumber – secondOrderNumber;
}
}
Notice that this example manually calls category(). This is necessary because
we’ve overridden the compare() method, so if we don’t call category() ourselves,
it won’t be called at all.
Unlike filters, it’s only possible to have one sorter at a time on a given Struc-
turedViewer. Multiple sorters wouldn’t make sense, because each would clobber
the work done by the others.
The default implementation of compare() generates labels for each item and
sorts based on those generated labels. For this reason, the Viewer is passed to the
compare() method. By casting the Viewer to a ContentViewer, the label provider
can be retrieved using getLabelProvider() and used to get the text that will be
displayed for the given element. In the previous example, overriding compare()
thus becomes unnecessary if the label provider is implemented such that it
returns the order number in String form. In that case, you could get away with
implementing category() to differentiate between inbound and outbound orders
and trust the default compare() to correctly group the orders. However, doing so
would introduce coupling between the label provider and the sorter, since if the
label provider changes, the orders may not be sorted correctly. How serious an
issue this might be will vary from application to application.
176 CHAPTER 8
Working with trees and lists
Now that we have all the background out of the way, let’s see some examples of
using these widgets.
8.2 Trees
A tree control displays data in a hierarchal format, allowing a
user to easily see the relationship between different ele-
ments. You’re probably familiar with using Windows
Explorer or a similar tool on your platform of choice to navi-
gate your machine’s file system. The folders on your
machine are displayed, with each subfolder displayed
beneath its parent. Sections of this hierarchy can be
expanded or hidden, allowing you to focus on the section of
the file system that interests you. A tree control lets you pro-
vide similar functionality for any group of objects that has a parent/child relation-
ship, the way folders and subfolders do. Figure 8.2 shows a simple tree.
We’ll first discuss the SWT Tree widget, followed by the TreeViewer from JFace,
which you can use to simplify use of the Tree.
8.2.1 SWT trees
Tree doesn’t have a particularly useful interface. It extends Scrollable and pro-
vides the basic operations outlined in table 8.2.
The items in the tree are a bit more interesting.
TreeItem
TreeItem is the class used to add items to a Tree. In addition to displaying content,
TreeItems maintain a relationship with both parent and child items. A given
Figure 8.2
A tree showing
parent/child
relationships
Table 8.2 Operations available on a tree
Method Description
addSelectionListener() Enables notification of selection events.
addTreeListener() The TreeListener interface provides callbacks for notification
when a level of the tree is expanded or collapsed.
select()/deselect() Modifies the current selection.
getSelection() Retrieves the current selection.
show() Forces the control to scroll until the given item is visible.
Trees 177
item’s parent can be retrieved with getParentItem(), which returns null for an
item at the root of the Tree; getItems() returns the children in the form of an
array of TreeItem.
Two style options are relevant for a Tree. The first is a choice between SWT.SIN-
GLE or SWT.MULTI, which affects how many items may be selected at a time. Tree
defaults to SWT.SINGLE, which means that each time an item is selected, the previ-
ous selection disappears. Using SWT.MULTI lets the user select multiple options in
whatever way is supported by the operating system (usually by Ctrl- or Shift-
clicking multiple entries).
The last style that may be applied is SWT.CHECK, which causes checkboxes to be
drawn to the left of each item in the tree. If checkboxes have been enabled, the
status of any given TreeItem can be queried using the getChecked() method,
which returns a boolean indicating whether the item has been checked. Note that
on some platforms, an item can be selected without being checked.
A parent is set by passing it to the constructor of TreeItem and can’t be modi-
fied from either end of the relationship. Because of the way these relationships
are maintained, removing a single item from a Tree is awkward: You must call
removeAll() to empty the Tree and rebuild its contents, minus the items you wish
to remove.
TreeItems provide methods to modify the text or image displayed in the form
of setText() and setImage(). A TreeItem can be forced to expand or contract
itself using setExpanded(boolean).
You’re welcome to build and display a tree by directly creating and manipulat-
ing TreeItems, but doing so forces you to deal with widgets on a lower level than is
necessary. By using a TreeViewer to handle your tree, you can focus on the logic of
your application rather than on the details of user interface elements.
8.2.2 JFace TreeViewers
A TreeViewer offers the filtering and sorting capabilities common to all Viewers,
as well as the ability to use a label provider. Additionally, a TreeViewer can use an
ITreeContentProvider to populate itself. The ITreeContentProvider interface
extends IStructuredContentProvider to add methods for querying the parent or
children of a given node.
As we mentioned in our earlier discussion of general Viewer features, a con-
tent provider provides an interface to business object relationships. For example,
suppose you need to display the elements of an XML document in a tree to allow
the user to easily navigate between them. Using a Tree and TreeItems directly, this
would require you to loop through all elements in the document, building the
178 CHAPTER 8
Working with trees and lists
items by hand. Using the DOM parsing facilities in JDK 1.4, the resulting
pseudocode looks something like this:
Document document = ... //parse XML
Tree tree = ...
NodeList rootChildren = document.getChildNodes();
for(int i = 0; i < rootChildren.getLength(); i++)
{
Element rootElement = (Element)rootChildren.item(i);
TreeItem item = new TreeItem(tree, NODE_STYLE);
item.setText(rootElement.getTagName());
buildChildren(rootElement, item);
}
...
/*
Recursively builds TreeItems out of the child
nodes of the given Element
*/
private void buildChildren(Element element,
TreeItem parentItem)
{
NodeList children = element.getChildNodes();
for(int i = 0; i < children.length(); i++)
{
Element child = (Element)children.item(i);
TreeItem childItem = new TreeItem(parentItem, NODE_STYLE);
buildChildren(child, childItem);
}
}
In contrast, the code to use a content provider consists of trivial implementations
of methods defined in ITreeContentProvider:
Document document = ... //parse XML document
TreeViewer viewer = ...
viewer.setContentProvider(new XMLContentProvider());
viewer.setInput(document);
viewer.setLabelProvider(XMLLabelProvider());
...
class XMLContentProvider
implements ITreeContentProvider
{
public Object[] getChildren(Object parentElement) {
return toObjectArray(((Node)parentElement).getChildren());
}
public Object[] getElements(Object inputElement) {
return toObjectArray(((Node)inputElement).getChildren())
}
Trees 179
private Object[] toObjectArray(NodeList list){
Object[] array = new Object[list.getLength()];
for(int i = 0; i < list.getLength(); i++) {
array[i] = list.item(i);
}
return array;
}
public Object getParent(Object element) {
return ((Node)element).getParentNode();
}
public boolean hasChildren(Object element) {
return ((Node)element).getChildNodes().getLength() > 0;
}
... //additional methods with empty implementations
}
At first glance, the content provider code takes more space, and in terms of lines
of code it’s longer. However, we would argue that the content provider is both
conceptually simpler and easier to maintain. getChildren() and getElements()
call getChildren() on the current Node and convert the result to an array. Using
Tree, you’re forced to handle the top-level elements differently than the rest of
the items, creating two separate sections of code that must be updated if the
requirements change. More importantly, by using a TreeViewer, content provider,
and label provider, you’re operating directly on your domain objects (in this case,
Nodes of an XML document). If the document changes, the display can be
updated by calling refresh() on the viewer. At runtime, if more detail should be
displayed at each node, an alternate implementation of ILabelProvider can be
assigned to the viewer. If you’re creating a Tree and TreeItems by hand, these
cases require you either to manually traverse the tree to find and update the rele-
vant nodes or to rebuild the entire Tree from scratch. On the whole, use of a con-
tent provider results in a design that is both simpler and more flexible.
It’s worth discussing the hasChildren() method briefly. It’s provided as an opti-
mization hint for the tree. It would be possible to call getChildren() and check
the size of the returned array, but in some cases it may be expensive to get the
children of a given element. If a content provider can determine whether there
are children for a node without having to compute all the children, then return-
ing false here enables the tree to skip calling getChildren() when there aren’t any
children to display. If there is no easy way to calculate this, it’s safe to always return
true from hasChildren() and let getChildren() return an empty array when there
are no children to display.
180 CHAPTER 8
Working with trees and lists
8.3 Using the List widget
A List widget presents a sequence of items. An mp3 player
could use a List to present playlists to the user, whereas
Eclipse uses a List to display possible matching classes when
you choose Open Type. The user can select one or more val-
ues from the list, as shown in figure 8.3.
Again, we’ll cover building lists with the basic SWT classes
and then dive into the more powerful capabilities offered by
ListViewers.
8.3.1 SWT lists
Because the widget is so simple, it’s easy to use a List without an attached Viewer
and still obtain useful results. For example, building a list of Strings requires
nothing more than the following:
List list = new List(parent, SWT.SINGLE);
for( int i = 0; i < 20; i++ )
{
list.add( "item " + i);
}
Like Tree, List supports SWT.SINGLE or SWT.MULTI to control how many items may
be selected simultaneously. No other styles (other than the ones supported by
superclasses) are supported by Tree.
NOTE If you’re developing an SWT application that will run on Motif, you
should be aware that it isn’t possible to absolutely prevent the vertical
scrollbar from being shown on a list. Accordingly, in Motif, SWT.V_SCROLL
is added to whatever other styles you specify for a List in order to ensure
that the style bits match what is displayed.
The List inherits scrolling capability from its superclass, Scrollable. Unless you
specifically change it, the style is assumed to be SWT.V_SCROLL. This means that if
the list of items exceeds the space available, a vertical scrollbar appears to allow
the user to navigate the list. No horizontal scrollbar is available unless you add
SWT.H_SCROLL to the style.
The drawback in our example is that List only accepts instances of String.
Consequently, there is no way to display an image in the list, and updating a
domain object requires searching the List for its old value, removing it, and
replacing with the new one. This approach works fine for simple situations like
Figure 8.3
A simple list
Using the List widget 181
the one shown previously, but eventually you’ll most likely want to do something
more interesting with your List. For that, you’ll need to use a ListViewer.
8.3.2 JFace ListViewers
Using a ListViewer is the preferred way to interact with a List. At its most basic
level, using the viewer allows more options for controlling the behavior of the wid-
get, such as adding an image to each element or changing the order of the items
on the fly without having to rebuild the entire list. It also allows decoupling of
your model data from the way it’s presented.
A ListViewer is instantiated with a parent Composite and an SWT style. The
viewer supports the same styles as the basic List: SWT.SINGLE and SWT.MULTI,
which designate how many items may be selected at the same time.
Although ListViewer provides an add() method that you can use to insert
objects directly into the list, using a ContentProvider, as we did with the Tree-
Viewer, is a good idea. ListViewer uses the IStructuredContentProvider inter-
face. This interface is simple, generally requiring only that the method Object[]
getElements(Object inputElement) be implemented. After setInput() is called
in the viewer, getElements() is called and passed the same object that was set the
input to the viewer.
With all the various helper classes operating on the viewer—content providers,
label providers, filters, sorters—it’s important to understand the way they interact.
Everything starts with the content provider, which returns the entire set of items
that may be displayed. This set is then passed to any filters attached to the viewer,
which have the opportunity to remove items. Any items that pass all filters are
then sorted and finally given to the label provider to determine what to display.
Retrieving items with IStructuredSelection
Up to this point, we haven’t discussed how to retrieve the selected items from a
ListViewer or TreeViewer. Any time you wish to query which items are selected,
JFace provides an interface, IStructuredSelection, to manage the results.
getSelection(), which returns an instance of IStructuredSelection, is pro-
vided by the StructuredViewer class. Being an IStructuredSelection implies that
there is some structure to the data returned—namely, an order. The interface
provides a method to retrieve an iterator for the selected items, the same as the
objects in the Collections framework. This iterator returns items in the same
order in which they appear in the List. Typically, you’ll loop through the items, as
shown here:
182 CHAPTER 8
Working with trees and lists
...
IStructuredSelection selection =
(IstructuredSelection)viewer.getSelection();
for( Iterator i = selection.iterator();
i.hasNext(); )
{
Object item = i.next();
//process item
}
...
If necessary, however, the interface also provides toArray() and toList() meth-
ods to retrieve the entire collection of selected items at once.
8.4 Updating WidgetWindow
Let’s add two new composites to the WidgetWindow, one to demonstrate trees and
the second for lists. First add Ch8TreeComposite, which appears in listing 8.1.
package com.swtjface.Ch8;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
public class Ch8TreeComposite extends Composite
{
public Ch8TreeComposite(Composite parent)
{
super(parent, SWT.NULL);
populateControl();
}
protected void populateControl()
{
FillLayout compositeLayout = new FillLayout();
setLayout(compositeLayout);
int[] selectionStyle = {SWT.SINGLE, SWT.MULTI};
int[] checkStyle = {SWT.NONE, SWT.CHECK};
for(int selection = 0;
selection < selectionStyle.length;
Listing 8.1 Ch8TreeComposite.java
b Styles
Updating WidgetWindow 183
selection++)
{
for(int check = 0; check < checkStyle.length; check++)
{
int style = selectionStyle[selection] | checkStyle[check];
createTreeViewer(style);
}
}
}
private void createTreeViewer(int style)
{
TreeViewer viewer = new TreeViewer(this, style);
viewer.setContentProvider(new ITreeContentProvider() {
public Object[] getChildren(Object parentElement) {
return ((TreeNode)parentElement).getChildren().toArray();
}
public Object getParent(Object element) {
return ((TreeNode)element).getParent();
}
public boolean hasChildren(Object element) {
return ((TreeNode)element).getChildren().size() > 0;
}
public Object[] getElements(Object inputElement) {
return ((TreeNode)inputElement).getChildren().toArray();
}
public void dispose() {}
public void inputChanged(Viewer viewer,
Object oldInput,
Object newInput) {}
});
viewer.setInput(getRootNode());
}
private TreeNode getRootNode()
{
TreeNode root = new TreeNode("root");
root.addChild(new TreeNode("child 1")
.addChild(new TreeNode("subchild 1")));
root.addChild(new TreeNode("child 2")
.addChild( new TreeNode("subchild 2")
.addChild(new TreeNode("grandchild 1"))) );
return root;
}
}
class TreeNode
c ContentProvider
d setInput()
e getRootNode()
f TreeNode
184 CHAPTER 8
Working with trees and lists
{
private String name;
private List children = new ArrayList();
private TreeNode parent;
public TreeNode(String n)
{
name = n;
}
protected Object getParent()
{
return parent;
}
public TreeNode addChild(TreeNode child)
{
children.add(child);
child.parent = this;
return this;
}
public List getChildren()
{
return children;
}
public String toString()
{
return name;
}
}
These two orthogonal style sets cover all possible styles available for a Tree. The
code loops through and combines them to make several sample tree instances,
demonstrating all the different styles.
Here the code defines a ContentProvider, which is used to provide data to the
TreeViewer. Notice that it can assume the parameters to each method are an
instance of the appropriate domain object (TreeNode, in this case) and cast them
accordingly.
Calling setInput() on the viewer starts the process of populating the tree with the
given data.
This method builds the initial collection of domain objects.
This simple class serves as the domain object for the example.
b
c
d
e
f
Updating WidgetWindow 185
This pane creates simple trees three levels deep. We use the class TreeNode to act
as the domain objects. TreeNode’s only function is to maintain a list of children.
The key method to pay attention to is createTreeViewer(), which creates a
new TreeViewer instance and assigns it an ITreeContentProvider. This content
provider receives TreeNodes and knows how to return the children for each node.
Because the domain objects naturally know about their own relationships, imple-
menting the content provider consists of trivially asking each node for its parent
or children and calling toArray() when appropriate. There is no need to convert
objects to Strings in getChildren() or getElements(). You can return the full
domain object and let the label provider (in this case, the default BaseLabelPro-
vider, which calls toString()) worry about how to display them.
After assigning the content provider, you must
remember to call setInput() and pass it the
TreeNode to use as the base of the tree. This step
associates actual domain objects with the viewer;
otherwise the viewer can’t know which objects to
display. This root object is passed to getElements()
to retrieve the first level of children. Each element
in the array returned by getElements() is in turn
passed to getChildren() to build the next level of
the hierarchy. This process continues until has-
Children() returns false or no more children are returned by getChildren().
Figure 8.4 shows the results when you run this example.
To run this example, you must add the following three lines to WidgetWindow:
TabItem chap8Tree = new TabItem(tf, SWT.NONE);
chap8Tree.setText("Chapter 8 Tree");
chap8Tree.setControl(new Ch8TreeComposite(tf));
Next, listing 8.2 presents the Ch8ListComposite, which uses some of the more
advanced viewer features.
package com.swtjface.Ch8;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.Viewer;
Listing 8.2 Ch8ListComposite.java
Figure 8.4 Tree pane
186 CHAPTER 8
Working with trees and lists
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
public class Ch8ListComposite extends Composite
{
public Ch8ListComposite(Composite parent)
{
super(parent, SWT.NULL);
populateControl();
}
protected void populateControl()
{
FillLayout compositeLayout = new FillLayout();
setLayout(compositeLayout);
int[] styles = {SWT.SINGLE, SWT.MULTI};
for(int style = 0; style < styles.length; style++)
{
createListViewer(styles[style]);
}
}
private void createListViewer(int style)
{
ListViewer viewer = new ListViewer(this, style);
viewer.setLabelProvider(new LabelProvider() {
public String getText(Object element) {
return ((ListItem)element).name;
}
});
viewer.addFilter(new ViewerFilter() {
public boolean select(Viewer viewer,
Object parent,
Object element) {
return ((ListItem)element).value % 2 == 0;
}
});
viewer.setSorter( new ViewerSorter() {
public int compare(Viewer viewer,
Object obj1,
Object obj2) {
return ((ListItem)obj2).value - ((ListItem)obj1).value;
}
});
viewer.setContentProvider(new IStructuredContentProvider() {
b Styles
c Filter
d Sorter
Updating WidgetWindow 187
public Object[] getElements(Object inputElement)
{
return ((List)inputElement).toArray();
}
public void dispose() {}
public void inputChanged(Viewer viewer,
Object oldInput,
Object newInput)
{
}
});
List input = new ArrayList();
for( int i = 0; i < 20; i++ )
{
input.add(new ListItem("item " + i, i));
}
viewer.setInput(input);
}
}
class ListItem
{
public String name;
public int value;
public ListItem(String n, int v)
{
name = n;
value = v;
}
}
These two styles are the only ones available for lists. The code creates one of each.
This simple ViewerFilter selects only items whose value field is even. If two divides
cleanly into the value, you return true, which allows the item to be displayed.
This ViewerSorter sorts domain objects by their value field, from high to low.
ListItem acts as the domain object for this example.
This code creates a class ListItem to act as domain objects. ListItem stores a
name and an integer value, which are used for ordering and filtering.
Because a List handles only simple data with no relationships between ele-
ments, implementing the IStructuredContentProvider requires only a single line
in getElements(). To make up for the boring implementation of the content
e ListItem
b
c
d
e
188 CHAPTER 8
Working with trees and lists
provider, we’ve added a label provider, a filter, and a sorter. We’ll consider these
in the order in which they’re executed.
After the viewer has retrieved the list of items from the content provider, the
filter is given first shot at the items. For the sake of this example, we decided to
only display items whose value field is even. This can be accomplished by imple-
menting the select() method of the filter and returning true or false depend-
ing on whether the value is even. Only items that you return true for will
eventually be displayed. If you added more than one filter to the viewer, they
would each be called in turn.
Next the sorter is used to determine the order of items in the list. The com-
pare() method sorts ListItems by their value, from high to low. Again, this
requires a single line of code.
Finally, once the items have been filtered and sorted, the text to display is
determined by calling a label provider. Because the results of calling toString()
on objects wouldn’t be pretty, you create a label provider that returns the name
field of each ListItem. The final result is shown in figure 8.5; add these lines to
WidgetWindow, compile, and run:
TabItem chap8List = new TabItem(tf, SWT.NONE);
chap8List.setText("Chapter 8 List");
chap8List.setControl(new Ch8ListComposite(tf));
The elegance of the viewer design becomes appar-
ent when you consider that all these operations
are cleanly decoupled from each other. The con-
tent provider doesn’t care what will be done with
the objects it provides. Filters don’t need to know
about each other or how the items will be sorted.
The label provider displays objects without having
to care how the sorter ordered them. And any one
of these can be swapped for a completely differ-
ent implementation without affecting the rest of
the code.
Figure 8.5 The list pane
Summary 189
8.5 Summary
Understanding the relationships between the various widgets and their viewers is
key to using these controls effectively. Simple use of the controls is possible with-
out the viewers, but being able to use filters, sorters, label providers, and content
providers will enable you to separate the concerns of your application much more
cleanly. Above all, decide whether you’re going to use the viewers, and stick to
that decision. Mixing direct creation of TreeItems (or any other item class) with
use of a content provider will cause unpredictable results and make understand-
ing your code very difficult.
190
Tables and menus
This chapter covers
■ SWT tables
■ JFace tables
■ Editing table data
■ Creating menus
Tables 191
Just about every time we want to go out to eat, we find ourselves sitting in the car,
wracking our brains as we try to think of somewhere to go. We end up naming dif-
ferent styles of food—“Japanese?” “Not bad, but not really what I’m in the mood
for.” “Italian?” “Not tonight.” “Indian?” “That’s a good idea, but let’s keep think-
ing.” Especially when we’re hungry, we have a hard time thinking about what res-
taurants are nearby and coming up with good options.
Eventually, we came up with a plan: One afternoon, when we weren’t hungry
and had time to think, we wrote up a list of restaurants in the area, organized by
price and type of food. Now, when we decide to go out, we can look at the list and
have concrete options to discuss. It doesn’t help when we’re in the mood for dif-
ferent things, but it makes the process of deciding where to go easier.
In a software application, a menu provides a function similar to our list of res-
taurants. A finite list of options is presented to users to guide them in deciding
what tasks they wish to perform. Just as we sometimes rediscover a favorite place to
eat that we haven’t visited in a while, users can discover functionality they didn’t
know existed in your application by seeing it listed in a pull-down or context menu.
We’ll cover two tasks in this chapter. First, we’ll continue our discussion of the
Viewer framework from the previous chapter by covering the last of the basic
viewer widgets, the table. The concepts you’ve already learned are just as applica-
ble to tables as they were to trees and lists, but JFace also provides advanced
options in the form of cell editors to make it easy to implement user-editable
tables. Once you’re familiar with the editing framework, we’ll revisit the Actions
we discussed in chapter 4 and show how to apply them to the creation of menus,
so that you can present functions to your users instead of leaving them to guess or
remember what your application is capable of. Finally, our example in this chap-
ter shows how to apply a context menu to a table by presenting a small user-
editable widget that could be used to edit data in a relational database.
9.1 Tables
To the user, a table looks like a two-dimensional grid composed of many cells.
Often this is a convenient way to display items such as the result of a database
query—each row of the result set maps nicely to a single row in the table. As you’ll
see, however, JFace provides advanced facilities for editing table data as well.
9.1.1 Understanding SWT tables
Continuing SWT’s trend of intuitive widget names, a table is represented by a class
named Table. The Table class isn’t terribly interesting. In general, if you’re using
192 CHAPTER 9
Tables and menus
JFace, you’ll be better off interacting with a Table through the interface provided
by a TableViewer, which we discuss later in the chapter. However, if you need to
manipulate the currently selected table items directly, or you aren’t using JFace,
you’ll need to use the underlying Table.
The first thing you’ll notice when looking at the methods available on Table is
that although there are plenty of accessor methods to query its state, there is a dis-
tinct lack of setters that would let you customize the Table. In fact, rather than
adding data or columns directly to the Table, you’ll pass a Table instance to the
appropriate dependent class when that dependent is instantiated, similar to the
way Composites are passed to other widgets rather than the widget being added to
the Composite. Other than a few setters for straightforward display properties,
such as header visibility, the critical methods to be aware of when manipulating a
Table are summarized in table 9.1.
It’s also important to remember that Table extends Scrollable and will therefore
automatically come equipped with scrollbars unless you turn them off.
TableItems
To add data to a table, you must use a TableItem. Each instance of TableItem rep-
resents an entire row in the table. Each TableItem is responsible for controlling
the text and image to display in each column of its row. These values can be set
using the setText() and setImage() methods, each of which takes an integer
parameter designating which column to modify.
As we mentioned, TableItems are associated with a Table in their constructor,
as shown here:
Table t = ...
//Create a new TableItem with the parent Table
//and a style
Table 9.1 Important Table methods
Method Description
addSelectionListener() Notifies you when the table’s selection changes
select()/deselect() Overloaded in several ways to let you programmatically add or
remove the selection on one or more items
getSelection() Retrieves an array of the currently selected items
remove() Removes items from the table
showItem()/showSelection() Forces the table to scroll until the item or selection is visible
Tables 193
TableItem item = new TableItem(t, SWT.NONE);
item.setText(0, “Hello World!”);
...
According to the Javadocs, no styles are valid to be set on a TableItem, but the
constructor accepts a style parameter anyway. This seems rather unnecessary to us,
but it’s at least consistent with the other widgets we’ve seen.
TableColumn
The final class you’ll need to work directly with tables is TableColumn, which cre-
ates an individual column in the table. As with TableItem, you must pass a Table to
the constructor of TableColumn in order to associate the two objects.
Each TableColumn instance controls one column in the table. It’s necessary to
instantiate the TableColumns you need, or the Table will default to having only one
column. Several methods are available to control the behavior and appearance of
each column, such as the width, alignment of text, and whether the column is resiz-
able. You can add header text by using the setText() method. Instead of setting the
attributes directly on a column, however, it’s usually easier to use a TableLayout. By
calling TableLayout’s addColumnData() method, you can easily describe the appear-
ance of each column in the table. The ability to pass addColumnData() instances of
ColumnWeightData is key; doing so lets you specify a relative weight for each column
without having to worry about the exact number of pixels required for each one.
The following snippet shows how to create a table using a TableLayout. The
code creates three columns of equal width and fills two rows with data. The code
produces a table that looks similar to figure 9.1.
//Set up the table layout
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(33, 75, true));
layout.addColumnData(new ColumnWeightData(33, 75, true));
layout.addColumnData(new ColumnWeightData(33, 75, true));
Table table = new Table(parent, SWT.SINGLE);
table.setLayout(layout);
//Add columns to the table
TableColumn column1 = new TableColumn(table, SWT.CENTER);
TableColumn column2 = new TableColumn(table, SWT.CENTER);
TableColumn column3 = new TableColumn(table, SWT.CENTER);
TableItem item = new TableItem(table, SWT.NONE);
item.setText( new String[] { "column 1",
"column 2",
"column 3" } );
item = new TableItem(table, SWT.NONE);
item.setText( new String[] { "a", "b", "c" } );
194 CHAPTER 9
Tables and menus
The first thing to do is set up the structure for this table using a TableLayout. Each
time you call addColumnData(), it adds a new column to the table. We’ll have three
columns, so we add a ColumnWeightData to describe each. The parameters to the
constructor that we use here are weight, minimumWidth, and resizeable. weight
indicates the amount of screen space this column should be allocated, as a per-
centage of the total space available to the table. minimumWidth is, as the name indi-
cates, the minimum width in pixels to use for this column. The resizeable flag
determines whether the user can resize this column.
After we’ve set up the table, we need to instantiate three columns so they will
be added to the table. It’s important to keep in mind that adding columns is a
two-step process: create a TableLayout that describes how large each column will
be, and then create the columns themselves. Because we allow the TableLayout to
control sizing, we don’t need to use the columns after they’ve been created.
9.1.2 JFace TableViewers
Although it’s possible to use a Table directly in your code, as you can see, doing so
is neither intuitive nor convenient. Similarly to List, however, JFace provides a
viewer class to make using tables easier. The following snippets demonstrate a
basic TableViewer that displays data from a database. The same concepts of filters,
sorters, and label providers that we discussed in chapter 8 apply here as well. Addi-
tionally, we’ll use a ContentProvider to supply the data to our table, because the
same arguments presented in the previous chapter apply here.
First, the table must be set up. This is similar to the process of setting up a
Table, which you saw in the previous section, using addColumnData() for each col-
umn that will be created:
final TableViewer viewer = new TableViewer(parent,
SWT.BORDER | SWT.FULL_SELECTION);
//configure the table for display
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(33, true));
layout.addColumnData(new ColumnWeightData(33, true));
layout.addColumnData(new ColumnWeightData(33, true));
viewer.getTable().setLayout(layout);
Figure 9.1
A simple three-column table
Tables 195
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
Once the table has been configured, we attach the appropriate providers. The
most important one in this example is the content provider, which is responsible
for retrieving data from the database and passing it back to the viewer. Note that
you never return null from getElements()—instead, return an empty array if
there are no more children:
viewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object input)
{
//Cast input appropriately and perform a database query
...
while( results.next() )
{
//read results from database
}
if(resultCollection.size() > 0)
{
return new DBRow[] { ... };
}
else
{
return new Object[0];
}
}
//... additional interface methods
});
viewer.setLabelProvider(new ITableLabelProvider() {
public String getColumnText(Object element, int index) {
DBRow row = (DBRow)element;
switch(index)
{
//return appropriate attribute for column
}
}
//... additional interface methods
});
Once the providers have been set up, we can add the columns. The text we set on
each column will appear as a header for that column when the table is displayed:
TableColumn column1 = new TableColumn(viewer.getTable(),
SWT.CENTER);
column1.setText("Primary Key");
TableColumn column2 = new TableColumn(viewer.getTable(),
SWT.CENTER);
column2.setText("Foreign Key");
196 CHAPTER 9
Tables and menus
TableColumn column3 = new TableColumn(viewer.getTable(),
SWT.CENTER);
column3.setText("Data");
Finally, we need to provide input to drive the content provider. The input object
(in this case, a String describing a query) is set on the viewer, which passes it to
the content provider when it’s ready to display the table:
viewer.setInput(QUERY);
This example simulates retrieving multiple rows from a database and displaying
the results. However, it suffices to get our point across about content providers.
The role of the IStructuredContentProvider implementation is straightforward:
Given an input element, return all the children elements to be displayed. A table
doesn’t maintain parent/child relationships, so this method is called only once
and is given the current input object. The final issue to be aware of when using a
content provider is that it will always execute in the UI thread. This means updates
to the interface will be waiting for your methods to complete, so you definitely
shouldn’t query a database to get your updates. The content provider should
traverse a graph of already-loaded domain objects to select the appropriate con-
tent to display.
A word about error handling
When you’re using JFace—especially the providers that the widgets call inter-
nally—it pays to be careful with your error handling. When JFace makes the
callback to your class, it typically does so inside a try/catch block that catches
all exceptions. JFace does some checks to see whether it knows how to handle
the exception itself before letting the exception propagate. Unfortunately,
these checks rely upon the Platform class, which is tightly coupled with
Eclipse; it’s practically impossible to initialize Platform correctly unless you’re
running Eclipse. This leads to internal assertion failures when JFace tries to
use Platform outside of Eclipse, and these exceptions end up masking your
own errors.
In practical terms, you shouldn’t ever let an exception be thrown out of a
provider method. If it happens, you’re in for strange “The application has not
been initialized” messages. If you ever see one of these, check your code care-
fully—things such as ClassCastExceptions can be hard to spot, and locating
them is even more difficult when JFace hides them from you.
Tables 197
Editing table data
Displaying data can be useful on its own, but eventually you’ll want to let the user
edit it. Often, the most user-friendly way to enable editing is to allow the user to
change it directly in the table as it’s presented. JFace provides a means to support
this editing through CellEditors.
As we mentioned in the chapter overview, CellEditors exist to help decouple
the domain model from the editing process. In addition, using these editors can
make your UI more user friendly: Users won’t be able to enter values your applica-
tion doesn’t understand, thus avoiding confusing error messages further down
the line. The framework assumes that each domain object has a number of named
properties. Generally, you should follow the JavaBeans conventions, with property
foo having getFoo() and setFoo() methods; but doing so isn’t strictly necessary as
long as you can identify each property given only its name. You begin by attaching
an instance of ICellModifier to your TableViewer. The ICellModifier is responsi-
ble for retrieving the value of a given property from an object, deciding whether a
property can currently be edited, and applying the updated value to the object
when the edit has been completed. The actual edit, if allowed, is performed by a
CellEditor. JFace provides CellEditors for editing via checkbox, combo box,
pop-up dialog, or directly typing the new text value. In addition, you can subclass
CellEditor if you need a new form of editor. After registering CellEditors, you
associate each column with a property. When the user clicks on a cell to change its
value, JFace does all the magic of matching the proper column with the property
to edit and displaying the correct editor, and it notifies your ICellModifier when
the edit is complete.
We’ll show examples of the important parts of the process here. The rest of the
snippets in this section are taken from the Ch9TableEditorComposite, which is
presented in full at the end of the chapter.
The first snippet sets up data that the rest of the code will reference. The array
of Strings in VALUE_SET holds the values that will be displayed by our ComboBox-
CellEditor. We’ll need to convert between indices and values several times (see
the discussion later in the chapter):
private static final Object[] CONTENT = new Object[] {
new EditableTableItem("item 1", new Integer(0)),
new EditableTableItem("item 2", new Integer(1))
};
private static final String[] VALUE_SET = new String[] {
"xxx", "yyy", "zzz"
};
198 CHAPTER 9
Tables and menus
private static final String NAME_PROPERTY = "name";
private static final String VALUE_PROPERTY = "value";
Our class contains several different methods that are each responsible for setting up
a different facet of the cell editor. They are called in turn from buildControls. The
first thing this method does is set up the table and the classes required by the viewer:
protected Control buildControls()
{
final Table table = new Table(parent, SWT.FULL_SELECTION);
TableViewer viewer = new TableViewer(table);
... //set up a two column table
Once the table has been initialized, we continue by adding an instance of ITable-
LabelProvider to our viewer. The idea is similar to the label providers we dis-
cussed in chapter 8. However, because each row of a table has many columns, the
signature of our methods must change slightly. In addition to the element, each
method now takes the integer index of the column that is being requested. The
label provider must therefore contain the logic to map column indices to proper-
ties of the domain objects. The next snippet shows how this is done:
viewer.setLabelProvider(new ITableLabelProvider() {
public String getColumnText(Object element,
int columnIndex) {
switch(columnIndex)
{
case 0:
return ((EditableTableItem)element).name;
case 1:
Number index = ((EditableTableItem)element).value;
return VALUE_SET[index.intValue()];
default:
return "Invalid column: " + columnIndex;
}
}
});
attachCellEditors(viewer, table);
return table;
}
The attachCellEditors() method is where we set up our ICellModifier, which is
responsible for translating a property name into data to be displayed, deciding
whether a given property can be edited, and then applying whatever changes the
user makes. When the user double-clicks a cell to edit it, canModify() is called to
determine whether the edit should be allowed. If it’s allowed, getValue() is called
next to retrieve the current value of the property being edited. Once the edit is
Tables 199
complete, modify() is called; it’s modify()’s responsibility to apply the changes the
user made back to the original domain object. While in getValue() and canMod-
ify(), it’s safe to cast parameters directly to the domain objects; this doesn’t work
in modify(). modify() receives the TableItem that’s displaying the row. This
TableItem has had the domain object set as its data, so we must retrieve it using
getData() before we can update it:
private void attachCellEditors(final TableViewer viewer,
Composite parent)
{
viewer.setCellModifier(new ICellModifier() {
public boolean canModify(Object element,
String property) {
return true;
}
public Object getValue(Object element, String property) {
if( NAME_PROPERTY.equals(property))
return ((EditableTableItem)element).name;
else
return ((EditableTableItem)element).value;
}
//method continues below...
When modify() is finished updating the domain object, we must let the viewer
know to update the display. The viewer’s refresh() method is used for this pur-
pose. Calling refresh() with the domain object that changed causes the viewer to
redraw the given row. If we skip this step, users will never see their changes once
the edited cell loses focus:
public void modify(Object element,
String property, Object value) {
TableItem tableItem = (TableItem)element;
EditableTableItem data =
(EditableTableItem)tableItem.getData();
if( NAME_PROPERTY.equals( property ) )
data.name = value.toString();
else
data.value = (Integer)value;
viewer.refresh(data);
}
});
The items given in the CellEditor array here are matched in order with the col-
umns of the underlying table:
viewer.setCellEditors(new CellEditor[] {
new TextCellEditor(parent),
200 CHAPTER 9
Tables and menus
new ComboBoxCellEditor(parent, VALUE_SET )
});
Next, the strings in setColumnProperties() are the names of the editable proper-
ties on our domain objects. They’re also matched in order with the table’s col-
umns, so that in our example clicking column 0 will try to edit the name property,
and column 1 will edit the value property:
viewer.setColumnProperties(new String[] {
NAME_PROPERTY, VALUE_PROPERTY
});
}
}
class EditableTableItem
{
... //name and value properties
}
Using a ComboBoxCellEditor as we do here is tricky. The editor’s constructor takes
an array of Strings that are the values presented for the user to choose from.
However, the editor expects Integers from getValue() and returns an Integer to
modify() when the edit is complete. These values should correspond to the index
of the selected value in the array of Strings passed to the ComboBoxCellEditor
constructor. In this simple example we save the Integer directly in the value field,
but in a real application you’ll probably need utilities to easily convert back and
forth between indices and values.
Again, using CellEditors is an area where it’s smart to pay attention to your
casting and error handling. Especially when different methods require you to cast
to different objects, as in the ICellModifier, it’s easy to make a mistake the com-
piler can’t catch for you. Due to JFace’s exception handling, as we discussed ear-
lier, these issues show up as cryptic “Application not initialized” runtime errors
that can be hard to track down if you don’t know what you should be looking for.
9.2 Creating menus
Every graphical application uses a menu of some sort. You’ll often find File, Edit,
and so on across the top of your application’s window. These menus fill an
important role, because they provide a place for users to browse through the
functionality offered by your application.
We’ll first discuss creating menus using SWT. We’ll then revisit the JFace Action
classes that we mentioned in chapter 4, to discuss an alternate way to create
menus that allows for easy sharing of common code.
Creating menus 201
9.2.1 Accelerator keys
Before we get too deep into the specifics of menus, let’s discuss how SWT handles
accelerator keys. Accelerator keys are keyboard shortcuts that activate a widget with-
out the user having to click it with the mouse. The best example is the ubiquitous
Ctrl-C (or Open Apple-C if you’re using a Mac) to copy text to the clipboard, the
same as if you selected Copy from the Edit menu that’s present in most applica-
tions. Offering accelerator keys for common tasks can greatly increase advanced
users’ productivity, because their hands don’t have to continually switch between
the keyboard and mouse. The accelerator keystroke for an item customarily
appears next to the item’s name in drop-down menus for the application, making
it easier for users to learn the keystrokes as they use the application.
In both SWT and JFace, accelerator keys are expressed by using constants from
the SWT class. The concept is the same as for styles: All the constants are bitwise
ORed together to determine the final key combination. Additionally, chars are
used to represent letters or numbers on the keyboard. Because a Java char can be
automatically converted to an int, chars can be used just like the SWT style con-
stants to build a bitmask. This bitmask is passed to the setAccelerator() method
on a Menu to register the combination of keys that will activate that menu item. For
example, a MenuItem whose accelerator is set to SWT.CONTROL | SWT.SHIFT | 't'
will activate when the Ctrl, Shift, and T keys are pressed simultaneously.
9.2.2 Creating menus in SWT
When you’re creating menus using SWT, you’ll use only two classes: Menu and
MenuItem. Although the classes themselves aren’t complicated, several areas of
complexity arise once you begin to use them.
Menu acts as a container for MenuItems. Menu extends Widget and contains meth-
ods for adding MenuItems and controlling the visibility and location of the menu.
Menu also broadcasts events to implementors of the MenuListener interface, which
receives notification when the menu is shown or hidden.
Menu supports three different styles, which go beyond controlling the visual
appearance to determine the type of menu created:
■ SWT.POP_UP—Creates a free-floating pop-up menu of the type that typically
appears when you right-click in an application.
■ SWT.BAR—Creates the menu bar at the top of an application window. A
menu bar doesn’t typically have selectable menu items; instead, it acts as a
container for menu items that contain menus of type SWT.DROP_DOWN.
202 CHAPTER 9
Tables and menus
■ SWT.DROP_DOWN—Creates the File, Edit, and other drop-down menus that
we’re all familiar with. These menus may contain a mix of MenuItems and
submenus of their own.
A MenuItem is a widget that either can be selected by the end user or can display
another menu. A MenuItem is always created as a child of a Menu. A variety of styles
are available for MenuItems:
■ SWT.PUSH—Creates a standard menu item with no frills.
■ SWT.CHECK, SWT.RADIO—Add either a checkbox or radio button, as appropri-
ate, which flips between on and off each time the item is selected.
■ SWT.SEPARATOR—Visually separates groups of menu items. It displays the
standard separator for your platform (usually a thin line) and may not be
selected by the user.
■ SWT.CASCADE—Creates a submenu. When a cascading menu item has a
menu assigned to it, highlighting that item results in the submenu being
displayed.
All MenuItems except separators broadcast SelectionEvents that can be listened
for. Figure 9.2 shows the different menu styles.
Creating Menus is straightforward. Classes are instantiated and configured,
and then assigned to the widgets on which they should be displayed. The follow-
ing snippet shows how to create a File menu attached to the main window of
your application:
Composite parent = ... //get parent
Menu menuBar = new Menu(parent.getShell(), SWT.BAR);
MenuItem fileItem = new MenuItem(menuBar, SWT.CASCADE);
fileItem.setText("&File");
Menu fileMenu = new Menu(fileItem);
fileItem.setMenu(fileMenu);
parent.getShell().setMenuBar(menuBar);
Figure 9.2
Menu types. From top to bottom, SWT.CHECK,
SWT.CASCADE, SWT.PUSH, and SWT.RADIO.
Creating menus 203
Notice that you must first create the root menu bar and then add a menu item to
hold each drop-down menu that will appear on it. At this point, we have a menu
bar that displays File but is empty. Our next task is to populate this menu:
MenuItem open = new MenuItem(fileMenu, SWT.PUSH);
open.setText("Open...");
open.setAccelerator(SWT.CONTROL | 'o');
open.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent event) {
... //handle selection
}
};
Clicking File will now reveal a drop-down menu with an Open option. If Open is
selected, the selection listener we’ve defined is invoked to display an Open File
dialog or do whatever other action is appropriate to the application. We’ve also
set the keyboard accelerator for this option to Ctrl-O by calling setAccelerator()
with a bitmask of the keys we wish to assign. The result is that pressing Ctrl-O
invokes the selection listener just as if it was selected with the mouse.
Creating a pop-up menu is similar to what we’ve done here, but there is a slight
wrinkle. We don’t need a menu bar, so we can start with the pop-up:
Composite parent = ... //get composite
final Menu popupMenu = new Menu(parent.getShell(), SWT.POP_UP);
Notice that we declare the Menu instance to be final. This is important, because
we’ll need to reference it in a listener later.
Creating the MenuItems is the same as for a drop-down menu. For variety, we’ll
show how to create a menu item that reveals a submenu when highlighted. The
important point to notice in this process is that after the submenu is created, it
must be assigned to its parent menu item using setMenu(), just as we did with the
menu bar in our earlier example:
MenuItem menuItem = new MenuItem(popupMenu, SWT.CASCADE);
menuItem.setText("More options");
Menu subMenu = new Menu(menuItem);
menuItem.setMenu(subMenu);
MenuItem subItem = new MenuItem(subMenu, SWT.PUSH);
subItem.setText("Option 1");
subItem.addSelectionListener( ... );
Unlike a menu bar, a pop-up menu isn’t displayed by default—you must decide
when to display it. Typically this is done in response to a mouse right-click, so we’ll
use a MouseListener on the parent Composite. This is where we need the pop-up
menu instance to be final, so we can reference it within our anonymous inner class:
204 CHAPTER 9
Tables and menus
parent.addMouseListener(new MouseListener() {
public void mouseDown(MouseEvent event) {
if(event.button == 2)
{
popupMenu.setVisible(true);
}
}
... //other MouseListener methods
});
MouseEvent contains information about the button that was clicked. The buttons
are numbered: 1 is the left mouse button, and 2 is the right button. If this button
was clicked, we make the pop-up menu visible; it’s displayed at the location that
was clicked. Pressing Esc or clicking anywhere other than on the menu automati-
cally causes the pop-up to be hidden.
Now that you’ve seen how SWT handles menus, we’ll turn our attention to the
menu options offered by JFace.
9.2.3 Using JFace actions to add to menus
We’ve already discussed the design of JFace’s Action classes in chapter 4. To
review briefly, an action encapsulates the response to a single application level
event, such as “Open a file” or “Update the status bar.” This action can then be
reused and triggered in different contexts, such as a toolbar button or a menu
item. We’ll discuss this last case here. By using actions to create your menus,
instead of doing it by hand, you can simplify the design of your application and
reuse common logic.
Using actions in a menu is similar to using them anywhere else. Remember
that an IContributionManager is responsible for assembling individual Actions
and transforming them into a form that can be displayed to the user. For menus,
we’ll use the MenuManager implementation of IContributionManager. After adding
whatever actions are needed to the MenuManager, we can tell it to create a new
menu or to add the actions to another menu. The code looks something like this:
Shell shell = ... //obtain a reference to the Shell
MenuManager fileMenuManager = new MenuManager("File");
IAction openAction = new OpenAction(...);
... //create other actions as appropriate
fileMenuManager.add(openAction);
... //add other actions
Menu menuBar = new Menu(shell, SWT.BAR);
fileMenuManager.fill(menuBar, -1);
shell.setMenuBar(menuBar);
Updating WidgetWindow 205
Although we’ve still created the menu bar manually, we can add actions to the
manager and let it worry about how the menu should be built. In this case, we end
up with a File menu on the window’s menu bar, because that is the name we gave
the MenuManager when we instantiated it. The advantage of doing it this way
instead of building menus by hand is that the action classes can be easily reused
elsewhere. For example, if we have a toolbar that includes a button to let users
open files, we can use the same OpenAction class there.
You must keep one caveat in mind when you’re using menu managers: Once
fill() or createXXX() has been called on a given instance, Menu and MenuItem
instances are created and cached internally. This is necessary so that the manager
can be used to update the menu. However, it also means that you shouldn’t make
further calls to fill() or create(), especially for a different type of menu. For
example, suppose that after the previous code we called createContextMenu() on
fileMenuManager. We would get exceptions when we tried to add the menu to a
composite, because the menu would be the cached instance with type SWT.CAS-
CADE instead of type SWT.POP_UP (which is required by context menus).
9.3 Updating WidgetWindow
Our pane for this chapter combines a table viewer, cell editors, and a context
menu. We’ll expand the snippets of a database editor that we discussed earlier
and add a right-click menu that lets the user insert a new row. The final product
looks like figure 9.3.
Listing 9.1 is longer than the code for most of our chapter panes, so we’ll point
out the most interesting bits before you begin reading it. The first thing to notice
is the inner class NewRowAction. This class holds the logic to insert a new row into
the table; it’s added to the MenuManager we create in createPane().
Next is the createPane() method, which is the entry point into the class. After
delegating to methods to lay out the table and attach a label provider, content
provider, and cell editor, we instantiate a MenuManager and use it to build a context
Figure 9.3 Our database table editor
206 CHAPTER 9
Tables and menus
menu that we then attach to the newly created Table. Finally, we pass the initial
content to the viewer.
After createPane() come the private utility methods. The most important for
our purposes is attachCellEditors(), which contains the logic to allow editing of
individual table cells. Note that these modifications are performed directly on the
domain objects.
At the end of the listing is the EditableTableItem class, which serves as a
domain object for this example and is included in the same file for convenience.
package com.swtjface.Ch9;
import org.eclipse.jface.action.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.*;
public class Ch9TableEditorComposite extends Composite
{
private static final Object[] CONTENT = new Object[] {
new EditableTableItem("item 1", new Integer(0)),
new EditableTableItem("item 2", new Integer(1))
};
private static final String[] VALUE_SET = new String[] {
"xxx", "yyy", "zzz"
};
private static final String NAME_PROPERTY = "name";
private static final String VALUE_PROPERTY = "value";
private TableViewer viewer;
public Ch9TableEditorComposite(Composite parent)
{
super(parent, SWT.NULL);
buildControls();
}
private class NewRowAction extends Action
{
public NewRowAction()
{
super("Insert New Row");
}
public void run()
{
Listing 9.1 Ch9TableEditorComposite.java
b Initial content
c NewRowAction class
d run() method
Updating WidgetWindow 207
EditableTableItem newItem =
new EditableTableItem("new row", new Integer(2));
viewer.add(newItem);
}
}
protected void buildControls()
{
FillLayout compositeLayout = new FillLayout();
setLayout(compositeLayout);
final Table table = new Table(this, SWT.FULL_SELECTION);
viewer = buildAndLayoutTable(table);
attachContentProvider(viewer);
attachLabelProvider(viewer);
attachCellEditors(viewer, table);
MenuManager popupMenu = new MenuManager();
IAction newRowAction = new NewRowAction();
popupMenu.add(newRowAction);
Menu menu = popupMenu.createContextMenu(table);
table.setMenu(menu);
viewer.setInput(CONTENT);
}
private void attachLabelProvider(TableViewer viewer)
{
viewer.setLabelProvider(new ITableLabelProvider() {
public Image getColumnImage(Object element,
int columnIndex) {
return null;
}
public String getColumnText(Object element,
int columnIndex) {
switch(columnIndex)
{
case 0:
return ((EditableTableItem)element).name;
case 1:
Number index = ((EditableTableItem)element).value;
return VALUE_SET[index.intValue()];
default:
return "Invalid column: " + columnIndex;
}
}
public void addListener(ILabelProviderListener listener) {
}
public void dispose(){
}
e Build menu
f getColumnText()
method
208 CHAPTER 9
Tables and menus
public boolean isLabelProperty(Object element,
String property){
return false;
}
public void removeListener(ILabelProviderListener lpl) {
}
});
}
private void attachContentProvider(TableViewer viewer)
{
viewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object inputElement) {
return (Object[])inputElement;
}
public void dispose() {
}
public void inputChanged(Viewer viewer,
Object oldInput,
Object newInput) {
}
});
}
private TableViewer buildAndLayoutTable(final Table table)
{
TableViewer tableViewer = new TableViewer(table);
TableLayout layout = new TableLayout();
layout.addColumnData(new ColumnWeightData(50, 75, true));
layout.addColumnData(new ColumnWeightData(50, 75, true));
table.setLayout(layout);
TableColumn nameColumn = new TableColumn(table, SWT.CENTER);
nameColumn.setText("Name");
TableColumn valColumn = new TableColumn(table, SWT.CENTER);
valColumn.setText("Value");
table.setHeaderVisible(true);
return tableViewer;
}
private void attachCellEditors(final TableViewer viewer,
Composite parent)
{
viewer.setCellModifier(new ICellModifier() {
public boolean canModify(Object element, String property){
return true;
}
public Object getValue(Object element, String property) {
g getElements()
method
buildAndLayoutTable()
method
H
Updating WidgetWindow 209
if( NAME_PROPERTY.equals(property))
return ((EditableTableItem)element).name;
else
return ((EditableTableItem)element).value;
}
public void modify(Object element,
String property,
Object value) {
TableItem tableItem = (TableItem)element;
EditableTableItem data =
(EditableTableItem)tableItem.getData();
if( NAME_PROPERTY.equals( property ) )
data.name = value.toString();
else
data.value = (Integer)value;
viewer.refresh(data);
}
});
viewer.setCellEditors(new CellEditor[] {
new TextCellEditor(parent),
new ComboBoxCellEditor(parent, VALUE_SET )
});
viewer.setColumnProperties(new String[] {
NAME_PROPERTY, VALUE_PROPERTY
});
}
}
class EditableTableItem
{
public String name;
public Integer value;
public EditableTableItem( String n, Integer v)
{
name = n;
value = v;
}
}
These constants hold the data we’ll use for our initial content. In a real applica-
tion, this data would likely be read from a database or other external source.
This class contains the logic to insert new rows into the data set. It extends Action
so it can be used by a MenuManager.
i modify() method
j EditableTableItem class
b
c
210 CHAPTER 9
Tables and menus
To perform the necessary logic, we override the run() method defined in Action.
The action framework ensures that this method is invoked at the appropriate
time. Our implementation creates a new domain object and calls add() on the
table viewer. Most real applications will need additional logic here to manage the
collection of domain objects.
We build a simple context menu by creating a new MenuManager and adding the
actions we want to use. In this case, we add the menu directly to the Table. If the
tab contained more controls than just this table, then the menu would appear
only when the user right-clicked on the table. If we wanted it to appear when the
user clicked anywhere on the tab, we would need to add the menu to the par-
ent Composite.
This is a standard LabelProvider implementation, similar to ones you’ve seen ear-
lier. It returns the value of whichever property matches the requested column.
Our content provider assumes that whatever input it’s given is an array of Objects.
It performs the appropriate cast and returns the result.
Here we construct the table. We add two columns and set the header text.
The modify() method is the most important part of our CellModifier implemen-
tation. The element parameter contains the TableItem for the cell that was just
changed. The domain object associated with this item is retrieved with the get-
Data() method. We then check the propertyName parameter to determine what
property was modified; we update the matching property on the domain object
using the value parameter, which contains the date entered by the user.
This small class serves as the domain objects for our example.
Run this example by adding the following lines to WidgetWindow:
TabItem chap9TableEditor = new TabItem(tf, SWT.NONE);
chap9TableEditor.setText("Chapter 9");
chap9TableEditor.setControl(new Ch9TableEditorComposite(tf));
When you run this example, the initial window contains two rows with sample
data. Right-clicking brings up a context menu that lets you insert a new row into
the table. Double-clicking a cell allows you to edit the data, either by typing or by
choosing from a drop-down menu.
d
e
f
g
h
i
j
Summary 211
9.4 Summary
Most of what you’ve seen with Tables and TableViewers should be familiar from
chapter 8. The basic concepts of viewers and providers are identical to those we
discussed earlier. Because tables impose a two-dimensional structure on data, they
require more configuration than some of other widgets we’ve examined. The
TableLayout and TableColumn classes create this structure for each table and con-
trol the details of how the table appears to the user.
After working through these two chapters, you should be well equipped to
handle any requirement that calls for the use of one of these viewers, or any of the
more esoteric classes such as TableTreeViewer that are included in JFace.
CellEditors, however, are a useful feature unique to TableViewers. CellEdi-
tors provide a framework for handling updates to specific cells in a table, and the
predefined CellEditor classes provide an easy way to provide discrete options for
the user to choose from.
Just about any application will need to provide a menu bar, and it’s common to
provide context menus that show only options that are relevant to what the user is
currently doing. For example, right-clicking in a word processor typically brings
up options related to formatting text. SWT makes creating these menus easy, and
JFace adds the action framework to facilitate reusing logic easily regardless of the
context from which it was invoked. We discussed the theory behind actions in
chapter 4, and the examples we’ve shown here should give you a good feel for
how they’re used in practice.
212
Dialogs
This chapter covers
■ Dialogs included by SWT
■ Dialogs included by JFace
■ Progress indicators
■ Creating custom dialogs in JFace
SWT dialogs 213
If you want to be noticed, you must find a way to attract attention to yourself.
Whether your goal is to woo a potential sweetheart or market a new invention, it’s
impossible to succeed if your target isn’t aware of your efforts. The same principle
holds for software. If your program needs something from the user, it must find a
way to draw that user’s attention to itself. There are a variety of ways to accomplish
this, but the most common is to present the user with a dialog box. A dialog box is
a window that is separate from your application’s main window. When this window
is placed in front of the application, the user is forced to pay attention to whatever
you display there, whether it’s a status message or a request for input, such as a
filename to save to. Because displaying dialogs is such a common and necessary
task, SWT and JFace provide support to make handling dialogs easy.
We need to discuss two independent Dialog classes: org.eclipse.swt.wid-
gets.Dialog and org.eclipse.jface.dialogs.Dialog. As their package names
suggest, the first class is part of SWT, whereas the second is from JFace. It would be
possible to build an application using only the SWT dialogs, but doing so wouldn’t
be fun. Still, SWT provides several prebuilt dialogs that perform common tasks.
We’ll cover the use of the SWT dialogs first, followed by a comparison with JFace
dialogs. We’ll round out the chapter by creating a username/password prompt
dialog to demonstrate how to write a custom dialog.
10.1 SWT dialogs
The abstract class Dialog provides the basis for all dialogs in SWT. By itself, this
class is of little interest, because it doesn’t provide much in the way of behavior.
It’s possible to derive your own SWT Dialog subclasses if you wish. However, deriv-
ing from the Dialog classes provided by JFace will make your job easier. Conse-
quently, we’ll discuss creating custom dialogs in the JFace section of this chapter.
SWT does provide prebuilt dialogs for common tasks that are convenient and
easy to use. We’ll discuss how and when to use each of these dialogs next.
10.1.1 ColorDialog
Suppose you’re writing a text editor, and you want to let users specify the color of
the text on the screen. You may be able to get away with letting them specify RGB
values by hand if your target audience consists of hard-core programmers, but in
general users want to see the available options and choose one by pointing and
clicking. SWT does this for you with the class ColorDialog.
214 CHAPTER 10
Dialogs
The grayscale nature of this book doesn’t do
the image justice, but figure 10.1 shows how
the user can easily choose a color from a Color-
Dialog.
Displaying this dialog is simple. Just instanti-
ate it, and call open():
ColorDialog dialog = new
ColorDialog(shell);
RGB color = dialog.open();
If you wish to preselect a color, call setRGB()
before opening the dialog.
The call to open() blocks, which means it
won’t return until the user clicks OK or Cancel.
The selected color, if any, is returned from
open() as an instance of RGB. null is returned if
the user clicks Cancel. The selected color can
also be retrieved later by using getRGB().
10.1.2 DirectoryDialog
DirectoryDialog chooses a target directory—for example, the location to which
to save a group of files. The following snippet displays the directory chooser dia-
log along with a message explaining what the user is supposed to do:
DirectoryDialog dialog = new DirectoryDialog(shell);
dialog.setMessage("Choose a save directory");
String saveTarget = dialog.open();
if(saveTarget != null)
{
java.io.File directory = new java.io.File(saveTarget);
...
}
The dialog looks something like figure 10.2.
Once the user has chosen a directory, the call to open()returns a String that
holds the absolute path to the chosen directory. This String can be used to create
a java.io.File and then manipulated accordingly. Should the user cancel,
open() returns null.
Figure 10.1
ColorDialog allows the user to
select from available colors.
SWT dialogs 215
10.1.3 FileDialog
In many ways, FileDialog is similar to DirectoryDialog. The dialogs appear
nearly identical, except that whereas DirectoryDialog displays only a list of direc-
tories, FileDialog adds the files present in each current directory to the display,
as shown in figure 10.3.
The next snippet shows how to let the user select multiple files, as long as the
filenames end in “.txt”:
FileDialog dialog = new FileDialog(shell, SWT.MULTI);
dialog.setFilterExtensions(new String[] {"*.txt"});
dialog.open();
As usual, open() blocks and returns either the full path to the file as a String, or
null. Unlike the dialogs you’ve seen before, FileDialog supports three different
styles:
■ SWT.SAVE—Treats the dialog as a save dialog, allowing the user to either
select an existing file or type in the name of a new file to create.
■ SWT.OPEN—Lets the user select a single existing file to be opened.
■ SWT.MULTI—Lets the user select multiple files at once to be opened. Even if
the user selects multiple files in a MULTI-style dialog, open() will return only
Figure 10.2
DirectoryDialog waiting for the
user to choose a directory
Figure 10.3
FileDialog in Save mode allows the
user to enter a filename to save to.
216 CHAPTER 10
Dialogs
one. getFileNames() must be used to retrieve the array of all filenames
selected after open() returns.
Also of note in FileDialog are the methods setFilterPath(), setFilterNames(),
and setFilterExtensions(). When they’re called before the dialog opens, these
methods can be used to restrict the list of files that are visible to the user. setFil-
terPath() takes a single String that’s used as the path to the directory that should
be displayed by default. The other two methods take arrays of Strings, which are
used to assemble valid filenames and extensions. Our previous example filters out
everything that doesn’t end in “*.txt”. Note that the filter is displayed to the user
and is editable, so there is no guarantee that they won’t select a file of a type other
than what you expect.
10.1.4 FontDialog
Just as users of your text editor need to select a color for their text, they also need
to select a font to display it in. For this purpose, we have FontDialog. Its use is
nearly identical to that of the ColorDialog we discussed earlier:
FontDialog dialog = new FontDialog(shell);
FontData fontData = dialog.open();
FontDialog automatically picks up the fonts available to SWT on the user’s system.
This can result in a complex display, as figure 10.4 shows.
The returned FontData can be used to instantiate the correct font, as discussed
in chapter 7.
10.1.5 MessageBox
If your application encounters an error it can’t recover from, the typical response
is to display a text message to the user and then exit. For this or any other purpose
where you need to display a dialog with a message, SWT provides MessageBox. A
Figure 10.4
FontDialog displays all fonts
installed on the user’s system.
SWT dialogs 217
simple dialog that gives the user the option of continuing or not can be displayed
with the following lines:
MessageBox dialog = new MessageBox(shell,
SWT.OK | SWT.CANCEL);
dialog.setMessage("Do you wish to continue?");
int returnVal = dialog.open();
There are two important steps when you’re using MessageBox. The easy part is to
set the text message to display using setMessage(). More complicated is setting
the style. Using an icon style adds an appropriate icon next to your message. Styles
can also be used to control what buttons the MessageBox displays. However, some
styles are valid only in combination with certain other styles; the allowed combina-
tions are presented in table 10.1. Any of these can also be freely combined with
one of the icon styles, which are listed in table 10.2. If no button or an invalid but-
ton style is specified, SWT.OK is used, resulting in a single OK button. open()
returns an integer matching the SWT constant of the button that was clicked.
Table 10.1 Valid button style combinations
Dialog button style combinations
SWT.OK
SWT.OK | SWT.CANCEL
SWT.YES | SWT.NO
SWT.YES | SWT.NO | SWT.CANCEL
SWT.RETRY | SWT.CANCEL
SWT.ABORT | SWT.RETRY | SWT.IGNORE
Table 10.2 Dialog icons
Dialog icon Indicates that…
SWT.ERROR_ICON An error has occurred.
SWT.ICON_INFORMATION The dialog is presenting noninteractive information to the user.
SWT.ICON_QUESTION The dialog requires an answer (usually OK or Cancel) from the
user.
SWT.ICON_WARNING The user is about to perform a potentially harmful action.
SWT.ICON_WORKING The program is in the middle of a task.
218 CHAPTER 10
Dialogs
10.2 JFace dialogs
The standard JFace dialog classes are straightforward to use, because they work
similarly to dialogs in other UI toolkits such as Swing. The main difference you
need to be aware of is that whereas Swing provides JOptionPane with a variety of
static methods to display message dialogs, error dialogs, and so on, JFace has a
separate subclass for each of these dialog types that may be instantiated and dis-
played as is or subclassed to further customize appearance or behavior.
All JFace dialogs extend from the abstract class org.eclipse.jface.dia-
logs.Dialog, which itself extends org.eclipse.jface.window.Window. Figure 10.5
shows the relationship between the standard dialog classes. As you can see, the
relationships are for the most part simple; the Error and Input dialogs rely upon
interfaces outside the basic hierarchy.
A few design considerations are common to any subclass of Dialog. You change
dialog behavior by overriding the buttonPressed() method. The default implemen-
tation closes the dialog immediately as soon as any button is clicked—even non-
standard buttons that you may have added yourself. If you wish to change this
behavior or do processing of any kind before the dialog is closed, you must override
Window
Dialog
ErrorDialog MessageDialog TitleAreaDialog InputDialog
<>
IStatus
<>
IInputValidator
getSeverity() : int
getMessage() : String
isValid(newText : String) : String
Figure 10.5 JFace dialog inheritance hierarchy
JFace dialogs 219
the method. Keep in mind that if you do override buttonPressed(), the dialog won’t
close unless you call super.buttonPressed() at the end of your implementation.
You can also get hooks into specific buttons by overriding okPressed() or can-
celPressed() for any dialog that supports those buttons. Again, by default, these
methods just close the dialog—if you’re going to add behavior, be sure to call the
parent method when you’re done.
Finally, the createButtonsForButtonBar() method controls the buttons that
are created for any given dialog. If you want to change the buttons for any dialog,
this is the place to do it. The one exception is MessageDialog—because you’ll
much more frequently want to change the buttons in a message dialog, the con-
structor provides a convenient way to specify the buttons that should be displayed
without having to create a subclass.
It’s recommended that a dialog be modal, meaning that once it’s opened, no
other window can receive focus until the dialog is closed. Writing code that uses a
modal dialog is generally simpler, because you can be sure that as long as the dia-
log is displayed, your user isn’t interacting with the rest of your application. All
the basic dialogs discussed in this section follow this recommendation. This
impacts your code in two ways. First, it doesn’t make sense to open a dialog with-
out a parent window, so all our code examples include a parent ApplicationWin-
dow for this purpose. Second, you must remember that in your code, the call to
open() blocks, meaning that the method won’t return until the dialog is dismissed
in one way or another. open() returns an int, which is the zero-based index of the
button that was clicked, or –1 if the dialog’s window was closed by some means
other than clicking a button (such as pressing the Esc key).
10.2.1 Message dialogs
A message dialog is used to display a message to the user. Little interaction is pos-
sible with a message dialog—the user is limited to dismissing the dialog by click-
ing one of the displayed buttons.
The following snippet shows how to display a message dialog—as you can see,
displaying the dialog itself requires only two lines of code. This is roughly equiva-
lent to calling JOptionPane.showMessageDialog() in Swing:
MessageDialog dialog =
new MessageDialog(
testWindow.getShell(),
"Greeting Dialog", //the dialog title
null,
"Hello! How are you today?", //text to be displayed
MessageDialog.QUESTION, //dialog type
220 CHAPTER 10
Dialogs
new String[] { "Good",
"Been better",
"Excited about SWT!" }, //button labels
0);
dialog.open();
Message dialogs come in several different types, defined as static constants in the
MessageDialog class. This type determines the image that’s displayed; in our
example, we get an image of a question mark, because we’ve declared this to be a
dialog of type QUESTION. Other types include ERROR, INFORMATION, WARNING, and
NONE. Each uses the standard image for that type on your operating system (except
type NONE, which causes no image to be displayed).
You can also create buttons automatically by passing an array of Strings that
are the button labels. For each label found, MessageDialog creates a correspond-
ing button. By default, all buttons behave the same and close the dialog. In prac-
tice, it’s unusual to find a message dialog with any button other than OK and
perhaps Cancel.
The constructor also optionally accepts an image to be displayed.
10.2.2 Error dialogs
Error dialogs are in many ways similar to MessageDialogs, in that they display an
error message to the user. You can mimic an ErrorDialog by creating a MessageDi-
alog with type ERROR. However, the ErrorDialog allows you to display more in-
depth error details by using the IStatus interface. IStatus holds a detailed mes-
sage and information about the severity of each error that has occurred. The
result can be seen in figure 10.6.
The error dialog shown in figure 10.6 is created with the following code. We
create an instance of ErrorDialog and pass it an IStatus object that holds error
information. The root IStatus holds several other instances of IStatus that pro-
vide increasingly granular details about the errors:
Figure 10.6
An error dialog with multiple
instances of IStatus
JFace dialogs 221
...
ErrorDialog errorDialog = new ErrorDialog(testWindow.getShell(),
"Test Error Dialog",
"This is a test error dialog",
testWindow.createStatus(),
IStatus.ERROR | IStatus.INFO );
...
public IStatus createStatus()
{
final String dummyPlugin = "some plugin";
IStatus[] statuses = new IStatus[2];
statuses[0] = new Status(IStatus.ERROR,
dummyPlugin,
IStatus.OK,
"Oh no! An error occurred!",
new Exception
statuses[1] = new Status(IStatus.INFO,
dummyPlugin,
IStatus.OK,
"More errors!?!?",
new Exception() );
MultiStatus multiStatus = new MultiStatus(dummyPlugin,
IStatus.OK
statuses,
"Several errors have occurred.",
new Exception() );
return multiStatus;
}
IStatus defines several severity-related constants. By bitwise ORing them together,
we create a bitmask describing the severities we’re interested in displaying. The
severity set in each individual IStatus object is compared with this mask, and
details of that object only are displayed in the case of a match. By changing INFO to
WARNING in this example, the details of our second Status object are suppressed.
Here we create an instance of Status, which implements the IStatus interface.
The idea is to encapsulate all the information about an error in this class and let
the ErrorDialog or any other consumer decide what is appropriate to display
based on the context.
IStatus requires a plug-in identifier, which is supposed to be a unique string. This
identifier is never used for ErrorDialogs, so we give the object a dummy value.
The Status stores the exception it’s given. The exception is included in the output
of Status’s toString() method and can also be retrieved using getException().
b Severity mask
c Status
d Plug-in
e Exception
f MultiStatus
g Severity
b
c
d
e
222 CHAPTER 10
Dialogs
MultiStatus also implements the IStatus interface and groups together multiple
instances of IStatus.
The severity set here is used to select an appropriate image to display in the dia-
log. The choices work the same as in a MessageDialog.
This code will display an error dialog with the message “Several errors have
occurred”, as you saw in figure 10.6. Clicking the Details button opens a panel at the
bottom of the dialog with the messages from the two Status objects we’ve defined.
The Details button appears because the root IStatus object given to the dialog
is a MultiStatus and returns true for the isMultiStatus() method. Upon seeing
that it’s dealing with a MultiStatus, the ErrorDialog calls getChildren() to
retrieve the detailed status messages. If the root IStatus returns false for isMulti-
Status(), a Details button won’t appear. Children of a MultiStatus may be Multi-
Statuses themselves, allowing you to build trees of arbitrary complexity, should
the need arise. A MultiStatus’s severity is equal to the greatest severity of its chil-
dren. The Javadocs define a MultiStatus with no children as defaulting to a sever-
ity of OK.
As you can see, ErrorDialog provides a significantly more advanced error-
reporting mechanism than using a MessageDialog of type ERROR. The primary
drawback to using ErrorDialog, however, is that it’s tied more closely to the Eclipse
platform than we’d like, instead of being a purely JFace-based widget. Not only do
the various IStatus-related classes come from org.eclipse.core.runtime, but
they also ask for plug-in identifiers as parameters—a concept that’s present in
Eclipse but not in JFace. How serious a drawback this may be is open for debate; it’s
possible to use the classes in this case by passing dummy values, because the values
aren’t used. However, you can’t pass null, because Status checks the plug-in value
it’s given and throws an internal assertion failure exception in case of null. Thus,
using the classes is at minimum confusing, and in general creates an awkward
design for any application not based on Eclipse. If you don’t need to provide
expanded details for your error messages, it’s best to avoid ErrorDialog and stick
to creating MessageDialogs with type ERROR. However, if you need the Details func-
tionality, it may be worth making a small compromise in your application design to
take advantage of these classes that have already been written and debugged.
10.2.3 Input dialogs
As the name suggests, an InputDialog is used to allow the user to enter text. These
dialogs are primarily intended for relatively short amounts of text (one line at
most). They fill the same role as Swing’s JOptionPane.showInputDialog().
f
g
JFace dialogs 223
The key functionality provided by an InputDialog is the optional use of an
IInputValidator, which is responsible for validating an input string. The follow-
ing example prompts the user for a string that’s from 5 to12 characters long:
IInputValidator validator = new IInputValidator() {
public String isValid(String text) { //return an error message,
if(text.length() < 5) //or null for no error
return "You must enter at least 5 characters";
else if(text.length() > 12)
return "You may not enter more than 12 characters";
else
return null;
}
};
InputDialog inputDialog = new InputDialog( testWindow.getShell(),
"Please input a String", //dialog title
"Enter a String:", //dialog prompt
"default text", //default text
validator ); //validator to use
inputDialog.open();
The isValid() method implements the validation check for the text entered by
the user. The semantics of the method seem slightly odd at first glance, but they
let you be flexible in communicating status back to the user. The method is
passed the text to validate and returns null if the text is valid. If it’s invalid, the
method should return a String that’s displayed to the user as an error message.
It’s permissible to return different error messages in different conditions, to help
make it clear to the user exactly what you expect them to enter.
Note that this method is called frequently—each time the text is modified
(every keystroke), it’s checked for validity. This means your implementation
should perform as little work here as possible in order to return quickly. Spending
much time in this method will make your UI unbearably sluggish.
You may provide a default string to be entered into the dialog. You can pass
null, in which case the text field is left empty. The validator passed may also be
null, in which case any input is accepted.
The InputDialog is passed a title, a prompt, and optionally some default text
and an instance of IInputValidator. The dialog is shown with OK and Cancel but-
tons. The OK button is enabled or disabled at any given time depending on the
return value of isValid() from the supplied IInputValidator; if no validator is
supplied, the button is always enabled. Once the dialog has been closed, you can
retrieve the entered value using getValue().
224 CHAPTER 10
Dialogs
10.2.4 Progress monitor dialogs
Applications often perform tasks that take a long time to complete (in computer
terms, at least). While your application is busy, it’s important to let users know that
you’re working on fulfilling their request so they don’t become frustrated. JFace
makes doing so relatively easy by providing a framework for displaying the task sta-
tus to the user. We’ll start by discussing the ProgressMonitorDialog and how it fits
into this framework.
You must understand several interfaces to effectively use a ProgressMonitor-
Dialog. Figure 10.7 shows the relationship between these interfaces.
The most important things to note here are the IRunnableContext and IRunna-
bleWithProgress interfaces. IRunnableContext provides a context for any long-
running task, and ProgressMonitorDialog implements this interface. IRunnable-
WithContext uses an instance of IRunnableWithProgress, which is meant to be
implemented by a long-running task. IRunnableWithProgress is therefore the
interface that your class must implement. Finally, IRunnableWithProgress is pro-
vided with an instance of IProgressMonitor, which it uses to report its progress as
it executes.
When interacting with an IProgressMonitor, calls must take place in a certain
sequence. The process starts by calling run() on an IRunnableContext, giving it an
instance of IRunnableWithProgress. After doing whatever initialization might be
necessary, IRunnableContext calls run() on IRunnableWithProgress, passing an
IProgressMonitor. IRunnableWithProgress starts by calling beginWork() with the
total amount of work it expects to do. It periodically calls worked() and subTask()
Dialog
ProgressMonitorDialog <>
IRunnableContext
<>
IRunnableWithProgress
<>
IProgressMonitor
run() : void
run() : void run() : void
beginTask() : void
done() : void
isCanceled() : void
worked() : void
setTaskName() : void
subTask() : void
Figure 10.7 Progress monitor classes
JFace dialogs 225
to notify the progress monitor of its progress. It should also call isCanceled() to
check whether it has been canceled. Finally, done() is called when the task is fin-
ished. After the call to done(), no more calls can be made on the IProgressMonitor.
IProgressMonitor assumes that your task can be broken into abstract units of
work. It then provides a callback method to let you notify it that x units of work
have been completed. Typically, this notification is called as the last step in a loop.
However, if your task is a sequential series of slow operations, such as database or
network accesses, you can assign a value to each operation as a percentage of the
total work to be done. Doing so effectively decouples the implementation of the
long-running task from the code that notifies the user how much work remains to
be done. In our case, ProgressMonitorDialog implements IRunnableContext and
provides the instance of IProgressMonitor; but because we deal only with the
interfaces, the same code can be used with any implementation of IRunnableCon-
text. In SWT/JFace, the only other implementation of IRunnableContext is
ApplicationWindow, but it’s conceivable that you could implement your own status
notification for your specific application—for example, for truly long-running
tasks, it may be appropriate to send an email as each stage is completed. In this
case, you can use these same interfaces.
Our next code snippet provides an example of using a ProgressMonitorDia-
log. Note that the status text to display to the user is controlled by the IRunnable-
Context when it calls beginTask() and subTask(), whereas updating the progress
bar on screen is handled by the IProgressMonitor as it receives calls through its
worked() method:
ProgressMonitorDialog progressMonitor =
new ProgressMonitorDialog(shell);
try
{
IRunnableWithProgress runnable = new IRunnableWithProgress() {
public void run( IProgressMonitor progressMonitor )
throws InterruptedException
{
progressMonitor.beginTask("Doing hard work...",
100);
while(!taskCompleted())
{
progressMonitor.worked(10);
progressMonitor.subTask("sub task: " +
getCurrentTask());
... //Perform some long task
if( progressMonitor.isCanceled() )
{
throw new InterruptedException();
b Total work
c Amount worked
d Canceled check
226 CHAPTER 10
Dialogs
}
}
progressMonitor.done();
}
};
progressMonitor.run(true,
true,
runnable );
}
catch (Exception e)
{
e.printStackTrace();
}
We must notify the ProgressMonitor that we’re starting work on our task. Addi-
tionally, we must either tell it how many units of work we expect to perform or use
the constant IProgressMonitor.UNKNOWN if we don’t know. This value is a hint to
the UI—if we end up performing more work than we specified, the progress bar
will clear itself and start over until we tell it we’re done.
Here we notify the ProgressMonitor that we’ve performed some amount of work.
This causes it to update the progress bar displayed to the user, if the increase is
enough to be visible. In our case, each unit of work is 10% of the total, so every
call to this method causes the bar to increase in length by a significant amount.
If we allow the user the option of canceling our task, we must periodically check
whether they have requested cancellation. IRunnableContext.run() specifies that
when a task has canceled itself, it should throw an InterruptedException after
doing whatever cleanup is necessary. This exception eventually propagates to the
original caller of IRunnableContext.run().
When we’re finished, we must notify the IProgressMonitor.
When starting a long-running task using an IRunnableContext, we’re allowed to
specify whether we should run the task in a separate thread. If you do run in a sep-
arate thread, you’re responsible for ensuring that you access all resources in a
thread-safe manner—see Chapter 4 for a discussion of threading and SWT.
We can also specify whether this task may be canceled by the user. In the case of a
ProgressMonitorDialog, this value decides whether a Cancel button is displayed.
Generally, if your task takes long enough to require the use of a ProgressMonitor
in the first place, you should allow the user to cancel it if at all possible. Note that
clicking the Cancel button is only a recommendation to the running task; the task
won’t be forcibly stopped. It’s up to the task to check for cancellation requests and
e Done
F Fork
g Cancellable
b
c
d
e
f
g
JFace dialogs 227
handle them appropriately—it’s free to ignore them, and by default it will do so if
you forget to add the check to your code.
Using ProgressIndicator for more control
The ProgressMonitorDialog provides an easy way to keep the user informed of a
task’s progress. Sometimes, however, you’ll want more control over the way in
which a progress bar is presented. When necessary, SWT lets you instantiate and
directly use widgets that control the progress bar, as we’ll discuss next.
The ProgressIndicator widget allows you to display a progress bar without
worrying about how to fill it. Like the ProgressMonitorDialog, it supports abstract
units of work—you need only initialize the ProgressIndicator with the total
amount of work you expect to do and notify it as work is completed:
ProgressIndicator indicator = new ProgressIndicator(parent);
...
indicator.beginTask(10); //total work to be done. Control is
... //not displayed until this method is called
//use asyncExec() to update in the UI thread
Display.getCurrent()display.asyncExec(new Runnable() {
public void run() {
indicator.worked(1); //inform the ProgressIndicator that
//some amount of work has completed
}
});
As it receives notifications, the ProgressIndicator assumes responsibility for
updating the appearance of the bar on the screen by calculating the percentage
of the total work that has been completed.
The ProgressIndicator also provides an animated mode, where the total
amount of work isn’t known. In this mode, the bar continually fills and empties
until done() is called. To use animated mode, you call beginAnimatedTask()
instead of beginTask(); and there is no need to call the worked() method. Assum-
ing your work is being correctly done in a non-UI thread, this implies that you
don’t need to worry about the asyncExec() call, either.
Occasionally, you may need more control than a ProgressIndicator allows.
For times when you need to manipulate widgets at a low level, SWT provides the
ProgressBar.
If you decide that you need to use a ProgressBar directly, you’re taking respon-
sibility for changing the display of the bar yourself. The following code snippet
shows an example:
//styles are SMOOTH, HORIZONTAL, or VERTICAL
ProgressBar bar = new ProgressBar(parent, SWT.SMOOTH);
228 CHAPTER 10
Dialogs
bar.setBounds(10, 10, 200, 32);
bar.setMaximum(100);
...
for(int i = 0; i < 10; i++) {
//use asyncExec() to do updates in the UI thread
Display.getCurrent()display.asyncExec(new Runnable() {
public void run() {
//update how much of the bar should be filled in
bar.setSelection((int)(bar.getMaximum() * (i+1) / 10));
}
});
}
Note that in addition to needing to calculate the bar update amounts yourself,
calling setSelection() causes the widget to be updated every time; this behavior
is unlike that of ProgressIndicator or ProgressMonitorDialog, which will update
the display only if it has changed by an amount that will be visible to the end user.
As you can see, there is more work involved with using ProgressBars than the
other widgets we’ve discussed, and in general we recommend avoiding them
unless you have no choice. However, you may occasionally need to use them—for
example, if you need to unfill the bar, there is no way to do it with the higher-
level controls.
10.2.5 Custom dialogs
Although the dialogs that we’ve discussed so far cover many common tasks, you’ll
frequently find that your application’s requirements call for a unique dialog that
the designers of JFace couldn’t have anticipated. If you need to create a new type
of dialog for your application, we recommend that you extend from the JFace
Dialog class instead of using SWT’s Dialog. The JFace framework provides more
structure to make your job easier; using SWT, you would be taking on the job of
writing most of this common functionality yourself.
Because JFace provides the framework necessary to manage opening and clos-
ing dialogs, your job primarily consists of defining the controls present on the
page. Dialog provides several different hooks to use in defining the layout of your
dialog, depending on the level of control you need. We’ll discuss what methods
are called in what order before we talk about when to override specific methods.
Because Dialog extends Window, everything starts with the createContents()
method discussed in chapter 2. After it does some initialization, createDialog-
Area() is called. This method builds the top section of the dialog. After createDi-
alogArea() returns, createButtonBar() is called and creates a new Composite and
Layout for the bars at the bottom of the dialog. Finally, createButtonBar() calls
JFace dialogs 229
createButtonsForButtonBar() to instantiate the buttons that appear on the dia-
log. By default, OK and Cancel buttons are created.
You’re free to take control of this process at any point by overriding the appro-
priate methods. In general, however, you can limit yourself to implementing cre-
ateDialogArea() or createButtonsForButtonBar().
createDialogArea() takes a Composite that’s used as the parent for any con-
trols you create and must return a Control whose layout data is an instance of
GridData. The easiest way to fulfill this contract is to call the default implementa-
tion before you do your own work:
Composite composite = (Composite)super.createDialogArea(parent);
...//add custom controls
return composite;
Other than these restrictions, you’re free to add whatever controls are appropri-
ate for your dialog.
Like createDialogArea(), createButtonBar() must return a Control with a Grid-
Data for its layout data. Rather than override createButtonBar(), however, it’s sim-
pler to implement createButtonsForButtonBar(), where you can focus on creating
the buttons you need without worrying about layout issues. Buttons are created using
the createButton() method. For example, the default implementation of create-
ButtonsForButtonBar() uses the following code to create OK and Cancel buttons:
createButton( parent,
IDialogConstants.OK_ID,
IDialogConstants.OK_LABEL,
true ); //make this button the default
createButton( parent,
IDialogConstants.CANCEL_ID,
IDialogConstants.CANCEL_LABEL,
false );
createButton() takes the button’s parent, an integer ID, the String to use as the
label, and a flag indicating whether this button should be made the default. In
addition to adding the button to its internal list and updating the layout data
appropriately, by default createButton() also adds a SelectionListener to the
button, which causes the dialog’s buttonPressed() method to be called with the
ID of the button that was clicked. You’re free to override createButton() if you
have requirements unique to your dialog, such as adding a specific style to all but-
tons created.
230 CHAPTER 10
Dialogs
10.3 Updating WidgetWindow
You’ve already seen examples of invoking each of the dialogs provided by SWT
and JFace, so our in-depth example for this chapter demonstrates creating a cus-
tom dialog. Listing 10.1 creates a subclass of Dialog that displays two text-entry
fields, one for a username and one for a password. We’ve also added a third but-
ton that clears any text that has been entered. Figure 10.8 shows what this dialog
will look like.
To accomplish this, we override the createDialogArea(), createButtonsFor-
ButtonBar(), and buttonPressed() methods of Dialog. Notice that createDialog-
Area() is the only one of these methods that is at all complex.
package com.swtjface.Ch10;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
public class UsernamePasswordDialog extends Dialog
{
private static final int RESET_ID =
IDialogConstants.NO_TO_ALL_ID + 1;
private Text usernameField;
private Text passwordField;
public UsernamePasswordDialog(Shell parentShell)
{
super(parentShell);
}
protected Control createDialogArea(Composite parent)
{
Composite comp = (Composite)super.createDialogArea(parent);
GridLayout layout = (GridLayout)comp.getLayout();
Listing 10.1 UsernamePasswordDialog.java
Figure 10.8
The custom password dialog
super.createDialogArea()
method
b
Updating WidgetWindow 231
layout.numColumns = 2;
Label usernameLabel = new Label(comp, SWT.RIGHT);
usernameLabel.setText("Username: ");
usernameField = new Text(comp, SWT.SINGLE);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
usernameField.setLayoutData(data);
Label passwordLabel = new Label(comp, SWT.RIGHT);
passwordLabel.setText("Password: ");
passwordField = new Text(comp, SWT.SINGLE | SWT.PASSWORD);
data = new GridData(GridData.FILL_HORIZONTAL);
passwordField.setLayoutData(data);
return comp;
}
protected void createButtonsForButtonBar(Composite parent)
{
super.createButtonsForButtonBar(parent);
createButton(parent, RESET_ID, "Reset All", false);
}
protected void buttonPressed(int buttonId)
{
if(buttonId == RESET_ID)
{
usernameField.setText("");
passwordField.setText("");
}
else
{
super.buttonPressed(buttonId);
}
}
}
We override createDialogArea() to instantiate the controls necessary for this dia-
log. First we call the method on the superclass to handle all the layout informa-
tion. The superclass guarantees that it will return a Composite with a GridLayout,
so it’s safe to cast the object that is returned. After setting the layout to have two
columns, we create a pair of labels and text fields to be displayed.
Adding our Reset All button requires only a single line. We make sure to call super.
createButtonsForButtonBar() so we get the standard OK and Cancel buttons.
Finally, we want to react to the user’s button clicks. When createButton() was
called, it associated an appropriate listener with each button to ensure that
buttonPressed() is called. We check the ID of the button to see if it matches the
createButtonsForButtonBar()
method
C
d buttonPressed() method
b
c
d
232 CHAPTER 10
Dialogs
ID we used to create the Reset All button earlier. If so, we reset the text on our text
fields. Otherwise we can delegate to the superclass and let it handle the button
click as normal.
Listing 10.2 presents the Composite, which isn’t terribly interesting. Its only pur-
pose is to launch our dialog. We can’t display a dialog directly in the tab, so the
Composite creates a button instead. When the button is clicked, the listener
instantiates and displays the UsernamePasswordDialog we showed you earlier.
package com.swtjface.Ch10;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class Ch10CustomDialogComposite extends Composite
{
public Ch10CustomDialogComposite(Composite parent)
{
super(parent, SWT.NONE);
buildControls();
}
protected void buildControls()
{
FillLayout layout = new FillLayout();
setLayout(layout);
Button dialogBtn = new Button(this, SWT.PUSH);
dialogBtn.setText("Password Dialog...");
dialogBtn.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e)
{
UsernamePasswordDialog dialog =
new UsernamePasswordDialog(getShell());
dialog.open();
}
public void widgetDefaultSelected(SelectionEvent e){}
});
}
}
Listing 10.2 Ch10CustomDialogComposite.java
Summary 233
After creating a button, we attach a SelectionListener to it. When the listener
receives a widget-selected event, it creates a new UsernamePasswordDialog and
opens it, just like any prebuilt dialog that comes with JFace.
You can run this example by adding the following lines to WidgetWindow:
TabItem chap10 = new TabItem(tf, SWT.NONE);
chap10.setText("Chapter 10");
chap10.setControl(new Ch10CustomDialogComposite(tf));
10.4 Summary
Using the dialog classes provided by JFace is generally straightforward, although
you’ll be well served by carefully considering the design of your application
before you write any code.
MessageDialog and InputDialog provide powerful alternatives to the capabili-
ties provided by the dialog support in Swing. Unlike JOptionPane’s static meth-
ods, the dialog classes in JFace may be subclassed and customized to meet your
application’s unique requirements, yet they provide easy-to-use options for han-
dling the simple cases.
ErrorDialog provides more advanced error-reporting capabilities at the cost
of introducing extra library dependencies into your application as well as
parameters that you’ll never use. You should give careful thought to these issues
before you use ErrorDialog; but we think the class is valuable enough that it’s
sometimes worth using anyway, especially if you can effectively isolate knowl-
edge of the org.eclipse.core.runtime-related classes and parameters from the
rest of your application.
The IProgressMonitor framework, on the other hand, provides a clean, exten-
sible set of classes ready to be used by your code. It’s possible to manipulate the
lower-level controls directly, but we recommend sticking to the framework classes
and interfaces except in unusual circumstances. By writing to the IRunnableWith-
Progress and IProgressMonitor interfaces, you’ll make it much easier to reuse
your code in new situations as they arise.
Finally, when you’re creating a custom dialog, you’ll be better served by start-
ing from the dialog class provided by JFace, as opposed to deriving from the basic
SWT class. JFace’s framework provides the structure needed to make creating a
new dialog easy. All you need to do is override a couple of methods to define the
specific components used by your dialog.
234
Wizards
This chapter covers
■ Multipage dialogs
■ The JFace wizard framework
■ Persisting dialog settings
Multipage dialogs 235
Today, most people are familiar with the concept of an application providing a
wizard for certain tasks. By separating a complex task into a series of steps, per-
formed one at a time, it’s possible to condense an otherwise intimidating set of
options into a relatively pleasant end-user experience. A good example can be
found in Eclipse when creating a new project. Eclipse supports development in a
wide variety of languages, and each of those languages has many different options
that can be configured for a new project. Rather than dump you straight into a
dialog box filled with combo boxes, text-entry fields, and checkboxes, however,
Eclipse guides you through the process of creating a new project one step at a
time. You can choose the language for your new project, then a location, and then
configure language-specific settings. Eclipse can infer sensible defaults for most of
these options; any time after you’ve provided the bare minimum of information,
you can click the Finish button to tell the program to go ahead with creating the
project. If you choose to configure details yourself, you can freely move back and
forth between steps, changing choices you made earlier. The whole experience is
made enjoyable because you can see what effects your choices have before they’re
made permanent.
JFace provides a framework to help you create and use wizards in your own
application. The framework is composed of a three-level hierarchy. Each level can
contain multiple instances of the level below it—a container contains wizards,
whereas wizards contain pages. Each level defines both an interface and a default
implementation of that interface. It’s generally easiest to subclass the default
implementations, but for maximum flexibility the framework is designed to only
reference objects by the interfaces. Any complete implementation of a wizard-
related interface may be freely mixed with the existing classes with no problems.
Figure 11.1 provides an overview of the classes used to create a typical wizard.
You should recognize some of these classes from our discussion of dialogs in the
previous chapter.
Figure 11.1 shows how the classes and interfaces of the wizard framework fit
together. The most important thing to take away is that the concrete classes at
each level, WizardDialog and Wizard, depend only on the interface of the next
level down, not the default implementation. This same property holds when tra-
versing the other direction—although IWizardPage makes use of IWizard, it
doesn’t matter whether IWizard is implemented by Wizard or by some other class.
We’ll start at the bottom of the diagram and work our way upward through the
hierarchy, discussing each of these classes in turn. We’ll then show you how they
work together.
Multipage dialogs
236 CHAPTER 11
Wizards
11.1 Multipage dialogs
All the dialogs we discussed in the previous chapter consisted of a single page. All
the available options were displayed at the same time, and the dialog could only
open and close. However, a wizard needs to display more than one page in a sin-
gle dialog. JFace provides a generic interface for use in multipage dialogs that
serves as the parent of the wizard-specific interfaces. We’ll briefly cover this
generic interface before turning our attention to wizards.
11.1.1 IDialogPage
IDialogPage is the base interface for the pages in any multipage dialog. The
interface provides methods to configure all the attributes for a given page, such
as its title, a description, or an Image to display. The most important method is
createControl(), which is called when it’s time for the page to create its con-
tents. JFace provides a default implementation of IDialogPage with the abstract
TitleAreaDialog
<>
IWizardContainer WizardDialog
<>
IRunnableContext
<>
IDialogPage
<>
IWizard
<>
IWizardPage Wizard
WizardPage
run() : void
Figure 11.1 Wizard classes
Multipage dialogs 237
DialogPage class, which provides default implementations of all methods
declared in the interface except createControl(). On its own, IDialogPage is nei-
ther very interesting nor useful, so we’ll move on to discuss its most commonly
used subinterface: IWizardPage.
11.1.2 IWizardPage
The basic element of the wizard is a page. A page should represent one step for
the user in whatever process you’re guiding them through. Key to creating a
usable wizard is defining these steps well—too much information on the page is
confusing, but too many separate steps are annoying for the user.
JFace uses the IWizardPage interface to represent a single page in a wizard. A
variety of methods are defined in this interface; the most important ones are sum-
marized in table 11.1.
Several other straightforward getter and setter methods are also defined in IWiz-
ardPage. Implementing all of them could quickly become tedious. Luckily, JFace
comes to your rescue with a default implementation—the WizardPage class.
11.1.3 WizardPage
WizardPage implements the IWizardPage interface and provides much of the basic
logic for a page. You need only implement createControl() from IDialogPage to
build the controls appropriate to your page, although a variety of other methods
may be overridden if you wish to modify the page’s behavior.
Table 11.1 Important methods defined by IWizardPage
Method Description
getName() Each page must have a unique name. This method is often used to
retrieve a particular page from the wizard.
getNextPage(),
getPreviousPage()
These methods are called when the user clicks the Next or Previous
button to move to another page. The proper page to move to (which
may vary depending on selections the user has made) must be
returned.
isPageComplete() Indicates whether the user has filled out everything that is necessary
on this page.
canFlipToNextpage() Indicates whether the Next button should be available for use. This
method typically returns true if the page is complete and at least one
page is left in the wizard.
238 CHAPTER 11
Wizards
Listing 11.1 shows a sample implementation of WizardPage. The page presents
a single checkbox, asking the user whether to use the default directory (perhaps
for setting up a new Java project, or some similar task). Taken on its own, the class
doesn’t provide any interesting behavior. Later in the chapter, we’ll show you how
to combine multiple implementations of IWizardPage to build a complete wizard.
package com.swtjface.Ch11;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
public class DirectoryPage extends WizardPage
{
public static final String PAGE_NAME = "Directory";
private Button button;
public DirectoryPage()
{
super(PAGE_NAME, "Directory Page", null);
}
public void createControl(Composite parent)
{
Composite topLevel = new Composite(parent, SWT.NONE);
topLevel.setLayout(new GridLayout(2, false));
Label l = new Label(topLevel, SWT.CENTER);
l.setText("Use default directory?");
button = new Button(topLevel, SWT.CHECK);
setControl(topLevel);
setPageComplete(true);
}
public boolean useDefaultDirectory()
{
return button.getSelection();
}
}
The WizardPage constructor takes a page name (which must be unique in this wiz-
ard), the title for the page, and (optionally) an image descriptor for the image to
display on this page.
Listing 11.1 DirectoryPage.java
b Constructor
c createControls() method
d setControl() method
e setPageComplete() method
f useDefaultDirectory() method
b
The wizard 239
Your page must implement this method. Here you create all the controls that will
be displayed on the page. For this example, we create a single label and a checkbox.
When you’ve finished creating your controls, you must call setControl() to let
the superclass know about your new creations. Failing to do so results in internal
JFace assertions failing at runtime.
This method is used to signal whether the page has sufficient information to allow
the user to move on. For simplicity, we set it to true here. In most applications,
you’ll need to attach listeners to your controls and wait for events to signal that
the user has entered all required data.
Here we make a public method available to allow the status of the checkbox to be
queried. Other classes in the wizard can then query whether the user wants to use
the default location, and act accordingly.
The page is responsible for maintaining its own state, but it doesn’t need to worry
about other pages in the wizard or where it fits into the overall flow. Its only job is
to let the wizard framework know whether it’s complete enough to move on.
11.2 The wizard
A wizard is a step up from an individual page. A wizard groups a collection of
pages and represents the overall task that the user is trying to perform. In addi-
tion to grouping the pages, the wizard’s primary responsibility is to keep track of
whether the overall task has enough information to finish and to do whatever pro-
cessing is necessary when the task is finished.
Like wizard pages, the wizard has both an interface and a default implementation.
11.2.1 IWizard
The IWizard interface has quite a few methods, most of which are straightforward
accessors for configuration options. A few are worth mentioning in greater detail,
however; we present them in table 11.2.
As with wizard pages, JFace saves you from the drudgery of implementing all
the methods defined in IWizard by providing a default implementation in the
form of the Wizard class.
c
d
e
f
240 CHAPTER 11
Wizards
11.2.2 Wizard
Continuing our example, we’ll show the use of Wizard, JFace’s default implemen-
tation of IWizard. Our subclass is simple, because Wizard does most of the work
for us. Note that Wizard provides a variety of configuration options (such as set-
ting images or colors) that we don’t show here.
Our sample wizard continues the project setup that we discussed earlier, using
the DirectoryPage class we developed. We’ll discuss only the skeleton of the class
here and present the full listing later in the chapter:
public class ProjectWizard extends Wizard
{
public ProjectWizard()
{
super();
}
public void addPages()
{
addPage(new DirectoryPage());
//... add other pages as needed
}
Table 11.2 Important methods defined by the IWizard interface
Method Description
canFinish() Called periodically to check whether it’s currently possible for this wizard to
finish. The result is used to determine whether to enable the Finish button.
Note that returning true doesn’t imply that the wizard will immediately fin-
ish, only that if the user clicked the Finish button right now; any informa-
tion he hasn’t entered can be given reasonable defaults.
createPageControls() Intended to allow the wizard to create the controls for all of its pages in
advance, so that it can calculate the maximum size needed and avoid hav-
ing to resize when switching from one page to another. The Wizard imple-
mentation of this method calls createControl() on all pages included in
the wizard, which is generally what you want. However, this method can be
overridden if you want to delay creation of some of the pages, especially if
the creation is slow and may not be needed.
performCancel() Provides notification that the user has asked to cancel the wizard. Any
cleanup or other processing that should be done for a cancellation should
be performed here. This method returns a boolean; returning false signals
the framework that cancellation isn’t allowed at the current time.
performFinish() Provides notification that the user has successfully finished the wizard. All
logic related to the wizard finishing should be performed here. Like per-
formCancel(), this method returns a boolean, and returning false signals
the framework that the finish request was refused.
b addPages() method
Putting it all together 241
public boolean performFinish()
{
DirectoryPage dirPage =
(DirectoryPage)getPage(DirectoryPage.PAGE_NAME);
if(dirPage.useDefaultDirectory())
{
...
}
return true;
}
public boolean performCancel()
{
//... perform cancel processing
return true;
}
}
This method is called to tell the wizard to add any pages it desires. Pages are nor-
mally displayed in the order they’re added. To change this behavior, you must
override getNextPage() and getPreviousPage().
Here we go through the actual process of creating our project. The Directo-
ryPage we added earlier is retrieved using its page name, and it can then be que-
ried for the data we’re interested in. This also demonstrates why each page in a
wizard must have a unique name—if there were duplicates, getPage() wouldn’t be
able to determine which page to return.
If any cleanup must be done when the user cancels, we do it here.
As you can see, Wizard takes care of most of the work for you. Aside from setting
configuration options, there is little to do other than implement performFinish()
and, if you wish, performCancel().
11.3 Putting it all together
Finally, we come to the layer that controls the entire wizard: the wizard container.
Although at first glance it may seem odd to have this separate from the wizard
itself, it allows one container to group multiple wizards together and switch
between them.
11.3.1 Wizard containers
A wizard container is meant to act as a host for one or more wizards. The IWizard-
Container interface isn’t interesting in itself—it provides methods to get the
c performFinish() method
d performCancel() method
b
c
d
242 CHAPTER 11
Wizards
current page, several methods to update aspects of the container’s window, and a
method to programmatically change the currently displayed page. Most of the
real action comes from WizardDialog, which implements IWizardContainer.
11.3.2 WizardDialog
Clients are free to provide their own implementations of IWizardContainer, but
WizardDialog will be sufficient for most needs. Typically it isn’t even necessary to
subclass WizardDialog. We’ll first show how to use WizardDialog as is, and then dem-
onstrate creating a subclass that decides at runtime whether to display certain pages.
First, listing 11.2 shows the standard WizardDialog.
package com.swtjface.Ch11;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.widgets.Display;
public class WizardDialogDemo
{
public static void main(String[] args)
{
ApplicationWindow testWindow = new ApplicationWindow(null);
testWindow.setBlockOnOpen(false);
testWindow.open();
ProjectWizard wizard = new ProjectWizard();
WizardDialog wizardDialog = new WizardDialog(
testWindow.getShell(),
wizard);
wizardDialog.create();
wizardDialog.open();
}
}
As our demo program shows, if all you wish to do is display a wizard’s pages in
order, using a WizardDialog is simple. Just pass the IWizard to the dialog’s con-
structor and call open(), and your wizard’s pages will be displayed in the order in
which they were added.
Listing 11.2 WizardDialogDemo.java
Combining wizards 243
A warning about initialization errors
The example code will run as we’ve presented it, but there is a gotcha to be
aware of if you’re testing wizard code on your own. When we were originally test-
ing wizard functionality, we created a subclass of WizardDialog and added a
main() method. Unfortunately, this doesn’t work due to a subtle interaction
between SWT and the java classloader. When you type java TestWizardDialog,
the Java VM first loads and initializes the TestWizardDialog class; it then looks for
and executes the static void main() method defined there. To initialize
TestWizardDialog, the VM needs to initialize all of its superclasses, which include
org.eclipse.jface.dialogs.Dialog. Dialog, however, has static initialization
code that attempts to retrieve certain images from the ImageRegistry. Because
the system hasn’t been fully initialized at this point (remember, main() hasn’t
even started execution), retrieving the values from the registry fails, throwing a
NullPointerException and causing the main thread to terminate. In a typical
application this won’t be an issue, because main() is usually located in a class by
itself or in a subclass of ApplicationWindow. However, it’s worth being aware of
this potential issue here and in other SWT classes, in case you’re ever bitten by it.
The symptoms are strange, but the solution is simple—put your main() method
in a class that doesn’t extend an SWT class.
11.4 Combining wizards
Occasionally you may have a situation that requires the user to select from one of
several possible wizards. A good example occurs in Eclipse when you select
File->New->Other. You’re shown a wizard with a variety of options to choose which
new object you wish to create. Whichever one you choose launches a separate wiz-
ard as appropriate. JFace provides support for this use case with the WizardSelec-
tionPage class and the IWizardNode interface.
11.4.1 WizardSelectionPage
WizardSelectionPage extends WizardPage and is in general intended to act like
any other page in a wizard. One additional method is important for this class:
setSelectedNode(), which takes an IWizardNode as a parameter. The subclass
should call this method as appropriate when a node has been selected.
As is the case when you subclass WizardPage directly, you must implement cre-
ateControl() in a subclass of WizardSelectionPage. The method should be imple-
mented to present the available choices to the user—often it’s in the form of a
tree, but the JFace designers chose to not make any assumptions about what
244 CHAPTER 11
Wizards
might be the best presentation for your situation. Each available selection should
be tied to an instance of IWizardNode.
11.4.2 IWizardNode
An IWizardNode is intended to be a placeholder for an actual instance of a wizard.
WizardSelectionPage passes these instances to setSelectedNode() and retrieves
them from getSelectedNode() when the selection page has completed. This inter-
face includes two important methods (see table 11.3).
Generally, you’ll use these classes by subclassing WizardDialog. After a WizardSe-
lectionPage has finished, you’ll call getSelectedNode() to retrieve the node the
user chose. You can then call getWizard() on that node to retrieve the wizard and
pass the wizard instance to setWizard() in WizardDialog.
11.5 Persistent wizard data
Sometimes you need to save a wizard’s data between invocations. For example, the
Create New Java Class wizard in Eclipse includes a series of checkboxes to gener-
ate code such as a public static void main() method or default implementa-
tions of abstract methods in the superclass. The state of these checkboxes is saved
between uses of the wizard so that if you uncheck the box to generate a main()
method once, you won’t have to change it every time.
JFace provides a convenient way to manage these persistent settings with the
DialogSettings class. Although theses techniques are often used with wizards,
there is no reason the same classes can’t be used by any other dialog that wishes to
persist state.
Table 11.3 Important methods defined by the IWizardNode interface
Method Description
getWizard() Retrieves the wizard tied to this node. It’s assumed that the wizard
won’t be created until this method is called for the first time, and that
if this method is called multiple times, the same cached wizard
instance will be returned rather than a new one being created every
time.
isContentCreated() Queries the status of an IWizardNode and checks whether it has
already instantiated a wizard.
Persistent wizard data 245
11.5.1 DialogSettings
DialogSettings provides an implementation of the IDialogSettings interface
using a hash table and backed by an XML file. This is sufficient for most needs; but
you should generally reference objects in terms of the interface rather than the
concrete implementation, in case you find it necessary to switch implementations
at some point in the future.
Using IDialogSettings is simple:
IDialogSettings settings = new DialogSettings("mydialog");
settings.put("checkboxOneChecked", true);
settings.put("defaultName", "TestDialog");
settings.save("settings.xml");
IDialogSettings loadedSettings = new DialogSettings(null);
loadedSettings.load("settings.xml");
loadedSettings.getBoolean("checkboxOneChecked");
loadedSettings.get("defaultName");
When run, this code writes a simple XML file to the current directory that (once
cleaned up for readability) looks something like this:
Storing values in XML this way has the advantage that it’s easy to edit them by
hand, either to test odd combinations of values or to make emergency repairs if
invalid values are somehow stored.
Storing values
The values are put into the settings object. It may be saved either to a file by
giving the save() method a filename (as shown) or to any java.io.Writer. Like-
wise, it’s read from the file (or a java.io.Reader) using the load() method.
Because DialogSettings loads and saves using XML, you’ll need xercesImpl.jar
and xmlParserAPIs.jar (from $ECLIPSE_HOME/plugins/org.apache.xerces_x.y.z)
in your classpath.
The name you pass to the constructor of DialogSettings creates a section. Sec-
tions are ways to group related data in the overall dialog settings. You can retrieve
a section by name using getSection(), which returns another instance of IDia-
logSettings. As you can see from the code that loads the settings, there is no
246 CHAPTER 11
Wizards
need to specify section names when loading; they’re picked up automatically from
the file.
Retrieving values
Calling get() or getArray() returns null if no value has been set for the given key.
However, the various numeric get()s throw NumberFormatExceptions if you
attempt to retrieve a nonset value (or if the file has been edited by hand so it’s no
longer a valid number), so you must be prepared to handle these cases if there is
a possibility that some values haven’t been set.
How useful all this is depends on your target platform. In Java 1.4, similar func-
tionality is provided by the classes in the java.util.prefs package. From a design
standpoint, it’s generally better to stick to the facilities provided by the base plat-
form, but you don’t have this luxury if you’re supporting Java 1.3 or earlier in your
application; in this case, IDialogSettings can make a convenient alternative.
11.6 Updating WidgetWindow
To create a functional wizard, we need a few more classes than are usually
required for WidgetWindow. You saw DirectoryPage earlier in the chapter. In order
to finish the example, we need to add a couple more pages, complete the imple-
mentation of ProjectWizard, and add a Composite subclass.
First, let’s look at the ChooseDirectoryPage. This page is invoked when the user
declines to use the default directory. The page presents a text input field for the
user to enter a choice of directory. ChooseDirectoryPage is presented in
listing 11.3.
NOTE It’s important to remember that this design is purely for the purpose of
demonstrating how multiple wizard pages work. In a real application, you
should let the user enter his choice of directory on the same page as the
use default checkbox, and you’ll probably use a DirectoryDialog as dis-
cussed in the previous chapter.
package com.swtjface.Ch11;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
public class ChooseDirectoryPage extends WizardPage
Listing 11.3 ChooseDirectoryPage.java
Updating WidgetWindow 247
{
public static final String PAGE_NAME = "Choose Directory";
private Text text;
public ChooseDirectoryPage()
{
super(PAGE_NAME, "Choose Directory Page", null);
}
public void createControl(Composite parent)
{
Composite topLevel = new Composite(parent, SWT.NONE);
topLevel.setLayout(new GridLayout(2, false));
Label l = new Label(topLevel, SWT.CENTER);
l.setText("Enter the directory to use:");
text = new Text(topLevel, SWT.SINGLE);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
setControl(topLevel);
setPageComplete(true);
}
public String getDirectory()
{
return text.getText();
}
}
This page is similar to DirectoryPage. The input field is presented to the user, and
a public method is made available for the rest of the application to query the
user’s choice.
The final page in our example wizard is a summary of the user’s choices. There
is no user interaction on this page; it displays a text string indicating the choice
made. SummaryPage appears in listing 11.4.
package com.swtjface.Ch11;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
public class SummaryPage extends WizardPage
{
public static final String PAGE_NAME = "Summary";
Listing 11.4 SummaryPage.java
248 CHAPTER 11
Wizards
private Label textLabel;
public SummaryPage()
{
super(PAGE_NAME, "Summary Page", null);
}
public void createControl(Composite parent)
{
Composite topLevel = new Composite(parent, SWT.NONE);
topLevel.setLayout(new FillLayout());
textLabel = new Label(topLevel, SWT.CENTER);
textLabel.setText("");
setControl(topLevel);
setPageComplete(true);
}
public void updateText(String newText)
{
textLabel.setText(newText);
}
}
In some respects, this class is the opposite of the previous two. Instead of provid-
ing a method for clients to query the state of the page, the class offers a method to
update the displayed text. As an alternative to forcing the state of the page to be
explicitly updated, it would also be possible to let this class query some shared
state when it needs to display itself, such as a Project object that represents the
project that’s in the process of being built. This approach would require overrid-
ing the setVisible() method defined in IDialogPage. When setVisible(true) is
called, the textLabel and any other relevant widgets will be refreshed. In general,
you should prefer this approach, because it localizes knowledge of how to display
things to the SummaryPage. We implemented it as we did to avoid having to write a
Project class and to keep the example short.
We next present the full implementation of ProjectWizard in listing 11.5. There
are two enhancements over the snippet we showed earlier in the chapter. First,
we’ve expanded the implementation of addPages() to add all the pages needed for
the wizard. More importantly, we’ve expanded the logic in getNextPage().
Updating WidgetWindow 249
package com.swtjface.Ch11;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.Wizard;
public class ProjectWizard extends Wizard
{
public void addPages()
{
addPage(new DirectoryPage());
addPage(new ChooseDirectoryPage());
addPage(new SummaryPage());
}
public boolean performFinish()
{
DirectoryPage dirPage = getDirectoryPage();
if (dirPage.useDefaultDirectory())
{
System.out.println("Using default directory");
}
else
{
ChooseDirectoryPage choosePage = getChoosePage();
System.out.println(
"Using directory: " + choosePage.getDirectory());
}
return true;
}
private ChooseDirectoryPage getChoosePage()
{
return (ChooseDirectoryPage) getPage(
ChooseDirectoryPage.PAGE_NAME);
}
private DirectoryPage getDirectoryPage()
{
return (DirectoryPage) getPage(DirectoryPage.PAGE_NAME);
}
public boolean performCancel()
{
System.out.println("Perform Cancel called");
return true;
}
public IWizardPage getNextPage(IWizardPage page)
{
if (page instanceof DirectoryPage)
{
Listing 11.5 ProjectWizard.java
250 CHAPTER 11
Wizards
DirectoryPage dirPage = (DirectoryPage) page;
if (dirPage.useDefaultDirectory())
{
SummaryPage summaryPage =
(SummaryPage) getPage(SummaryPage.PAGE_NAME);
summaryPage.updateText("Using default directory");
return summaryPage;
}
}
IWizardPage nextPage = super.getNextPage(page);
if (nextPage instanceof SummaryPage)
{
SummaryPage summary = (SummaryPage) nextPage;
DirectoryPage dirPage = getDirectoryPage();
summary.updateText(
dirPage.useDefaultDirectory()
? "Using default directory"
: "Using directory:" + getChoosePage().getDirectory());
}
return nextPage;
}
}
The meat of this class is contained in the getNextPage() method. It’s here that we
control the navigation between pages. We must handle two scenarios correctly.
First is the case when the user is leaving the DirectoryPage, which is where she
can choose to use the default directory. The parameter passed to getNextPage() is
the page the user is coming from, so we check whether it’s the DirectoryPage. If
so, after casting the parameter to the correct implementation of IWizardPage, we
query the status of the checkbox. If it has been checked, we want to skip straight
to the status page, so we retrieve it using getPage() and return it.
If the previous page wasn’t DirectoryPage, or if the user unchecked the check-
box, we fall back on the default behavior for determining the next page by calling
super.getNextPage(). However, if the next page will be the summary page, we
need to make sure to update the text to reflect the user’s current choice. In this
case, we cast the IWizardPage to a SummaryPage and then retrieve the other pages
as necessary to determine the correct text to display. As noted after our discussion
of SummaryPage, this logic is caused by our not having a shared state available to
SummaryPage; in general it should be avoided because the complexity can quickly
become overwhelming in a wizard with more pages.
The final class to complete our example is the composite used by WidgetWin-
dow, shown in listing 11.6. Like the composite used in the previous chapter, this
Updating WidgetWindow 251
one isn’t very interesting. It presents a button that, when clicked, initializes and
displays a WizardDialog with our ProjectWizard.
package com.swtjface.Ch11;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class Ch11WizardComposite extends Composite
{
public Ch11WizardComposite(Composite parent)
{
super(parent, SWT.NONE);
buildControls();
}
protected void buildControls()
{
final Composite parent = this;
FillLayout layout = new FillLayout();
parent.setLayout(layout);
Button dialogBtn = new Button(parent, SWT.PUSH);
dialogBtn.setText("Wizard Dialog...");
dialogBtn.addSelectionListener(new SelectionListener()
{
public void widgetSelected(SelectionEvent e)
{
WizardDialog dialog =
new WizardDialog(
parent.getShell(),
new ProjectWizard());
dialog.open();
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
}
Listing 11.6 Ch11WizardComposite.java
252 CHAPTER 11
Wizards
The part of this class to notice is in widgetSelected(), where we initialize the dia-
log. Notice that WizardDialog works exactly as we want with no modifications. We
can pass a new instance of our ProjectWizard to it and let it do its thing.
11.7 Summary
The wizard framework builds on the dialog classes we’ve already discussed by add-
ing support for multiple pages in a single dialog. There are three levels in the
hierarchy of the wizard framework. IWizardContainer, which is implemented by
WizardDialog, contains instances of IWizard, usually Wizard. An IWizard, in turn,
contains multiple IWizardPages.
The life cycle of a wizard isn’t complex. Each IWizardPage implements the
createControl() method to build whatever controls are necessary to display.
addPages() is called on IWizard, which instantiates and tracks the pages it intends
to use. In the default Wizard implementation, this requires nothing more than
calling addPage() for each one. As each page is displayed, isPageComplete() and
canFlipToNextPage() are called to determine whether the Next and Previous but-
tons should be enabled. When the user clicks either Next or Previous, getNext-
Page() or getPreviousPage() is called on the current page to determine which
page should be displayed next. Finally, once the user clicks Finish or Cancel, per-
formFinish() or performCancel() is called on the wizard itself to signal that the
appropriate processing should be performed.
In addition to the standard three interfaces necessary to implement any wizard,
JFace provides an additional level in the hierarchy that you can use to assemble
multiple wizards. A WizardSelectionPage uses instances of IWizardNode to present
multiple wizards to the user, allowing one to be selected. Each node is set up to
instantiate the wizard only after it’s selected, to avoid doing unnecessary work.
The IDialogSettings interface provides a way to easily store persistent settings
data, as long as those settings can be represented by Java primitives. The default
implementation, DialogSettings, serializes the objects to an XML file.
253
Advanced features
This chapter covers
■ Interacting with the system clipboard
■ Implementing drag and drop
■ Storing user preferences
■ Adding images to labels
■ Embedding a web browser within your application
254 CHAPTER 12
Advanced features
By now, you should be familiar with everything you need to build a working appli-
cation using SWT and JFace. We’ve covered the essential widgets, shown you how
to easily position them on the screen, and discussed the issues to keep in mind to
ensure a well-designed piece of software. However, you’ll want to become familiar
with a few miscellaneous topics as your use of SWT increases.
This chapter covers a variety of issues. We’ll start by discussing how to transfer
data to and from the underlying operating system, and we’ll show how to use this
capability to implement drag-and-drop and copy-and-paste functionality in your
applications. Next we’ll discuss two frameworks provided by SWT for managing user
preferences and enhancing how your labels are displayed by the viewer classes.
Finally, we’ll close with a brief look at a new widget provided in SWT 3.0, the Browser,
which enables you to control the user’s web browser from within your application.
Because some of these classes are designed around interacting directly with the
underlying operating system, there are differences in how they function on differ-
ent platforms. In addition, some widgets aren’t fully supported on all platforms at
the current time. We’ll point out these platform-specific gotchas as we go along.
12.1 Transferring data
Although you may not notice it, almost any application you use is constantly shuf-
fling data back and forth behind the scenes. Every time you cut and paste, the
application must interact with the system clipboard, where data is stored tempo-
rarily. Dragging and dropping items requires similar communication, because the
application needs to let the system know what kind of data formats it can provide
as well as whether it will accept any given data type.
SWT handles many of the common cases automatically. For example, you saw
in earlier chapters that it’s possible to cut and paste text from a text control using
the standard keyboard shortcuts for your operating system. However, you need to
handle this work yourself if you wish to support drag-and-drop operations or cut-
ting and pasting with application-specific formats. This section will cover how to
do so, as we build a primitive file browser that supports dragging, dropping, and
copy-and-paste operations both internally and interacting with the native operat-
ing system tools.
Before we get too deep into the technical details, look at figure 12.1, which
shows what we’re about to build. Two ListViewers are used, each displaying the
Transferring data 255
contents of a certain directory. Dragging a file or files from one to the other will
cause a corresponding file copy on disk. The Copy and Paste buttons copy the
current selection in the left list to the system clipboard or paste files from the clip-
board to the directory currently displayed in the left list, respectively.
12.1.1 The Transfer class
In order for data to be moved or copied between elements, there must be a way
for those elements to agree on what format that data is in. If the application
doesn’t understand a given format, it won’t make sense to try to import it—for
example, there is no way for a text editor to handle an image that’s dropped into
it. SWT provides a relatively simple way for elements to negotiate what data for-
mats are acceptable through the use of the Transfer class and its subclasses.
Each subclass of Transfer represents a certain type of data and knows how to
convert that data between a Java representation and one that makes sense to the
underlying operating system. SWT ships with Transfer subclasses to handle files,
plain text, and text in Rich Text Format (RTF). If none of these meets your needs,
you can write your own Transfer implementation, although doing so is beyond the
scope of this book. Consult the Javadocs for org.eclipse.swt.dnd.Transfer and
org.eclipse.swt.dnd.ByteArrayTransfer if you need a custom implementation.
For our purposes, we can treat the Transfer instances as black boxes that rep-
resent certain data types. Each subclass has a static factory method getInstance()
to obtain an instance of the class. We can pass these instances around to designate
what data types we’re interested in, but we never need to call any methods on
them ourselves. Under the hood, SWT calls javaToNative() and nativeToJava()
when appropriate to transform data.
Table 12.1 shows the default general-purpose transfer agents that SWT provides.
Figure 12.1
The File Browser, displaying the
contents of two different directories
256 CHAPTER 12
Advanced features
12.1.2 Drag-and-drop capability
Allowing a user to drag an item from its current location to wherever they wish it
to be can help make your application’s interface intuitive and easy to use. How-
ever, to accomplish this, a fair amount of work must go on behind the scenes.
First, your application must make the system aware of the kinds of data it can pro-
vide or knows how to accept. These data types are configured separately for each
widget—just because an object can accept objects dropped into it doesn’t imply
that it can provide data to be dragged out. Once the system is aware of the capa-
bilities of the various widgets in your application, those widgets will receive events
when a drag or drop occurs that it must use to implement appropriate logic.
Types of drag-and-drop operations
When a user drags an item from one place to another, there are typically multiple
ways the action can be interpreted—for example, as either a copy or a move. Each
operating system has different keyboard conventions that are used to toggle
between these operations. However, your widgets also need to tell SWT what oper-
ations they support. A read-only display may support copying items by dragging
them out but may not allow the user to move them. Support for these operations
is designated by using constants from the org.eclipse.swt.dnd.DND class, summa-
rized in table 12.2.
Table 12.1 Default transfer agents provided by SWT
Transfer class name Description
FileTransfer Transfers one or more files. Data is an array of Strings, each of
which is the path to a file or directory.
TextTransfer Transfers plain text. Data is a String.
RTFTransfer Transfers text in RTF. Data is a String with rich text formatting.
Table 12.2 Types of transfer operations
Operation constant Description
DROP_COPY The item is copied when dragged in or out of this control.
DROP_MOVE The item is moved from its current location to wherever it’s
dropped.
DROP_LINK Dropping the item creates a link back to the original.
DROP_NONE Nothing happens when the item is dropped.
Transferring data 257
Dropping items into an application
You can register a control to be able to receive dropped data by using an instance
of DropTarget. DropTarget stores both the type of data a widget can select and the
operations that are legal to perform on that widget. The operating system uses
this information to provide visual feedback as to whether an item may be dropped
when it’s dragged over the widget. Once the target has been registered, any
DropTargetListeners will receive DropTargetEvents when the user attempts to
drop something within the control.
Creating a DropTarget is simple. You instantiate it with a widget and a set of
operations, and you set the allowed data types by calling setTransfer(). A listener
is then attached, which contains the logic to execute when something is dropped.
The following snippet demonstrates:
int operations = DND.DROP_MOVE | DND.DROP_COPY;
DropTarget target = new DropTarget(control, operations);
Transfer[] transfers = new Transfer[] {
TextTransfer.getInstance(),
RTFTransfer.getInstance() };
target.setTransfer(transfers);
target.addDropListener( new DropTargetListener(){...} );
If you’re working with a viewer, you must call the method addDropSupport() on
the viewer instance instead of attempting to manipulate the control directly. The
next snippet, taken from our file browser example, shows how we add support for
dropping files into a list viewer:
Transfer[] types = new Transfer[] {
FileTransfer.getInstance()
};
viewer.addDropSupport(DND.DROP_COPY,
types,
new FileDropListener(this));
The registration process isn’t complicated. The most important part is imple-
menting the DropTargetListener interface. The methods in this interface are
called in the following specific order as the user drags an item into a control:
1 dragEnter()—The cursor has entered the boundaries of the control while
dragging an item.
2 dragOver()—The cursor is moving across the control, dragging an item.
3 dragOperationChanged()—This method may be called multiple times dur-
ing the operation, whenever the user changes the type of operation to be
258 CHAPTER 12
Advanced features
performed. This occurs most often when the user presses or releases a
modifier key, such as Ctrl or Option.
4 dropAccept()—The user has dropped an item in the control. This is the
application’s last chance to reject the drop or to change the type of opera-
tion being performed.
5 drop()—The data has been dropped. The listener must implement the
appropriate logic to handle the data it has been given.
Each method is given a DropTargetEvent containing information about the cur-
rent operation. Most important, this event contains a list of data types that the
data source can support, the current data type that will be dropped, the opera-
tions available to be performed, and the current operation to be performed. You
can change the data type to be used and the operation to be performed by modi-
fying the currentDataType and detail fields, respectively.
A sixth method, dragLeave(), may be called at any time before dropAccept().
This method lets the application know that the user has moved the cursor outside
of the control and that no drop will occur.
Unless you need to dynamically change the data type or operation, the only
method for which you need to implement logic is drop(). SWT and the operating
system handle the other details; if a suitable agreement on data type and opera-
tion can’t be reached, the drop won’t be allowed, and your listener won’t receive
the events. Listing 12.1 shows how we implemented a DropTargetListener for the
file browser example.
package com.swtjface.Ch12;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
final class FileDropListener implements DropTargetListener
{
private final FileBrowser browser;
FileDropListener(FileBrowser browser)
{
this.browser = browser;
}
public void dragEnter(DropTargetEvent event) {}
public void dragLeave(DropTargetEvent event) {}
public void dragOperationChanged(DropTargetEvent event) {}
public void dragOver(DropTargetEvent event) {}
public void dropAccept(DropTargetEvent event) {}
Listing 12.1 FileDropListener.java
Transferring data 259
public void drop(DropTargetEvent event)
{
String[] sourceFileList = (String[])event.data;
browser.copyFiles(sourceFileList);
}
}
The logic to implement the drop operation is simple. We only support the file
transfer type, so when this method is called it’s safe to assume that the data type is
FileTransfer, which provides the data as an array of Strings. If we supported
other data types, we would need to add conditional logic to react differently
depending on the data type. Likewise, we can assume that the operation is a copy.
Therefore, all our listener needs to do is extract the list of filenames and tell the
FileBrowser component to copy them.
Dragging items from your application
Allowing data to be dragged from your application follows a process similar to
what you just saw. A DragSource is created to register the control as a source of
data. An implementation of DragSourceListener receives events when the user
starts a drag operation and is responsible for implementing the logic once the
item(s) have been dropped. The registration code looks almost identical. The
first snippet shows how to create a DragSource by hand:
int operations = DND.DROP_MOVE | DND.DROP_COPY;
DragSource source = new DragSource(control, operations);
Transfer[] transfers = new Transfer[] {
TextTransfer.getInstance(),
RTFTransfer.getInstance() };
source.setTransfer(transfers);
source.addDragListener( new DragSourceListener(){...} );
Just like for a DropTarget, when you’re using a viewer a method on the viewer han-
dles some of the work for you. The next excerpt shows the drag registration in the
file browser example:
Transfer[] types = new Transfer[] {
FileTransfer.getInstance()
};
...
viewer.addDragSupport(DND.DROP_COPY,
types,
new FileDragListener(this));
The drop method
260 CHAPTER 12
Advanced features
The DragSourceListener interface is much simpler than the one to handle drops;
it consists of only three methods, called in the following order:
1 dragStart()—The user has started dragging data from this control. If the
drag should be allowed to proceed, the doit field of the event must be set to
true.
2 dragSetData()—A drop has been performed. This method must supply
the data to be dropped by putting it in the event’s data field.
3 dragFinished()—The drop has completed successfully. Any cleanup
remaining to be done, such as deleting the original data for a move oper-
ation, should be performed here.
Each method receives a DragSourceEvent with data about the drag. Unlike the
DropTargetEvent, this event may not be modified except as noted.
Listing 12.2 shows how we implement this listener in the filesystem browser.
package com.swtjface.Ch12;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
public class FileDragListener implements DragSourceListener
{
private FileBrowser browser;
public FileDragListener(FileBrowser browser)
{
this.browser = browser;
}
public void dragStart(DragSourceEvent event)
{
event.doit = true;
}
public void dragSetData(DragSourceEvent event)
{
event.data = browser.getSelectedFiles();
}
public void dragFinished(DragSourceEvent event) {}
}
Listing 12.2 FileDragListener.java
b Drag has started
c Provide data to be
transferred
d Clean up
Transferring data 261
This method is called when the user attempts to drag an item from the control. If
this drag should be allowed, the doit field must be set to true. Our example
always allows drags, so we always set this field to true.
The item has been dropped in a receiver, and data must be provided. This data
must match what is expected by the current data type, obtained from the
dataType field. We only support FileTransfers, so our implementation gets the
currently selected files from the browser and inserts them into the event.
The operation has completed successfully. If the operation was a move, the origi-
nal data should be deleted. Likewise, if any cleanup is associated with the other
operation types, it should be performed in this method. Because our example
only supports copying, our implementation is empty.
12.1.3 Using the clipboard
The process of copying data to or from the system clipboard has some similarities
to dragging and dropping. It also uses Transfer subclasses to copy data to or from
the operating system. The primary difference is that it isn’t necessary to register in
advance to use the system clipboard, as it is when you’re dragging or dropping. Any
time your application decides to cut, copy, or paste, usually in response to an Action
of some sort, it can access the clipboard using the org.eclipse.swt.dnd.Clipboard
class and do whatever it needs to do.
Each instance of Clipboard is created with a Display. Remember that on some
platforms, accessing the clipboard may use native resources. It’s therefore critical
that you use dispose() to discard the Clipboard as soon as you’ve finished using it.
Putting data into the clipboard
Placing data on the system clipboard is a simple method call, setContents(). All it
must do is pass the data, along with suitable Transfers to interpret it. This snippet
shows how this is done for our filesystem browser:
Clipboard clipboard = new Clipboard(getDisplay());
FileTransfer transfer = FileTransfer.getInstance();
clipboard.setContents(
new Object[] { browser.getSelectedFiles()},
new Transfer[] { transfer });
clipboard.dispose();
Notice that we pass both an Object array and a Transfer array. These arrays must
be the same size, and the Transfer instance at index i must be able to handle the
Object at index i in the Object array. This way, all data in all supported formats is
b
c
d
262 CHAPTER 12
Advanced features
placed on the clipboard at once, and your application doesn’t need to worry
about when it’s removed.
Although our example implements a copy operation, not a cut, the Clipboard
doesn’t care. It accepts the data; whether that data should be removed from its
original source is up to the application and must be implemented separately.
Pasting data from the clipboard
Likewise, copying data from the clipboard is a simple process. When your appli-
cation wishes to retrieve data that is currently stored in the clipboard, it can use
two methods.
getAvailableTypeNames() returns an array of Strings with the names of all data
types that the clipboard can currently provide. These values are operating-system
dependent, and the String returned for a given data type will vary from platform
to platform. Hence, this method is intended as a debugging aid and shouldn’t be
used in production code. However, when you’re debugging and trying to figure
out what data is currently on the clipboard, this method is invaluable.
getContents() takes a Transfer and returns the data from the clipboard in the
format given by that Transfer, or null if no data can be provided in the given for-
mat. If your application supports multiple data formats, you’ll typically call get-
Contents() repeatedly, passing a different Transfer type each time, until you find
data that you can handle.
This code implements a paste in the file browser example:
Clipboard clipboard = new Clipboard(getDisplay());
FileTransfer transfer = FileTransfer.getInstance();
Object data = clipboard.getContents(transfer);
if (data != null)
{
browser.copyFiles((String[]) data);
}
clipboard.dispose();
You should always check for null after calling getContents(). It’s always possible
that the data currently on the clipboard can’t be converted to a format your appli-
cation understands, or that the clipboard is empty. Forgetting to check will even-
tually lead to NullPointerExceptions, which users never appreciate.
12.1.4 The filesystem browser
You’ve seen all the code our file browser uses to interact with the operating sys-
tem. Some snippets have been presented out of context, however, and you haven’t
Transferring data 263
seen the FileBrowser class itself. For completeness, we’ll present listings for the
remaining code needed to compile and run this example.
First, listing 12.3 shows the Composite that builds the visual components. This
class instantiates the visual controls and attaches listeners to the two buttons to
handle the copy and paste logic when the buttons are clicked.
package com.swtjface.Ch12;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
public class Ch12FileBrowserComposite extends Composite
{
private FileBrowser browser;
public Ch12FileBrowserComposite(Composite parent)
{
super(parent, SWT.NONE);
RowLayout layout = new RowLayout(SWT.HORIZONTAL);
setLayout(layout);
Button copyButton = new Button(this, SWT.PUSH);
copyButton.setText("Copy");
copyButton.addSelectionListener(new SelectionListener()
{
public void widgetSelected(SelectionEvent e)
{
Clipboard clipboard = new Clipboard(getDisplay());
FileTransfer transfer = FileTransfer.getInstance();
clipboard.setContents(
new Object[] { browser.getSelectedFiles()},
new Transfer[] { transfer });
clipboard.dispose();
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
Button pasteButton = new Button(this, SWT.PUSH);
pasteButton.setText("Paste");
pasteButton.addSelectionListener(new SelectionListener()
{
Listing 12.3 Ch12FileBrowserComposite.java
264 CHAPTER 12
Advanced features
public void widgetSelected(SelectionEvent e)
{
Clipboard clipboard = new Clipboard(getDisplay());
FileTransfer transfer = FileTransfer.getInstance();
Object data = clipboard.getContents(transfer);
if (data != null)
{
browser.copyFiles((String[]) data);
}
clipboard.dispose();
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
browser = new FileBrowser(this);
new FileBrowser(this);
}
}
Next, listing 12.4 shows the FileBrowser class. Each instance of FileBrowser cre-
ates and manages a ListViewer. A ContentProvider reads the contents of the cur-
rent directory, and we add a sorter and a LabelProvider to make the display
clearer. (We covered the use of these components in chapters 8 and 9, so we won’t
discuss them in detail here.) FileBrowser also contains public methods to retrieve
the list of currently selected files and to copy a list of files into the current direc-
tory. This code isn’t SWT related; if you’re unfamiliar with what’s going on, we rec-
ommend consulting the documentation for the java.io package.
package com.swtjface.Ch12;
import java.io.*;
import java.util.*;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.dnd.*;
import org.eclipse.swt.widgets.Composite;
public class FileBrowser
{
private ListViewer viewer;
private File currentDirectory;
public FileBrowser(Composite parent)
{
super();
Listing 12.4 FileBrowser.java
Transferring data 265
buildListViewer(parent);
Transfer[] types = new Transfer[] {
FileTransfer.getInstance()
};
viewer.addDropSupport(DND.DROP_COPY,
types,
new FileDropListener(this));
viewer.addDragSupport(DND.DROP_COPY,
types,
new FileDragListener(this));
}
private void buildListViewer(Composite parent)
{
viewer = new ListViewer(parent);
viewer.setLabelProvider(new LabelProvider()
{
public String getText(Object element)
{
File file = (File) element;
String name = file.getName();
return file.isDirectory() ? "
" + name : name;
}
});
viewer.setContentProvider(new IStructuredContentProvider()
{
public Object[] getElements(Object inputElement)
{
File file = (File) inputElement;
if (file.isDirectory())
{
return file.listFiles();
}
else
{
return new Object[] { file.getName()};
}
}
public void dispose()
{
}
public void inputChanged(Viewer viewer,
Object oldInput,
Object newInput)
{
}
});
266 CHAPTER 12
Advanced features
viewer.setSorter(new ViewerSorter()
{
public int category(Object element)
{
return ((File) element).isDirectory() ? 0 : 1;
}
public int compare(Viewer viewer, Object e1, Object e2)
{
int cat1 = category(e1);
int cat2 = category(e2);
if (cat1 != cat2)
return cat1 - cat2;
return ((File) e1).getName().compareTo(
((File) e2).getName());
}
});
viewer.addDoubleClickListener(new IDoubleClickListener()
{
public void doubleClick(DoubleClickEvent event)
{
IStructuredSelection selection =
(IStructuredSelection) event.getSelection();
setCurrentDirectory((File) selection.getFirstElement());
}
});
setCurrentDirectory(File.listRoots()[0]);
}
private void setCurrentDirectory(File directory)
{
if (!directory.isDirectory())
throw new RuntimeException(
directory + " is not a directory!");
currentDirectory = directory;
viewer.setInput(directory);
}
String[] getSelectedFiles()
{
IStructuredSelection selection =
(IStructuredSelection) viewer.getSelection();
List fileNameList = new LinkedList();
Iterator iterator = selection.iterator();
while (iterator.hasNext())
{
File file = (File) iterator.next();
fileNameList.add(file.getAbsoluteFile().toString());
Transferring data 267
}
return (String[]) fileNameList.toArray(
new String[fileNameList.size()]);
}
void copyFiles(String[] sourceFileList)
{
for (int i = 0; i < sourceFileList.length; i++)
{
File sourceFile = new File(sourceFileList[i]);
if (sourceFile.canRead() && currentDirectory.canWrite())
{
File destFile =
new File(currentDirectory, sourceFile.getName());
if (!destFile.exists())
{
FileOutputStream out;
FileInputStream in;
try
{
out = new FileOutputStream(destFile);
in = new FileInputStream(sourceFile);
byte[] buffer = new byte[1024];
while ((in.read(buffer)) != -1)
{
out.write(buffer);
}
out.flush();
out.close();
in.close();
viewer.refresh();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
}
else
{
System.out.println(
destFile + " already exists, refusing to clobber");
}
}
else
{
System.out.println(
"Sorry, either your source file is not readable " +
268 CHAPTER 12
Advanced features
"or the target directory is not writable");
}
}
}
}
To run this code, add the following lines to WidgetWindow:
TabItem ch12Files = new TabItem(tf, SWT.NONE);
ch12Files.setText("Chapter 12 File Broswer");
ch12Files.setControl(new Ch12FileBrowserComposite(tf));
12.2 Preferences
Any nontrivial application has settings the user may configure. Although the spe-
cific options that may be modified are limitless and tightly tied to the specific
application, the process of setting these options can generally be boiled down to a
few interactions such as clicking a checkbox, choosing from a list, or choosing a
target directory. JFace provides a framework to simplify storing a user’s prefer-
ences, retrieving them, and presenting them to the user to be modified.
Like most areas of JFace, the preference framework is divided into a series of
interfaces, each of which has a default implementation. You’re free to use the pro-
vided concrete classes, or you may implement your own from scratch to meet your
specific needs. We’ll consider each interface, followed by the implementation
provided by JFace.
The preferences framework is an extension of the JFace dialog framework.
Only the IPreferencePage interface extends the interfaces from the dialogs pack-
age, but the assumption is that preferences will be displayed in a modal dialog. It’s
possible to change this behavior if you need to by writing your own implementa-
tion of IPreferencePageContainer, which we’ll discuss later in the chapter.
12.2.1 Preference pages
Preferences are generally grouped into related sets, rather than strewn about ran-
domly, in order to make it easier for a user to find the specific option he is looking
for. In JFace, these sets are assigned to separate preference pages, which are dis-
played to the user one at a time. It isn’t necessary to split up your settings, espe-
cially if there aren’t many, but you must have at least one page.
Preferences 269
IPreferencePage
The IPreferencePage interface extends IDialogPage. In addition to the IDialog-
Page methods we discussed in chapter 11, seven new methods are defined (see
table 12.3).
PreferencePage
The abstract class PreferencePage forms the basis of all implementations of
IPreferencePage provided by JFace. Extending from DialogPage, PreferencePage
provides much of the support needed to display preferences in a dialog, including
a title and an optional image.
If you’re subclassing PreferencePage directly, you must implement the abstract
createControl() method to instantiate the controls necessary for the page. Again,
this is the same as any other DialogPage. Two buttons, Apply and Defaults, are
automatically added to the parent composite of your control unless the noDe-
faultAndApplyButton() method is called before the control is created. Typically
this will be done in the constructor of your subclass if necessary.
By default, PreferencePage returns true for okToLeave() whenever isValid()
returns true. Unless you change the validity of the page using setValid(), a
PreferencePage will always consider itself to be valid. This also means that a user
will be allowed to flip pages or close the dialog at any time.
Table 12.3 Methods defined by the IPreferencePage interface
Method Description
setContainer() Associates an instance of IPreferencePageContainer with the
page.
computeSize(), setSize() Deal with the size of the control as it appears on screen. These meth-
ods are passed and return an instance of org.eclipse.swt.graph-
ics.Point. Instead of representing an (x,y) coordinate, the fields of
this Point object should be interpreted as the width and height,
respectively, of the control.
okToLeave() Called when the use wishes to flip to another page. Returning false
prevents the user from leaving the page.
isValid() Indicates whether the page is currently valid. Exactly what “valid”
means is subjective, but it’s generally an indicator of whether it’s pos-
sible to leave the page or close the dialog in the current state.
performOk(),
performCancel()
Indicate that the OK or Cancel button has been clicked, respectively.
Any processing relevant to these events should be performed in these
methods, both of which return a boolean indicating whether the event
should be allowed to happen.
270 CHAPTER 12
Advanced features
The performOk(), performCancel(), performApply(), and performDefaults()
methods may all be overridden to react to the occurrence of the appropriate
event. By default, these methods do nothing, so you need to override them if you
wish your page to do anything useful.
FieldEditorPreferencePage
The only subclass of PreferencePage provided by JFace, and the only one you’ll
need for the majority of cases, is FieldEditorPreferencePage. FieldEditorPref-
erencePage assumes that your preferences consist of a number of discrete fields
that can be modified independently. The FieldEditorPreferencePage is meant to
make it easy to collect all the FieldEditors necessary to edit the preferences for
the page. As such, it implements and overrides all the methods from Preference-
Page discussed in the previous section. Typically, you’re left with only one method
that you must implement.
createFieldEditors() is called once the page is ready to lay out the editors.
All the method does is add the editors to be displayed using addField(). Editors
are then laid out on the displayed control in the order in which they were added.
FieldEditorPreferencePage exposes only a few public methods beyond those
present in PreferencePage, and clients generally have little need to call them.
12.2.2 Field editors
A field editor is responsible for displaying and editing a single preference value.
The editor can range from displaying a text field and allowing the user to type, to
opening a complex dialog and allowing the user to select a valid value. JFace
includes nine concrete FieldEditor subclasses, which we’ll discuss. These should
cover most of your needs.
You must follow a few steps if you need to define your own FieldEditor subclass:
1 Think about the basic controls you’ll need in order for your editor to function.
Implement getNumberOfControls() to return the number of controls you’ll
be using. FieldEditor uses this value to figure out how to lay out your control.
2 In its implementation of createControl(), FieldEditor calls the abstract
doFillIntoGrid() method. This should be implemented to instantiate
your controls and add them to the Composite that’s passed to the method.
3 If your editor includes a label, FieldEditor includes built-in support for
storing the label text and the label control. You should use getLabelCon-
trol(Composite parent) in this case, rather than creating your own Label.
Preferences 271
4 Implement the doLoad(), doLoadDefault(), and doStore() methods to
load values from and persist them to the PreferenceStore associated with
your editor. This store can be retrieved by using the getPreference-
Store() method, which may return null if no persistent store has been
configured for the editor.
In addition to implementing all the abstract methods, you can fire events when
your editor’s properties change. FieldEditor provides a fireValueChanged()
method, which takes a property name, the old value, and the new value and auto-
matically invokes any registered PropertyChangeListener. This isn’t necessary if
your control doesn’t have any properties that are interesting to outside listeners—
most of the FieldEditor subclasses included in JFace don’t bother to fire these
events, but the support is there if you need it.
Whether you’re implementing a completely new editor or using a built-in one,
it can be useful to add validation to your FieldEditor. You do so by overriding
both the isValid() and refreshValidState() methods. By default, isValid()
always returns true, and refreshValidState() does nothing. isValid() is simple:
It returns true or false according to whether your editor currently contains a value
that is valid to save. refreshValidState() is slightly more complicated. This
method should query isValid() and, if the value has changed, fire a value-
changed event for the property FieldEditor.IS_VALID. refreshValidState() is
invoked at various times by the FieldEditor framework, particularly after loading
and before attempting to save values.
Implementing your own FieldEditor may sound complicated, but you
shouldn’t need to do this very often. JFace provides nine types of FieldEditor (see
table 12.4), and most of the time you should be able to use or subclass one of them.
Table 12.4 Field editors provided by JFace
Editor class Description
BooleanFieldEditor Displays its preference as checkboxes, which are checked to indicate
true or unchecked to indicate false. By default, the checkbox appears
to the left of any supplied label, but using the style BooleanFieldEd-
itor.SEPARATE_LABEL creates the label on the left and the checkbox
on the right.
ColorFieldEditor Lets the user choose a color. A button is displayed; when it’s clicked,
another dialog is opened, allowing the user to see the available colors
and choose one by pointing with the mouse. The chosen color is saved
as an org.eclipse.swt.graphics.RGB value.
continued on next page
272 CHAPTER 12
Advanced features
DirectoryFieldEditor Lets the user choose any directory on the filesystem. A text field dis-
plays the current chosen directory. This value may be modified in place,
or the displayed Browse button lets the user navigate the filesystem
and choose a directory graphically.
FileFieldEditor Lets the user choose a filename and location. You can filter the types
of files displayed when browsing the filesystem by using the setFile-
Extensions() method, which takes an array of Strings. Files must
match one of the extensions in this array, or they won’t be displayed.
FontFieldEditor Lets the user choose a font, including size and bold or italic
attributes. Clicking the Change button opens a dialog presenting all the
available font options. Text demonstrating the chosen font is displayed;
you can set the string to use for this text in FontFieldEditor's con-
structor.
The value for this editor is returned as an org.eclipse.swt.graph-
ics.FontData object.
IntegerFieldEditor Ensures that any entered value is an integer. You can force the entered
value to be in a certain range by using the setValidRange() method.
PathEditor Lets the user choose multiple directory paths. The currently selected
paths are displayed in a list on the left; buttons to add, remove, or
change the order of the paths are on the right.
RadioGroupFieldEditor Presents a set of mutually exclusive options, forcing the user to pick
exactly one of them. Labels for the available options are specified in
the constructor, along with the value to return if each one is selected.
These are passed as a two-dimensional array of Strings, as shown
here:
RadioGroupFieldEditor editor = new RadioGroupFieldEditor(
/*some other parameters*/,
new String[][] {
{"Option One", "Value1"},
{"Option Two", "Value2"} },
/*more parameters*/ );
StringFieldEditor Provides the user with a text field to enter a string of characters. This
editor supports two options for validating the entered text:
VALIDATE_ON_FOCUS_LOST and VALIDATE_ON_KEY_STROKE; you can
toggle between them using setValidateStrategy(). By default,
StringFieldEditor accepts any string as valid. To add your own vali-
dation, override the protected doCheckState() method.
To limit the length of the entered text, use the setTextLimit()
method.
Table 12.4 Field editors provided by JFace (continued)
Editor class Description
Preferences 273
12.2.3 Preference page containers
Just as wizard pages are hosted by a wizard container, preference pages are dis-
played by a preference page container.
IPreferencePageContainer
The IPreferencePageContainer interface must be implemented by any class that
wishes to host preference pages. The interface is straightforward; it has only four
methods (see table 12.5).
Although it’s easy to implement IPreferencePageContainer if you need to, doing
so generally isn’t necessary. Preference pages are typically displayed in a dialog,
and PreferencePageDialog provides a default implementation that handles this
case well.
IPreferencePageNode
Whereas in a wizard dialog pages are typically displayed in a set order, preference
pages may be filled out in any sequence the user desires. It would be unfriendly to
force a user to click through several pages of options that she isn’t interested in,
just to modify one setting. However, avoiding this scenario necessitates a way to
display a list of the pages to the user. A preference node fills this role.
A preference node combines a preference page with a unique ID and an
optional title and image. The title and image are displayed to the user in a tree on
the left side of a dialog; when one of them is clicked, the corresponding page is
displayed on the right. This way, users can quickly navigate to the group of set-
tings they’re interested in. IPreferenceNode also adds support for making one
node a subnode of another with the add() method; in this case, the children are
shown when the parent is expanded in the tree. PreferenceNode provides a
default implementation of IPreferenceNode, and you’ll rarely need to implement
the interface yourself.
Table 12.5 Methods defined by the IPreferencePageContainer interface
Method Description
getPreferenceStore() Used by preference pages to retrieve a persistent
store for their values
updateButtons(), updateMessage(),
updateTitle()
Let pages request that the container update its dis-
play to match the currently active page
274 CHAPTER 12
Advanced features
Most of the methods on PreferenceNode are used by the framework. You can
set a title and image when instantiating PreferenceNode. Typically the only other
methods you’ll ever need to call on it are add() and remove(), to manage the chil-
dren associated with a given node.
PreferenceManager
PreferenceManager is a utility class that JFace uses to organize preference nodes. It
introduces the concept of a path, which is used to identify nodes in the hierarchy.
A path consists of a string made up of the IDs of one or more nodes, divided by a
separator character. By default, the separator is a period (.), but you can change
it by passing any other character to PreferenceManager’s constructor. The string is
tokenized on the separator character, and each ID is used to search starting from
the root, then the children of the first node found, then the next node’s children,
and so on, until the final node in the path has been found. You can add nodes at
the root or as a child of any node currently in the structure, identified by its path.
PreferencePageDialog
PreferencePageDialog is JFace’s implementation of IPreferencePageContainer. It
extends Dialog and adds support for displaying preference pages. The pages avail-
able are displayed in a tree on the left, and the currently active page is displayed
in the main area of the dialog. Once you have instantiated the dialog with an
instance of PreferenceManager and associated a persistent store using setPrefer-
enceStore(), you can call open(); PreferencePageDialog takes care of the rest.
12.2.4 Persistent preferences
Preferences aren’t very useful if they must be reset each time an application is
launched. JFace provides a way to make your preferences persistent using the
IPreferenceStore.
IPreferenceStore
An IPreferenceStore maps preference names to values. Each named preference
may have both a default value and a current value; if there is no current value, the
default is returned. Preferences may be any of Java’s primitive types (see also the
discussion of PreferenceConverter for an easy way to store certain JFace objects in
an IPreferenceStore). Each get and set method defined in this interface takes
the name of the preference to operate on. Additionally, there are methods to set
the default value for a given preference or reset a preference to the default, and a
Preferences 275
dirty indicator to check whether the store has been changed. A subinterface,
IPersistentPreferenceStore, adds a save() method to persist the values.
PreferenceStore
JFace includes PreferenceStore, an implementation of IPreferenceStore that’s
based on the java.util.Properties class. PreferenceStore only saves properties
that aren’t equal to the default value, thereby minimizing the amount of data that
must be written to disk. Values are persisted using the standard properties file for-
mat (name-value pairs separated by =). You have two options for loading and sav-
ing your data when using PreferenceStore. The simplest way is to specify a
filename when instantiating a new instance:
PreferenceStore store = new PreferenceStore( "some_file_name" );
store.load();
Alternatively, you can give the store a stream to use when loading or saving:
PreferenceStore store = new PreferenceStore();
FileInputStream in = new FileInputStream( "some_file_name" );
store.load( in );
...
FileOutputStream out = new FileOutputStream( "some_file_name" );
store.save( out, "Custom Header" );
You must also remember to explicitly call load() before passing your Prefer-
enceStore to a PreferenceDialog, because the dialog won’t call the method on
your behalf. It automatically calls save() when appropriate, however.
Note that calling the no-argument load() or save() method when no filename
is specified in the PreferenceStore constructor results in an IOException. Because
PreferenceDialog calls the no-argument method, you should always use the con-
structor that takes a filename; use the overloaded versions of load() and save()
only if you need to copy the values to a backup stream.
PreferenceConverter
PreferenceConverter is another utility provided by JFace. It consists of a series of
static methods used to set or retrieve common SWT objects that otherwise
couldn’t be used with an IPreferenceStore. Behind the scenes, PreferenceCon-
verter serializes the object to or from a string format suitable for long-term stor-
age. Values are set and retrieved like so:
276 CHAPTER 12
Advanced features
IPreferenceStore store = ...
PreferenceConverter.setValue( store,
"color_pref",
new RGB(0, 255, 0) );
...
RGB color = PreferenceConverter.getColor( store,
"color_pref" );
12.3 Label decorators
In our earlier discussion of ILabelProvider, we mentioned that there is an alter-
nate implementation of IBaseLabelProvider. That implementation is in ILabel-
Decorator, an interface designed to collaborate with basic label providers to
provide additional information.
Label decorators are intended to “decorate” a given object’s presentation with
visual cues as to the object’s current state. A good example can be found in the
Package Explorer in Eclipse. The Package Explorer displays all the Java classes in
the current project in a tree, organized by the package to which each belongs. A
label provider displays each object’s name along with an icon designating the
object as either a class or package. Label decorations are added on top of the stan-
dard icons to designate abnormal conditions, such as the small red X that appears
when there is a compilation error.
The main advantage of this design is the way it encourages decoupling. Con-
tinuing the Eclipse example, the standard label provider for a Java class only
needs to know how to retrieve the name of a class and draw the basic icon. The
logic to overlay the error icon (or warning icon, or any other variable status) is
separated out into the decorator, where it can also be applied to packages or any
other appropriate type of object. Likewise, because the Java class label provider
isn’t encumbered with code to display the status icons, it can easily be reused in
another context where the status icons aren’t desired.
12.3.1 ILabelDecorator
The main interface you’ll use to implement decorator functionality is ILabelDec-
orator. ILabelDecorator extends IBaseLabelProvider and is similar to ILabel-
Provider. Two methods are defined: decorateText() and decorateImage(). Each
is passed a domain object, along with the text or image that’s currently being dis-
played. Each method returns the new text or image that should be displayed for
the given domain object.
When you’re implementing decorateImage(), keep in mind that each Image con-
sumes relatively rare system resources. It’s therefore important to avoid creating
Label decorators 277
new Images if possible. Using the ImageRegistry, as we do in the example later in
the chapter, is helpful to avoid instantiating unnecessary Image instances. Best prac-
tices for using Images are discussed further in chapter 7.
12.3.2 DecoratingLabelProvider
Once you’ve implemented the decorator, we need to make sure it gets a shot at per-
forming its decorations. Rather than provide methods to explicitly add decorators
to viewers, JFace supplies the DecoratingLabelProvider class. DecoratingLabel-
Provider extends LabelProvider and thereby implements ILabelProvider. Instead
of providing labels itself, DecoratingLabelProvider takes an instance of ILabelPro-
vider and an ILabelDecorator in its constructor. Calls to getText() or getImage()
are delegated first to the label provider and then to the label decorator. The Dec-
oratingLabelProvider is then associated with the viewer, instead of calling setLa-
belProvider() with the ILabelProvider directly.
Because DecoratingLabelProvider is an instance of ILabelProvider, you can
easily chain decorators together by passing appropriate instances of Decorat-
ingLabelProvider in the constructor instead of LabelProviders. Each decorator is
then called in turn to build the final result. This technique is shown here:
DecoratingLabelProvider firstDecorator =
new DecoratingLabelProvider( new MyLabelProvider(),
new FirstLabelDecorator() );
DecoratingLabelProvider secondDecorator =
new DecoratingLabelProvider( firstDecorator,
new SecondLabelDecorator() );
viewer.setLabelProvider(secondDecorator);
12.3.3 An example
We’ll now show an example of the decorator concepts we’ve discussed as they’re
used to build a tree showing the relationships between family members. Each per-
son will be decorated with their family name and an icon indicating whether they
are male or female. The infrastructure for this example is similar to the TreeView-
ers we’ve discussed earlier. In the interest of conserving space, we won’t repro-
duce the entire example; instead, we’ll discussing only the sections that are
relevant for label decorators.
The first step is to create the TreeNode class that represents each node in the
tree. The member variables and constructor look like this:
public class TreeNode
{
private String firstName;
278 CHAPTER 12
Advanced features
private boolean isMale = false;
private String familyName;
private List children = new ArrayList();
private TreeNode parent;
public TreeNode(String firstName,
String familyName,
boolean male)
{
this.firstName = firstName;
this.familyName = familyName;
isMale = male;
}
//accessor methods
...
}
Each of the attributes has an accessor, so that our decorator will be able to query
the TreeNode for the data it needs.
Our implementation of ILabelDecorator is straightforward. Here we extend
LabelProvider for the convenient implementations of the methods defined in
IBaseLabelProvider:
public class FamilyDecorator
extends LabelProvider
implements ILabelDecorator
{
private static final String MALE_IMAGE_KEY = "male";
private static final String FEMALE_IMAGE_KEY = "female";
private ImageRegistry imageRegistry;
public FamilyDecorator(Shell s)
{
imageRegistry = new ImageRegistry(s.getDisplay());
Image maleImage = new Image(s.getDisplay(), "male.gif");
Image femaleImage = new Image(s.getDisplay(), "female.gif");
imageRegistry.put(FEMALE_IMAGE_KEY, femaleImage);
imageRegistry.put(MALE_IMAGE_KEY, maleImage);
}
public Image decorateImage(Image image, Object element)
{
if(element == null) return null;
TreeNode node = (TreeNode)element;
if(node.isMale())
{
return imageRegistry.get(MALE_IMAGE_KEY);
}
else
Label decorators 279
{
return imageRegistry.get(FEMALE_IMAGE_KEY);
}
}
public String decorateText(String text, Object element)
{
if(element == null) return null;
TreeNode node = (TreeNode)element;
return text + " [" + node.getFamilyName() + "]";
}
}
The constructor creates the Images we need and saves them in an ImageRegistry
for future use. When decorateImage() is called, it checks the isMale() method of
the TreeNode object and retrieves the appropriate image by name from the regis-
try; this is then returned as the Image to display. (Note that this section has been
simplified; in a real application, you’ll typically need to draw your decoration on
top of another image and return the combined result.)
decorateText() is also straightforward. Each node’s family name is retrieved
and appended to whatever text is already being displayed, and the result is
returned as the text to display.
Finally, we create a DecoratingLabelProvider with an instance of our decorator
and tell the viewer to use the new instance instead of the default label provider:
...
viewer.setLabelProvider(
new DecoratingLabelProvider(
(ILabelProvider)viewer.getLabelProvider(),
new FamilyDecorator(getShell())));
...
Note that here we retrieve the viewer’s default
label provider and pass it as the base for the
DecoratingLabelProvider to use. In your own
applications, this code may frequently be
replaced with an instance of a custom label pro-
vider.
Running the demo results in a tree such as
the one shown in figure 12.2.
The default label provider only added the
text for each character’s first name by calling
Figure 12.2
A decorated TreeViewer
280 CHAPTER 12
Advanced features
toString() on each node. The icons and family names were added after the fact
by our label decorator.
NOTE Using label decorators in Eclipse—When you’re using label decorators in an
Eclipse plug-in, you must be aware of some additional gotchas, such as
making sure you don’t accidentally clobber the built-in decorators. Ad-
ditional features are also available to you, such as configuring your dec-
orators in the plugin.xml file. A detailed discussion of these issues is
outside of the scope of this book; but the excellent article “Understand-
ing Decorators in Eclipse” by Balaji Krish-Sampath, available online at
www.eclipse.org/articles/Article-Decorators/decorators.html, will prove
invaluable if you’re working with decorators in Eclipse.
12.4 The Browser widget
With the rise of the World Wide Web, HTML has become one of the most impor-
tant technologies for creating a user interface. It has the advantage of being sim-
ple to write, easy to understand, and quick to modify in order to try out different
designs. When you’re developing an application using a thick-client technology
such as SWT or Swing, it’s common to find yourself becoming envious of the quick
development cycles afforded by an HTML-based interface. When you consider the
vast amount of information that exists in HTML, sometimes it makes sense to
design your application to be able to display HTML documents.
Thankfully, in the 3.0 release the SWT team has provided the Browser widget to
make this easy to do. By using Browser, you can embed the user’s web browser in
your application and use it to display HTML without having to write a custom ren-
dering engine. Additionally, because Browser uses the full-fledged native web
browser for your platform, you gain the ability to handle JavaScript, XML, and any
other format already understood by the browser.
Before we dive too deeply into our discussion of the Browser widget, a couple
of caveats are in order:
■ Browser isn’t currently supported on all platforms. It works on Microsoft
Windows without a problem, but using it on Linux requires Mozilla 1.5.
OS X and other platforms don’t support Browser at all; if you try to instanti-
ate it, the result is an SWTError. This code is under active development, how-
ever, so if you’re considering using Browser you should check the status
under all platforms you plan to support.
■ As of the time of this writing, the API for Browser is considered unstable. It
will be finalized by the time the final version of SWT 3.0 is released, but it’s
The Browser widget 281
possible that it will be different from the code samples we discuss here. In
this case, you should consult the Javadocs for the version of the widget in
your distribution to learn the differences.
The API for Browser is simple. It consists of methods to load the document found
at a URL, to navigate backward and forward between pages, to refresh the current
URL, and to stop the loading of the current page. Additionally, Browser broad-
casts several unique events. At the current time, these events include opening,
closing, and hiding windows; changing locations; and indicating progress as a
page is loaded.
Using the Browser widget may also require additional native libraries, depend-
ing on your platform. There are no additional dependencies for Windows, but
using Browser in the Linux/GTK distribution of SWT requires the libswt-mozilla-
gtk library to be included in your LD_LIBRARY_PATH. On other supported plat-
forms, you should check for the existence of a native library that includes the
name of your platform’s web browser.
We next provide a simple example of Browser in action. The code in
listing 12.5 opens a browser window when you run it. A text box allows the user to
type a URL, and when the Open button in the WidgetWindow is clicked, the corre-
sponding location is opened in the browser. Forward and Back buttons let the
user control navigation in the browser from within WidgetViewer. Running the
example results in the screenshot shown in figure 12.3.
Figure 12.3
Mozilla embedded in
an SWT application
282 CHAPTER 12
Advanced features
package com.swtjface.Ch12;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.*;
public class Ch12WebBrowserComposite extends Composite
{
private Browser browser;
public Ch12WebBrowserComposite(Composite parent)
{
super(parent, SWT.NONE);
GridLayout layout = new GridLayout(2, true);
setLayout(layout);
browser = new Browser(this, SWT.NONE);
GridData layoutData = new GridData(GridData.FILL_BOTH);
layoutData.horizontalSpan = 2;
layoutData.verticalSpan = 2;
browser.setLayoutData(layoutData);
browser.setUrl("http://www.manning.com/catalog/view.php?book=scarpino");
final Text text = new Text(this, SWT.SINGLE);
layoutData = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(layoutData);
Button openButton = new Button(this, SWT.PUSH);
openButton.setText("Open");
openButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e)
{
browser.setUrl(text.getText());
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
Button backButton = new Button(this, SWT.PUSH);
backButton.setText("Back");
backButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e)
{
browser.back();
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
Listing 12.5 Ch12WebBrowserComposite.java
b Create Browser instance
c Open URL
d Forward and Back buttons
Summary 283
Button forwardButton = new Button(this, SWT.PUSH);
forwardButton.setText("Forward");
forwardButton.addSelectionListener(new SelectionListener() {
public void widgetSelected(SelectionEvent e)
{
browser.forward();
}
public void widgetDefaultSelected(SelectionEvent e) {}
});
}
}
Browser is instantiated like any other control, with a parent Composite and a style
parameter. Currently, Browser doesn’t support any styles.
Any valid URL can be opened by passing it to the setUrl() method. This will clear
whatever page is currently loaded in the browser.
The browser can be told to move forward and back through its history by calling
the appropriate method.
If you’re on a supported platform, you can run this example by adding these lines
to WidgetWindow:
TabItem ch12WebBrowser = new TabItem(tf, SWT.NONE);
ch12WebBrowser.setText("Chapter 12 Web Browser");
ch12WebBrowser.setControl(new Ch12WebBrowserComposite(tf));
12.5 Summary
We’ve covered several important topics in this chapter, and the volume of infor-
mation can seem overwhelming. Don’t worry about mastering it all at first glance;
many of the concepts we’ve discussed aren’t necessary for day-to-day program-
ming with SWT and JFace. The important thing is to be aware of the capabilities
that are present, so that when you find yourself needing to implement drag and
drop or user preferences, you’ll know where to turn.
You should also keep in mind that SWT is under constant development.
Although at the time we’re writing this, widgets such as Browser aren’t fully sup-
ported on all platforms, the situation may have changed by the time you write
your own SWT application. Check the articles available at www.eclipse.org to see
what enhancements have been made since this book went to press.
d Forward and Back buttons
b
c
d
284
Looking beyond SWT/JFace:
the Rich Client Platform
This chapter covers
■ The theory behind the Rich Client Platform (RCP)
■ The classes that make RCP operation possible
■ The Eclipse Forms toolset
■ Building an example RCP application
Understanding RCP workbenches 285
So far, we’ve discussed how SWT serves as a general-purpose toolset for building
GUI applications. We’ve also shown how JFace provides more specialized capabili-
ties (Actions, Contributions, and Viewers) like those in the Eclipse platform.
These aspects of JFace simplify the development process, as long as your GUI’s
operation resembles that of the Eclipse Workbench.
To conclude this book, we’d like to take this progression one step further.
Instead of just using behavioral aspects of the Workbench, we’ll now explore
building complete, custom applications that look and function like Eclipse. We’ll
call them (lowercase) workbenches. Like JFace GUIs, they provide a great deal of
functionality but remain simple to code.
This exciting capability is made possible by Eclipse’s new Rich Client Platform
(RCP). With RCP, not only can you create workbenches quickly, but you can also
compile them into standalone applications. So, you won’t need the entire Eclipse
platform to run your GUIs.
In this chapter, we’ll explain the underlying structure of RCP and progress
through the stages of building a complete, standalone application. To make this
even more interesting, we’ll create this application using structures from Eclipse
Forms. Eclipse Forms is more than a new package or plug-in: It’s a complete tool-
kit for building powerful form-based applications.
Before you start coding, you need to understand how workbenches are
structured.
13.1 Understanding RCP workbenches
We’ll start our discussion by describing the building blocks that make up an RCP
application. Figure 13.1 presents our favorite workbench—the Eclipse Work-
bench—with labels for its individual sections.
In previous chapters, we’ve discussed the title, menu, toolbar, and status line,
and how to configure them inside user interfaces. A workbench is distinguished
from these other GUIs by its editors and views. We’ll discuss these now, along with
the perspective that controls their placement.
13.1.1 Entering data with editors
Essentially, a workbench consists of an editor and a series of views that support the
editing process. The Eclipse Workbench centers on a text editor whose view panes
let you alter or examine the editor’s environment. But in your RCP workbenches,
you have many options beyond regular text editing. Figure 13.2 shows the full
class hierarchy for workbench editors.
286 CHAPTER 13
Looking beyond SWT/JFace
Your editor doesn’t need to be text-based or even single-paged. But it must be a
subclass of EditorPart. This class contains the methods that communicate with
the workbench.
At the far left of figure 13.2, the GraphicalEditor creates diagrams based on
shapes and connections between them. (This is an involved topic and is the focus
of appendix D.) In the center, the TextEditor and its superclasses contain only
text. The MultiEditor contains a set of editors whose content can be communi-
cated between them.
The MultiPageEditorPart is similar to the MultiEditor except that it holds a
series of Controls that may or may not function as editors. Their only requirement
is that they extend the Control class. The FormEditor is a particularly interesting
and useful subclass of this editor; it creates a series of forms (FormPages) based on
the content of a main editor.
You can build TextEditors and MultiPageEditorParts quickly by starting a Java
plug-in project and selecting one of the editor-based templates. But if you want to
create a FormEditor, you have to start from scratch.
Figure 13.1 The structural elements of a workbench
Understanding RCP workbenches 287
13.1.2 Displaying information with views
Although a workbench’s focal point is its editor, views are needed to organize the
editor’s content, examine its environment, and display its results. For example,
the Eclipse Workbench contains views for navigating packages and directories,
keeping track of tasks and errors, and displaying console output from the Java
runtime. More than anything else, it’s these views that have made Eclipse so popu-
lar as a development platform. Without them, it would be just a text editor with
ties to the Java SDK.
It’s simple to create views, particularly if you want panes that function like those
in Eclipse. Figure 13.3 shows these different view types as ViewPart subclasses.
You can see what many of these classes look like by choosing the Window entry
in the Eclipse menu and selecting Show View. The BookmarkNavigator looks like a
specialized property view, and the ResourceNavigator view looks like the directory
navigator that appears on the left-hand side of the Eclipse Workbench. The
TaskList takes the same form as the corresponding window at the bottom of
Eclipse. The PageBookView and its subclasses represent views with multiple pages.
You can also create views that look and behave completely differently than
those in Eclipse. The ViewPart class is easy to extend; we’ll create a complete view
class as we progress through our RCP example.
Now that we’ve looked at the editors and views available, let’s examine how these
parts are integrated into the workbench. This capability is provided by perspectives.
EditorPart
GraphicalEditor FormPage
AbstractText
Editor MultiEditor
MultiPage
EditorPart
GraphicalEditor
withPalette
StatusText
Editor FormEditor
AbstractDecorated
TextEditor
TextEditor
Figure 13.2 The EditorPart and its subclasses
288 CHAPTER 13
Looking beyond SWT/JFace
13.1.3 Combining editors and views with perspectives
Just as SWT Composites use Layouts to arrange child components, workbenches
select and organize editors and views with perspectives. For example, the Eclipse
platform displays one set of editors and views in the Java perspective and another
set when you choose the Debug perspective.
Although the majority of the work involved in RCP development deals with
building and arranging editors and views, you also need to create a set of classes
that provides the workbench’s basic functionality. Next, we’ll present these classes
in the framework of building an RCP project.
13.2 RCP: Looking under the hood
The ability to create workbench editors and views isn’t new. These classes have
been around since Eclipse 2.1 and haven’t changed significantly since the previ-
ous version. What makes the RCP so different is that, with very few classes, you can
now create an entirely new, standalone application with these windows. In this sec-
tion, we’ll begin RCP development by creating an Eclipse project. Then, we’ll cre-
ate the three classes that make RCP operation possible.
13.2.1 Creating and configuring an RCP project
RCP development starts by creating an Eclipse plug-in project, but it’s important
to understand that the end result is not a plug-in. The ultimate goal is to build an
application that functions independently from the Eclipse Workbench.
To make this point clear, we need to go into greater technical depth. The dif-
ference between a plug-in and an RCP application centers around a small kernel
ViewPart
Bookmark
Navigator
Rescue
Navigator PageBookView TaskList
Content
Online
Abstract
DebugView
Property
Sheet
Figure 13.3 The ViewPart and its subclasses
RCP: Looking under the hood 289
called the platform runtime. This is the first element of Eclipse to execute, and it
functions by organizing plug-ins and controlling their operation. Unlike a plug-
in, a workbench contains its own platform runtime, which means that it controls
its own operation. You can execute a workbench like a regular Java application.
But even though a workbench operates differently than a plug-in, the process
of creating one requires that you build a plug-in project. Let’s get started.
NOTE This chapter describes the process of building of a plug-in project, but
doesn’t provide the overall theory behind Eclipse plug-ins. For more in-
formation on the subject, we recommend Eclipse in Action by David Gallar-
do, Ed Burnette, and Rob McGovern (Manning, 2003).
Creating and configuring the RCPExample project
To begin, open Eclipse, select File->New->Plug-in Project, and click Next. Enter
the name com.swtjface.RCPExample. Click Next to reach the Plug-in Content
screen, and click Finish to create the project.
You don’t need to modify the RCPExamplePlugin class that the wizard created,
but the project’s plugin.xml file must be updated to reflect the project’s configu-
ration. You can use the Plug-in Manifest Editor or change the file directly. Either
way, listing 13.1 uses boldface to show the alterations you’ll need to make.
Listing 13.1 plugin.xml
290 CHAPTER 13
Looking beyond SWT/JFace
13.2.2 Building the application class
The first extension in plugin.xml extends from org.eclipse.core.run-
time.applications. This point makes it possible for workbenches to operate with-
out Eclipse. Our example uses this extension to create a class called
ExampleApplication. This class functions like the main() method of a regular Java
application—it tells the runtime environment where it should begin processing.
Application classes need to implement the IPlatformRunnable interface in the
org.eclipse.core.runtime package. This interface requires only one method,
run(), which—like main()—may contain arguments that control the workbench’s
processing. In building an application class, you need to make sure that run()
performs the application’s top-level tasks. At the very least, it needs to create a
Display object for the workbench and start the application’s life cycle by invoking
methods from PlatformUI.
Listing 13.2 shows the code for ExampleApplication; we recommend that you
add it to the com.swtjface.RCPExample package. It won’t compile yet, but the
error will resolve once you add the ExampleAdvisor class.
Tells
workbench
how to
function as
application
Matches view class
with its identification
information
Tells
application
what class will
arrange its
windows
RCP: Looking under the hood 291
package com.swtjface.RCPExample;
import org.eclipse.core.runtime.IPlatformRunnable;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.application.WorkbenchAdvisor;
public class ExampleApplication implements IPlatformRunnable
{
public Object run(Object args) throws Exception
{
WorkbenchAdvisor advisor = new ExampleAdvisor ();
Display display = PlatformUI.createDisplay();
int code = PlatformUI.createAndRunWorkbench(display, advisor);
if (code == PlatformUI.RETURN_RESTART)
return IPlatformRunnable.EXIT_RESTART;
else
return IPlatformRunnable.EXIT_OK;
}
}
This application limits itself to the essentials—configuring a WorkbenchAdvisor,
creating a Display, and starting the application. The createAndRunWorkbench()
method continues functioning until you close the workbench. At that point, it
returns a value that either restarts or exits the application. Beyond the methods
shown here, the PlatformUI class also provides methods for obtaining IWorkbench
and IPreferenceStore interfaces and lets you use isWorkbenchRunning() to check
whether the workbench is running.
You might wonder how this small amount of code ties in with the editors,
views, menus, and toolbars inside a workbench. This connection is provided by a
very important class called WorkbenchAdvisor.
13.2.3 Adding a WorkbenchAdvisor
The WorkbenchAdvisor class is one of the RCP’s main innovations. Despite its
name, it performs a great deal of the work. This class concentrates the functions
of controlling the workbench’s operation and setting features of its appearance.
To see how this works, let’s examine the WorkbenchAdvisor class and the IWork-
benchWindowConfigurer interface that it accesses.
Listing 13.2 ExampleApplication.java
Associate
WorkbenchAdvisor
object with
application
Create Display object
for workbench
Start
application
292 CHAPTER 13
Looking beyond SWT/JFace
Controlling workbench operation with WorkbenchAdvisor methods
The WorkbenchAdvisor’s methods let you perform processing tasks before each
stage of your application’s life cycle. For example, if you want to disable a feature
during startup, you can do this in the preStartup() method. You can enable the
feature afterward with postStartup(). The preWindowOpen() method is particu-
larly important since it gives you a chance to configure the window’s appearance
before it’s displayed in the workbench.
In addition to the life-cycle methods, the WorkbenchAdvisor also contains
methods that let you configure aspects of the workbench. In our example, we’ll
invoke getInitialWindowPerspectiveId() to provide the ID of the perspective
that we’ll use. As you saw in plugin.xml, this is com.swtjface.RCPExample.Exam-
plePerspective.
Listing 13.3 shows how the WorkbenchAdvisor controls processing just before
the window opens and how it lets you specify the workbench’s perspective. We rec-
ommend that you add this class to the com.swtjface.RCPExample package.
package com.swtjface.RCPExample;
import org.eclipse.ui.application.WorkbenchAdvisor;
import org.eclipse.swt.graphics.Point;
import org.eclipse.ui.application.IWorkbenchWindowConfigurer;
public class ExampleAdvisor extends WorkbenchAdvisor
{
public String getInitialWindowPerspectiveId()
{
return "com.swtjface.RCPExample.ExamplePerspective";
}
public void preWindowOpen(IWorkbenchWindowConfigurer configurer)
{
super.preWindowOpen(configurer);
configurer.setTitle("RCPExample");
configurer.setInitialSize(new Point(225, 250));
configurer.setShowMenuBar(false);
configurer.setShowStatusLine(false);
configurer.setShowCoolBar(false);
}
}
The WorkbenchAdvisor methods are simple, but controlling the workbench’s
appearance is performed with the IWorkbenchWindowConfigurer interface. In our
Listing 13.3 ExampleAdvisor.java
Set workbench’s
perspective according
to its ID
Configure
workbench’s
appearance
RCP: Looking under the hood 293
example, the WorkbenchAdvisor obtains an instance of this with preWindowOpen()
and uses its methods to set application parameters. This interface allows you to
control the workbench’s appearance; let’s examine it more closely.
Configuring visuals with the IWorkbenchWindowConfigurer
Although your workbenches will necessarily look similar to Eclipse, the Rich Cli-
ent Platform provides a great deal of design flexibility with the IWorkbenchWindow-
Configurer. Our example WorkbenchAdvisor used a few of these to configure the
application’s title, size, menu bar, status line, and coolbar, but many more are
available. Table 13.1 doesn’t provide a complete account, but it lists those that
directly affect the appearance of the workbench.
Many of these methods are similar to those found in SWT and JFace containers, but
a few deserve additional attention. The first two, addEditorAreaTransfer() and
configureEditorAreaDropListener(), provide drag-and-drop capability between
editors and views, which enables you to cut and paste between windows. It’s
Table 13.1 Workbench configuration methods of the IWorkbenchWindowConfigurer
Method Function
addEditorAreaTransfer(Transfer) Provides a Transfer object for editor drag and drop
configureEditorAreaDropListener
(DropTargetListener)
Sets the DropTargetListener needed to receive
drag-and-drop events
createCoolBarControl(Composite) Specifies the control to receive CoolBar entries
createMenuBar() Creates a Menu within the workbench
createPageComposite(Composite) Sets the container for the editors and views
createStatusLineControl(Composite) Specifies the control to provide status-line information
setInitialSize(Point) Provides the workbench’s initial size
setShellStyle(int) Specifies style bits for the workbench’s Shell object
setShowCoolBar(boolean) Tells the workbench if it should display a CoolBar
setShowMenuBar(boolean) Tells the workbench if it should display a Menu
setShowPerspectiveBar(boolean) Tells the workbench if it should display a bar to select
different workbench perspectives
setShowStatusLine(boolean show) Tells the workbench if it should display a status line
setTitle(String title) Specifies a title for the workbench application
294 CHAPTER 13
Looking beyond SWT/JFace
interesting that the createXYZ(Composite) methods let you create custom GUI com-
ponents, but setXYZ(true) creates a default control provided by the application.
Now that we’ve discussed the workbench’s fundamental classes and top-level
appearance, we need to build a perspective to arrange its internal structure.
13.3 Adding views and perspectives
By default, workbenches contain editors to access, manipulate, and save file con-
tent. But the process of adding file handling to an RCP application is long and
involved. To keep our example as simple as possible, we’ll create a single view. In
this section, we’ll create the class for this view and the perspective needed to place
it inside the workbench.
NOTE If you want to see a full editor example involving file access and data per-
sistence, skip ahead to appendix D.
13.3.1 Building views
Essentially, a view is an editor without data-entry or file operations. Views provide
user interaction, but none of the user’s actions need to be saved. Further, views
activate immediately, without waiting for the user to select an appropriate file.
Rather than use a preconfigured class like ResourceNavigator, our custom
view extends from ViewPart. You need only one method to configure its appear-
ance and operation: createPartControl(Composite). The Composite argument of
this method serves as the view’s top-level container. Later, when we discuss the
child components provided by Eclipse Forms, we’ll add a series of widgets to this
parent Composite.
For now, the ExampleView class provides empty methods for createPartCon-
trol(Composite) and setFocus(). The workbench invokes this second method
when the user clicks on the view; you can add code to customize how the view
operates when it receives focus.
Our example, shown in listing 13.4, performs only the view’s default operation.
We recommend that you add this class to the com.swtjface.RCPExample package.
package com.swtjface.RCPExample;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;
public class ExampleView extends ViewPart
{
Listing 13.4 ExampleView.java
Adding views and perspectives 295
public void createPartControl(Composite parent)
{
}
public void setFocus()
{
}
}
Now that we have a basic shell for our view, we need to place it inside the work-
bench. For this, we’ll need to create a perspective.
13.3.2 Arranging workbench windows with a perspective
The plugin.xml file holds a separate extension for the perspective. This tells the
workbench what editors and views will be used and where they should be placed.
It also specifies the interface that our class will implement: IPerspectiveFactory.
By itself, the IPerspectiveFactory interface is easy to understand. It obtains an
IPageLayout object and configures this to provide the workbench’s appearance. Its
only method is createInitialLayout(IPageLayout), which makes it simple to code.
Configuring the IPageLayout is more involved. By default, the layout assumes
the presence of a single editor with no views. In our example, we need to make
the editor invisible and add our ExampleView to the IPageLayout.
Table 13.2 lists a number of IPageLayout methods that make this possible.
Other methods add folders, placeholders, and wizard shortcuts, but those in the
table are sufficient for most workbenches.
The addView() method is the most crucial method in the IPageLayout interface,
and it’s important to understand how it works. Its four arguments are as follows:
Table 13.2 Configuration methods of the IPageLayout class
Method Function
addShowViewShortcut(String) Creates a Window->Show View option in the menu
addView(String, int, float, String) Adds a view to the workbench with the given ID at the
specified position and dimensional ratio
GetEditorArea() Returns the ID of the workbench’s editor
isFixed() Returns whether the layout is changeable
setEditorAreaVisible(boolean) Specifies whether the editor will be displayed
setFixed() Specifies whether the layout is fixed in form
296 CHAPTER 13
Looking beyond SWT/JFace
■ viewID—A String (specified in plugin.xml) that identifies the view.
■ relationship—An int that specifies where the view should be placed rela-
tive to a reference. This can be IPageLayout.TOP, IPageLayout.BOTTOM,
IPageLayout.RIGHT, or IPageLayout.LEFT.
■ ratio—A float that describes what percentage of the reference should be
taken up by the view.
■ refID—A String that identifies the reference window.
An editor is automatically created in a workbench, so we’ll use that as our refer-
ence. But because we haven’t mentioned an editor in plugin.xml, we’ll use getEd-
itorArea() to obtain our refID. Further, to ensure that the view takes up the
entire workbench area, our example invokes setEditorAreaVisible(false).
Listing 13.5 presents the code for the example perspective. We recommend
that you add it to the com.swtjface.RCPExample package.
package com.swtjface.RCPExample;
import org.eclipse.ui.*;
public class ExamplePerspective implements IPerspectiveFactory
{
public void createInitialLayout(IPageLayout layout)
{
String editor = layout.getEditorArea();
layout.addView("RCPExample.ExampleView",
IPageLayout.RIGHT, 0f, editor);
layout.setEditorAreaVisible(false);
layout.setFixed(true);
}
}
Since the perspective makes the editor invisible, the relationship and ratio argu-
ments in addView() aren’t important. The view occupies the entire workbench. To
see this, you need to execute the example; but because our example is an applica-
tion (not a plug-in), we need to look into a separate process.
13.3.3 Executing an RCP application
Once we’re finished with the example, you’ll see how to compile it into a stand-
alone Java application. But if you only want to check to make sure that it works,
you can run it inside of Eclipse. This process consists of these steps:
Listing 13.5 ExamplePerspective.java
Adding views and perspectives 297
1 In the Eclipse main menu, choose the Run option under the Run menu item.
2 In the left pane, select the Run-time Workbench option, and click the
New button. A New_Configuration option appears; the window looks like
that in figure 13.4.
3 At the top, enter RCPExample as the workbench name. You can leave the
Workspace Location alone, but you need to select com.swtjface.RCPExam-
ple.ExampleApplication in the Program To Run group.
4 Click the Plug-ins tab, and select the Choose Plug-ins And Fragments To
Launch From The List radio button. Click Deselect All.
5 Select only the com.swtjface.RCPExample checkbox under Workspace
Plug-ins. Click Add Required Plug-ins, click Apply, and then click Run.
The resulting workbench should look like that shown in figure 13.5. At present, it
doesn’t look exciting. But that will change once we add the new containers and
components provided by the Eclipse Forms toolset.
13.3.4 Reviewing the RCP process
Before you learn about the new and exciting components provided by Eclipse
Forms, it will be helpful to look at the classes you’ve created and how they
Figure 13.4
Eclipse dialog to configure
application execution
298 CHAPTER 13
Looking beyond SWT/JFace
interact. This will clarify the structure of the RCP and make its development pro-
cess clearer.
So far, we’ve provided the code for five important files:
■ ExampleApplication.java—Starts initial execution, and points to the ID of
the application’s WorkbenchAdvisor
■ ExampleAdvisor.java—Provides overall visual configuration of the work-
bench, and identifies its perspective according to its ID
■ ExamplePerspective.java—Arranges the panes within the workbench, and
identifies each (in our case, only the view) by its ID
■ ExampleView.java—Provides the behavior and appearance of the window
that makes up the workbench
■ plugin.xml—Matches each of the classes mentioned here to a specific ID
Figure 13.5 The top-level workbench in the RCPExample application
Populating forms with Eclipse Forms widgets 299
As you can see, these files progress from the top-level application execution to the
low-level configuration of an individual window. By understanding each step of
the development process, you’ll be better able to improve and debug your future
RCP applications. But to finish the ExampleRCP project, we need to present the new
components contained in the Eclipse Forms toolset.
13.4 Populating forms with Eclipse Forms widgets
Eclipse’s Plug-in Manifest Editor used to bother us. It has hyperlinks, expandable
sections, and a cleaner, more professional appearance than anything we could
build with SWT/JFace. But after discovering the Eclipse Forms toolset, we can add
these features to our applications and make them look just as sharp. The goal of
this section is to show you how to do this.
We’ll start by examining the FormToolkit class that creates new GUI compo-
nents. Then, we’ll see what Composites the Eclipse Forms toolset has to offer and
add a number of them to the ExampleView class. Finally, we’ll examine the Hyper-
link class and the capability of adding text-based events.
13.4.1 Using FormToolkit and the Eclipse Forms containers
In SWT/JFace, you create widgets and add them to a parent Composite. Using
Eclipse Forms, you start with a FormToolkit object and create components by
invoking its methods. To show you what components are available, we’ll divide
these methods into two categories: those that create regular SWT widgets and
those that create Eclipse Forms widgets.
Adding SWT components with the FormToolkit
Table 13.3 lists the FormToolkit methods that create SWT widgets inside a form. In
each case, the method returns an instance of the desired component. (Refer to
chapters 3 and 5 if any of these look unfamiliar.)
Table 13.3 FormToolkit methods for creating SWT widgets
Method Function
createButton(Composite, String, int) Returns a Button with the given text and style
createComposite(Composite) Returns a Composite object
createComposite(Composite, int) Returns a Composite object with the given style
createLabel(Composite, String) Returns a Label with the given text
continued on next page
300 CHAPTER 13
Looking beyond SWT/JFace
It’s important to remember that many of these Controls need to be adapted for
insertion into the form. This limits the component’s colors to those used in the
form and provides keyboard access and tracking. The FormToolkit’s adapt()
method makes this possible.
Alternatively, you can use the Controls provided by the Eclipse Forms toolkit.
First we’ll present the new Composite classes provided by Eclipse Forms, and then
we’ll update the ExampleView class with them.
Understanding Eclipse Forms Composites
When you’re building form-based applications, you need more capabilities than
those provided by regular SWT Composites. For this reason, Eclipse Forms pro-
vides a series of container classes that simplify form development. These are listed
in table 13.4.
createLabel(Composite, String, int) Returns a Label with the given text and style
createSeparator(Composite, int) Returns a Separator with the given style
createTable(Composite, int) Returns a Table with the given style
createText(Composite, String) Returns a Text object with the given text
createText(Composite, String, int) Returns a Text object with the given text and style
createTree(Composite, int) Returns a Tree with the given style
Table 13.4 FormToolkit methods for creating Eclipse Forms composites
Method Function
createCompositeSeparator(Composite) Returns a Composite to serve as a separator
createExpandableComposite(Composite, int) Creates an ExplandableComposite object
createForm(Composite) Creates a Form object in the Composite
createFormText(Composite, boolean) Returns a FormText, and sets HTML reading
createPageBook(Composite, int) Returns a ScrolledPageBook Composite
createScrolledForm(Composite) Returns a ScrolledForm Composite
createSection(Composite, int) Returns a Section Composite
Table 13.3 FormToolkit methods for creating SWT widgets (continued)
Method Function
Populating forms with Eclipse Forms widgets 301
We’ll discuss the Form, FormText, and ExpandableComposite classes here. Forms
serve as the top-level containers in a form-based application, but FormText Compos-
ites are more interesting. Not only can you can configure them for word wrap-
ping, but they also can display text marked with HTML.
ExpandableComposites make it possible to expand and collapse regions of a
GUI by clicking on toggle signs called Twisties. These regions are represented by
Composites that are added to the ExpandableComposite with its setClient()
method. This is useful for forms with optional sections that need to save space.
Listing 13.6 creates these components inside the createPartControl()
method of the ExampleView class. We recommend that you update the Example-
View with this code.
package com.swtjface.RCPExample;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.forms.widgets.*;
import org.eclipse.ui.part.ViewPart;
public class ExampleView extends ViewPart
{
public void createPartControl(Composite parent)
{
FormToolkit kit = new FormToolkit(parent.getDisplay());
Form form = kit.createForm(parent);
ColumnLayout layout = new ColumnLayout();
form.getBody().setLayout(layout);
ExpandableComposite exComp = kit.createExpandableComposite
(form.getBody(), ExpandableComposite.TWISTIE);
exComp.setText("The Eclipse Forms toolset is:");
exComp.setExpanded(true);
FormText ft = kit.createFormText(exComp, true);
exComp.setClient(ft);
String html = "UsefulPowerful" +
"Simple";
ft.setText(html, true, false);
}
public void setFocus()
{
}
}
Listing 13.6 ExampleView.java (updated)
Use
FormToolkit to
create form
containers
b
Configure
ExpandableComposite
for display
c
d Configure
FormText
for
display
302 CHAPTER 13
Looking beyond SWT/JFace
You need to call the Form.setBody() method to associate a layout with the con-
tainer. This method provides the Form’s underlying Composite.
The ExpandableContainer.TWISTIE style creates a triangle component that con-
trols the state of the container. The setClient(ft) method tells it to expand and
collapse the FormText, and setExpanded(true) tells the container that its initial
state should be expanded.
When you’re using FormText objects to display HTML, you need to set the second
argument of setText() to true. Also, make sure the HTML starts with and
ends with .
Figure 13.6 shows how these containers work
together. It’s important to note that, because we
chose a Form container, the background is white
and the text takes the font and size shown.
Just as with SWT Composites, you can control
how child components are arranged with layouts.
You can still use the Layout classes from chapter 6,
and you can also use two subclasses provided by
Eclipse Forms: ColumnLayout and TableWrapLay-
out. The first organizes widgets into vertical col-
umns and tries to keep children at their preferred
size. The second produces a table format similar to
that used in HTML, where cells expand to provide
word-wrapping of text.
Now that we’ve discussed Eclipse Forms Com-
posites and how they arrange children, let’s look into the newest child compo-
nent available for use: the Hyperlink.
13.4.2 Firing text-based events with Hyperlinks
Regular hyperlinks function by causing a web browser to jump to a new URL,
but Eclipse Forms Hyperlinks provide more flexibility. In essence, they are
Labels that generate new events called HyperlinkEvents. By creating appropri-
ate event-handling routines, you can use these events to perform whatever pro-
cessing you choose.
b
C
D
Figure 13.6
The ExampleView with an
expandable container and
HTML display
Populating forms with Eclipse Forms widgets 303
Components can respond to HyperlinkEvents with addHyperlinkListener().
Table 13.5 lists the methods needed to implement the HyperlinkListener inter-
face and those contained in the HyperlinkEvent class.
When you click the link, the LinkActivated() method fires. The other event-
handling methods, LinkEntered() and LinkExited(), work similarly to the Mouse-
Entered() and MouseExited() methods discussed in chapter 4. Since most forms
only require LinkActivated(), we recommend creating a HyperlinkAdapter.
HTML hyperlinks use an HREF attribute to tell the web browser which URL to
locate upon activation. Eclipse Forms Hyperlinks have setHref() and getHref()
methods, but they serve a different purpose. In this case, setHref() stores an
Object for use during processing.
As shown, you can access this Object with the HyperlinkEvent’s getHref()
method. You can also access the Hyperlink’s text with getLabel() and determine
which modifier keys were pressed with getStateMask().
The following snippet shows how to create a Hyperlink with a FormToolkit
object (ft), and the process of setting and retrieving data using setHref() and
getHref(). In this case, clicking the Hyperlink changes its text to the String
assigned with setHref():
final Hyperlink hl = ft.createHyperlink(form.getBody(), "Click",
SWT.NULL);
hl.setHref("http://www.eclipse.org/");
hl.addHyperlinkListener(new HyperlinkAdapter()
{
public void linkActivated(HyperlinkEvent e)
{
Table 13.5 Methods to implement the HyperlinkListener interface and contained in the Hyper-
linkEvent class
Method Function
IHyperlinkListener.linkActivated() Performs processing if the link is clicked
IHyperlinkListener.linkEntered() Performs processing if the mouse hovers over the
link
IHyperlinkListener.linkExited() Performs processing if the mouse leaves the link
HyperlinkEvent.getHref() Returns the Object specified with setHref()
HyperlinkEvent.getLabel() Returns the text of the Hyperlink that fired the
event
HyperlinkEvent.getStateMask() Returns the modifier keys pressed during activation
304 CHAPTER 13
Looking beyond SWT/JFace
hl.setText((String)e.getHref());
}
});
By default, Hyperlinks are displayed in black without an underline. You can change
these parameters with the Hyperlink’s setUnderline(boolean) method and the
Control’s setForeground(Color) method. You can also standardize your Hyper-
links’ appearance throughout your form by obtaining a HyperlinkGroup with the
FormToolkit’s getHyperlinkGroup() method and adding each link to the group.
The HyperlinkGroup object’s methods are listed in table 13.6.
The code in bold in listing 13.7 updates the ExampleView’s createPartControl()
method to provide a Button and a series of Hyperlinks. When activated, these
links update the Button to display the text stored by their setHref() methods.
package com.swtjface.RCPExample;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.forms.*;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.*;
import org.eclipse.ui.part.ViewPart;
public class ExampleView extends ViewPart
{
public void createPartControl(Composite parent)
{
FormToolkit kit = new FormToolkit(parent.getDisplay());
Form form = kit.createForm(parent);
ColumnLayout layout = new ColumnLayout();
form.getBody().setLayout(layout);
Table 13.6 HyperlinkGroup methods for controlling Hyperlink appearance
Method Function
add(Hyperlink) Performs processing if the link is clicked
getLastActivated() Returns the most recently clicked Hyperlink
setBackground(Color) Sets the foreground color of the group’s Hyperlinks
setForeground(Color) Sets the foreground color of the group’s Hyperlinks
setHyperlinkUnderlineMode(int) Determines whether the links should be underlined
Listing 13.7 ExampleView.java (completed)
Populating forms with Eclipse Forms widgets 305
ExpandableComposite exComp = kit.createExpandableComposite
(form.getBody(), ExpandableComposite.TWISTIE);
exComp.setText("The Eclipse Forms toolset is:");
exComp.setExpanded(true);
FormText ft = kit.createFormText(exComp, true);
exComp.setClient(ft);
String html = "UsefulPowerful" +
"Simple";
ft.setText(html, true, false);
Label sep = kit.createSeparator(form.getBody(), SWT.HORIZONTAL);
final Button button = kit.createButton(form.getBody(),
"Favorite color?", SWT.NULL);
HyperlinkGroup hg = kit.getHyperlinkGroup();
hg.setHyperlinkUnderlineMode(HyperlinkSettings.UNDERLINE_HOVER);
hg.setForeground(parent.getDisplay().getSystemColor
(SWT.COLOR_RED));
String[] cnames = {"red", "green", "yellow", "blue"};
Hyperlink[] hl = new Hyperlink[4];
String name;
for (int i=0; i<4; i++)
{
name = "My favorite color is "+cnames[i]+".";
hl[i] = kit.createHyperlink(form.getBody(), name, SWT.NULL);
hg.add(hl[i]);
hl[i].setHref(cnames[i]);
hl[i].addHyperlinkListener(new HyperlinkAdapter()
{
public void linkActivated(HyperlinkEvent e)
{
button.setText("My favorite color is "
+ (String)e.getHref() + ".");
button.redraw();
}
});
}
}
public void setFocus()
{
}
}
Add
separator
and button
Create HyperlinkGroup;
standardize links’
appearance
Add Hyperlinks to form
and HyperlinkGroups
Store color name
to Hyperlink
Retrieve color
name; update
button text
306 CHAPTER 13
Looking beyond SWT/JFace
Figure 13.7 shows the result of the completed ExampleView.
Now that we’ve completed our discussion of creating workbenches with the
Rich Client Platform, let’s take advantage of its main benefit: standalone applica-
tion development. So far, we’ve created an Eclipse plug-in that can be executed as
an application, but we need to compile it into a form that can be run with a regu-
lar Java compiler.
13.5 Building a standalone RCP application
Having finished the workbench plug-in, it’s time to turn it into a regular Java
application. This straightforward process requires three steps:
1 Export the RCPExample project to a directory.
2 Add the necessary plug-ins to the exported directory.
3 Enter the command to launch the application.
We’ll start with step 1, which involves creating a separate directory to hold the
workbench application and its support files.
13.5.1 Exporting RCPExample to an application directory
Because Eclipse does most of the work, the first task is simple. Follow these steps:
1 To create the directory, go to the Eclipse Workbench and right-click the
project name, com.swtjface.RCPExample. Choose the Export option in the
context menu.
2 Select the Deployable plug-ins and fragments option, and click Next.
3 When the Export Plug-ins and Fragments dialog appears, make sure that
the com.swtjface.RCPExample checkbox is the only one selected.
Figure 13.7
The completed ExampleView, with
expandable containers and hyperlinks
Building a standalone RCP application 307
4 Under Export Options, choose to
deploy the plug-in as a directory
structure.
5 Enter a path name for the directory.
In the dialog shown in figure 13.8,
we’ve chosen to export the plug-in
to C:\RCPExample. Click Finish.
Look through the directory that you’ve cre-
ated. You should see a folder called plugins
and, immediately inside that, one called
RCPExample_1.0.0. There, you should find
plugin.xml and RCPExample.jar. You may
not think these two files are sufficient for
the application, and you’re right. Next,
we’ll add plug-ins to provide the work-
bench’s complete functionality.
13.5.2 Adding plug-ins to the application directory
Just as you have to add classpath variables to make an Eclipse-based application
run, you need to add plug-ins to execute a workbench application. Unfortu-
nately, Eclipse won’t do this for you. So, you need to go through your $ECLIPSE/
plugins folder and copy the following directories to the plugins folder in your
application directory:
■ org.eclipse.core.expressions_x.y.z
■ org.eclipse.core.runtime_x.y.z
■ org.eclipse.jface_x.y.z
■ org.eclipse.help_x.y.z
■ org.eclipse.osgi_x.y.z
■ org.eclipse.swt_x.y.z
■ org.eclipse.ui.forms_x.y.z
■ org.eclipse.ui.workbench_x.y.z
■ org.eclipse.ui_x.y.z
■ org.eclipse.update.configurator_x.y.z
Figure 13.8
The dialog settings for exporting
com.swtjface.RCPExample
to a directory
308 CHAPTER 13
Looking beyond SWT/JFace
In addition, you need to add the specific SWT plug-in(s) needed for your operat-
ing system and windowing system. In Windows, this is org.eclipse.swt.win32_x.y.z;
for Linux GTK, the plug-in is org.eclipse.swt.gtk_x.y.z. Just to be safe, we recom-
mend copying every plug-in that contains org.eclipse.swt in its title.
Finally, you need to add the file that lets you execute the application. Find
startup.jar in the top-level Eclipse directory ($ECLIPSE), and copy it to your top-level
application directory. On our Windows system, this directory is C:\RCPExample.
Once you’re finished with this step, you’re ready to execute the workbench. In
the next section, we’ll show you how this is done.
13.5.3 Executing the application
In the application directory, execute the following command:
java -cp startup.jar org.eclipse.core.launcher.Main –application
RCPExample.ExampleApplication
This should launch the view. If it doesn’t, find the log file in the configuration
directory in your application directory; this file will describe any errors that arose
in processing the application.
But if the form appears, congratulations! You’ve successfully used the Rich Cli-
ent Platform to build a standalone workbench. This capability will enable you to
build powerful, extensible applications based on the Eclipse framework. And who
knows? Maybe future developers will devote their time to building plug-ins for
your workbench.
13.6 Summary
The Rich Client Platform builds on what we’ve discussed in SWT and JFace and
provides a simple means of building workbenches with editors and views. As
you’ve seen, these can be exported as standalone applications. Similarly, the
Eclipse Forms toolset augments the widgets and containers from SWT/JFace to
enable rapid development of form-based interfaces.
It seems that each passing month brings a new and incredible capability involv-
ing SWT/JFace. Eclipse.org has just released a new version of its Visual Editor that
lets you build SWT GUIs in a graphical development environment (think MS
Visual Studio). The open-source GCJ tool can turn SWT/JFace code into native
executables, and Sun’s Java Web Start can deploy SWT/JFace applications across
the Internet.
Summary 309
Learning SWT/JFace can be an exciting process, but the new applications are
more exciting still. What will happen when the 3-D programming language,
OpenGL, merges with the rest of the SWT toolset? Will SWT/JFace become exe-
cutable in browsers and revolutionize applets in the same way that it’s revolution-
ized desktop development? What about J2EE?
One thing’s for certain: The SWT/JFace toolkit is becoming more important as
Eclipse gains in capability and popularity. Those familiar with its development will
have an advantage as new technologies become available. We hope that this book
has provided you with a firm foundation on which to build new and more exciting
graphical applications.
We, the authors, would like to thank you for sharing your time with us. If you’d
like to contact us for any reason, you can reach us through our publisher at
www.manning.com.
311
Creating projects
with SWT/JFace
312 APPENDIX A
Creating projects with SWT/JFace
Before you can begin coding with SWT and JFace, you need to prepare the Eclipse
development environment to include the two libraries. This appendix focuses on
the steps needed to ensure that your GUI code will compile and execute properly.
We hold Eclipse in the highest esteem, but if you intend to market your own
SWT/JFace applications, you’ll need to know how to build GUIs that can run without
the Workbench. Therefore, this appendix is divided into two parts. The first outlines
the steps needed to set up an SWT/JFace project in Eclipse. The second shows how
to accomplish the same purpose using the Java SDK (Java, Javac, and so on).
A.1 Eclipse-based SWT/JFace development
All the code samples in this book are part of one large project, WidgetWindow, and
each chapter adds classes in a separate package. Therefore, for this book, you
need to perform the process outlined here only once.
A.1.1 SWT and JFace projects in Windows
In writing this book, we have assumed that you’re already familiar with Eclipse.
But a brief review of creating projects will be helpful if you are out of practice. In
particular, this section outlines the process of setting up the WidgetWindow project
in Eclipse. For a full description of Eclipse projects, we recommend Eclipse in
Action by David Gallardo, Ed Burnette, and Robert McGovern (Manning, 2003).
The steps for setting up an SWT/JFace Eclipse project in Windows are listed in
table A.1.
Table A.1 Preparing an SWT/JFace application in Eclipse for Windows
Goal Procedure
1 Acquire the
necessary
software
tools.
1. If it isn’t already available, download the Java SDK (ver. 1.2.2 or later) from
http://java.sun.com. Install the SDK in your operating system.
2. Download the Eclipse SDK (ver. 2.0 or later) from Eclipse.org at
www.eclipse.org/downloads/index.php. No installation is necessary.
3. If you’re interested, download the source code for SWT from Eclipse.org by scroll-
ing down the same page in the Eclipse.org site.
continued on next page
Eclipse-based SWT/JFace development 313
2 Create the
Widget-
Window
project.
1. Start the Eclipse IDE, click the File option in the main menu, and select
New->Project from the drop-down menus that appear.
2. In the first page of the New Project Wizard, click Java in the left pane and Java
Project in the right pane. Click Next.
3. Enter WidgetWindow as the project name and leave the default option checked.
Click Finish. Doing so creates a WidgetWindow project and places it in the Wid-
getWindow directory.
4. In the Workbench, right-click the new project and select the New->Package
option from the drop-down menu. Enter a package name such as com.swtj-
face.Ch2. Click Finish.
continued on next page
Table A.1 Preparing an SWT/JFace application in Eclipse for Windows (continued)
Goal Procedure
314 APPENDIX A
Creating projects with SWT/JFace
3 Start the
process of
creating
classpath
variables
for the
SWT/JFace
libraries.
1. Right-click the WidgetWindow project and choose Properties, the final option in
the pull-down menu. Click the Java Build Path option at left on the screen. You’ll
now tell the Java compiler where to find the necessary SWT/JFace files.
2. Click the Libraries tab just below the Java Build Path title. Click the Add Variable
button. These variables will represent the libraries (*.jar) you need for compilation.
In the New Variable Classpath Entry dialog, click the Configure Variables button.
3. When the Preferences window appears, click New. Enter SWT_LIB as the vari-
able name, and click File to search for its corresponding library.
4. In the dialog that appears, search the directory to find $ECLIPSE/plugins/
org.eclipse.swt.win32_x.y.z/ws/win32/swt.jar. Select this file and click Open.
Click OK in the New Variable Entry dialog, and the SWT_LIB variable will join the
list of classpath variables.
continued on next page
Table A.1 Preparing an SWT/JFace application in Eclipse for Windows (continued)
Goal Procedure
Eclipse-based SWT/JFace development 315
4 Create vari-
ables for the
libraries
needed for
JFace.
1. Use the procedure described previously to create a variable named JFACE_LIB
for the jface.jar (or jface_new.jar) file at $ECLIPSE/plugins/
org.eclipse.jface_x.y.z/.
2. Create a variable named BOOT_LIB for the runtime.jar file located at $ECLIPSE/
plugins/org.eclipse.core.boot_x.y.z/.
3. Create a variable named RUNTIME_LIB for the runtime.jar file located at
$ECLIPSE/plugins/org.eclipse.core.runtime_x.y.z/.
4. Create a variable named WORKBENCH_LIB for the workbench.jar (or
workbench_new.jar) file at $ECLIPSE/plugins/org.eclipse.ui.workbench_x.y.z/.
5. Click OK in the Preferences window.
5 Add these
variables to
the Widget-
Window
project.
1. In the Workbench, right-click on the WidgetWindow project, and select the Prop-
erties option.
2. Select the Java Build Path option in the left pane, and click the Libraries tab on
the right pane.
3. Click the Add Variable button. In the New Variable Classpath Entry box, select
the JFACE_LIB, BOOT_LIB, RUNTIME_LIB, and WORKBENCH_LIB variables.
Click OK after each.
4. Use the procedure described previously to create a variable named JFACE_LIB
for the jface.jar (or jface_new.jar) file at
$ECLIPSE\plugin\org.eclipse.jface_x.y.z\.
5. Create a variable named BOOT_LIB for the runtime.jar file located at
$ECLIPSE\plugins\org.eclipse.core.boot_x.y.z\.
6. Create a variable named RUNTIME_LIB for the runtime.jar file located at
$ECLIPSE\plugins\org.eclipse.core.runtime_x.y.z\.
7. Create a variable named WORKBENCH_LIB for the workbench.jar (or
workbench_new.jar) file at $ECLIPSE\plugins\org.eclipse.ui.workbench_x.y.z\.
8. Click OK in the Preferences window.
continued on next page
Table A.1 Preparing an SWT/JFace application in Eclipse for Windows (continued)
Goal Procedure
316 APPENDIX A
Creating projects with SWT/JFace
A.1.2 SWT and JFace projects in *nix
Table A.2 shows the steps needed to prepare a project to use the SWT/JFace
toolset. Although they’re geared for Linux and GTK, the procedures should be
similar for any *nix platform and windowing system.
6 Add the
native graph-
ics library to
the project.
1. To enable communication between SWT/JFace commands and the operating
system calls, you need to make the SWT native graphics file available. It’s
called swt-win-nnnn.dll, and it’s located at $ECLIPSE/plugins/
org.eclipse.swt.win32_x.y.z/os/win32/x86.
2. Once you’ve found the graphics library, you need to make sure the application
launcher can use it. The documentation lists a number of ways to do this, but
we’ve found that adding a copy to the $JAVA/jre/bin directory works best.
Other methods, which can be less reliable, include the following:
Option 1: Copy and paste these files directly in the WidgetWindow project.
Option 2: Include the native library in any directory pointed to by the
java.library.path variable. This variable, among others, can be seen by
clicking Help->About Eclipse Platform->Configuration Details.
Option 3: Go to Control Panel->System->Advanced->Environmental Variables and
update the PATH variable with the directory containing the library file.
Table A.1 Preparing an SWT/JFace application in Eclipse for Windows (continued)
Goal Procedure
Table A.2 Preparing an SWT/JFace application in Eclipse for *nix
Goal Procedure
1 Acquire the
necessary
software
tools.
1. If it isn’t already available, download the Java SDK (ver. 1.2.2 or later) from
http://java.sun.com. Install the SDK in your operating system.
2. Download the Eclipse SDK (ver. 2.0 or later) from Eclipse.org at
www.eclipse.org/downloads/index.php.
3. Unzip the file. The resulting directory will be called $ECLIPSE.
4. If you’re interested, download the source code for SWT from Eclipse.org by
scrolling down the same page in the Eclipse.org site.
continued on next page
Eclipse-based SWT/JFace development 317
2 Create the
WidgetWind
ow project.
1. Start the Eclipse IDE, click the File option in the main menu, and select
New->Project from the drop-down menus that appear.
2. In the first page of the New Project Wizard, click Java in the left pane and Java
Project in the right pane. Click Next.
3. Enter WidgetWindow as the project name and leave the default options
checked. Click Finish. Eclipse will create a WidgetWindow project and add it to
the WidgetWindow directory.
4. In the Workbench, right-click the new project and select the New->Package
option from the drop-down menu. Enter a name for your package, such as
com.swtjface.Ch2. Click Finish.
continued on next page
Table A.2 Preparing an SWT/JFace application in Eclipse for *nix (continued)
Goal Procedure
318 APPENDIX A
Creating projects with SWT/JFace
3 Start the pro-
cess of creat-
ing classpath
variables
for the
SWT/JFace
libraries.
1. Right-click the WidgetWindow project and choose Properties. Click the Java
Build Path option at the left of the screen. You’ll now tell the Java compiler
where to find the necessary SWT/JFace files.
2. Click the Libraries tab just below the Java Build Path title. Click Add Variable.
These variables will represent the libraries (*.jar) you need for compilation. In
the New Variable Classpath Entry dialog, click the Configure Variables button.
3. When the Preferences window appears, click New button. Enter SWT_LIB as
the variable name, and click File to search for its corresponding library.
4. In the dialog that appears, search the directory to find $ECLIPSE/plugins/
org.eclipse.swt.gtk_x.y.z/ws/gtk/swt.jar. Select this file and click OK. Click OK
in the New Variable Entry dialog, and the SWT_LIB variable will be added to the
list of classpath variables.
5. For Linux/GTK, repeat steps 3 and 4 to add the SWT_PI variable, whose
swt_pi.jar file is located at $ECLIPSE/plugins/org.eclipse.swt.gtk_x.y.z/ws/
gtk/swt_pi.jar.
For Linux/Motif, repeat steps 3 and 4 to add the SWT_GTK variable, whose swt-
gtk.jar file is located at $ECLIPSE/plugins/org.eclipse.swt.motif_x.y.z/ws/gtk/
swt_gtk.jar.
continued on next page
Table A.2 Preparing an SWT/JFace application in Eclipse for *nix (continued)
Goal Procedure
Eclipse-based SWT/JFace development 319
4 Create addi-
tional vari-
ables for the
libraries
needed for
JFace.
1. Use the procedure described earlier to create a variable named JFACE_LIB for
the jface.jar (or jface_new.jar) file at $ECLIPSE/plugins/org.eclipse.jface_x.y.z/.
2. Create a variable named BOOT_LIB for the runtime.jar file located
at$ECLIPSE/plugins/org.eclipse.core.boot_x.y.z/.
3. Create a variable named RUNTIME_LIB for the runtime.jar file located at
$ECLIPSE/plugins/org.eclipse.core.runtime_x.y.z/.
4. Create a variable named WORKBENCH_LIB for the workbench.jar (or
workbench_new.jar) file at $ECLIPSE/plugins/org.eclipse.ui.workbench_x.y.z/.
5. Once finished, click OK in the Preferences window.
5 Add these
variables to
the Widget-
Window
project.
1. In the New Variable Classpath Entry dialog, select each of the variables you’ve
created—SWT_LIB, SWT_PI_LIB (or SWT_GTK), JFACE_LIB, BOOT_LIB,
RUNTIME_LIB, and WORKBENCH_LIB—and click OK.
2. Click OK to return to the Workbench.
continued on next page
Table A.2 Preparing an SWT/JFace application in Eclipse for *nix (continued)
Goal Procedure
320 APPENDIX A
Creating projects with SWT/JFace
6 Add the
native graph-
ics file (files)
to the
project.
1. To provide communication between the SWT/JFace commands and the operat-
ing system calls, you need to make the SWT native graphics files available. The
first step involves finding them. The locations for these files are as follows:
Platform
Native library file
Library pathname
Linux GTK
libswt-gtk-nnnn.so
libswt-gtk-pi.nnnn.so
libswt-gnome-gtk-nnnn.so
org.eclipse.swt.gtk_x.y.z/os/linux/x86
Linux Motif
libswt-motif-nnnn.so
libswt-gtk-motif.nnnn.so
libswt-gnome-gtk-nnnn.so
libswt-motif-nnnn.so
libswt-kde-motif.nnnn.so
org.eclipse.swt.motif_x.y.z/os/linux/x86
Solaris
libswt-cde-motif-nnnn.so
org.eclipse.swt.photon_x.y.z/os/qnx/x86
AIX Motif
libswt-motif-nnnn.so
org.eclipse.swt.motif_x.y.z/os/ppc
PhotonQNX
libswt-photon-nnnn.so
org.eclipse.swt.photon_x.y.z/os/qnx/x86
2. Once you’ve found the necessary file or files, you need to make sure the appli-
cation launcher can find them. The documentation lists a number of ways to do
this, but we’ve found that adding the files to the /usr/lib directory works best.
This isn’t the safest thing to do, but it’s reliable.
Other methods, which can be less reliable, include the following:
Option 1: Copy and paste these files directly in the WidgetWindow project.
Option 2: Include the native library in any directory pointed to by the
java.library.path variable. This variable, among others, can be seen by
clicking Help->About Eclipse Platform->Configuration Details.
Option 3: Make sure the LD_LIBRARY_PATH environmental variable contains the
directory in which these library files are located.
Table A.2 Preparing an SWT/JFace application in Eclipse for *nix (continued)
Goal Procedure
Eclipse-based SWT/JFace development 321
A.1.3 SWT in OS X
Since the advent of OS X, the Macintosh has become popular as a platform for
Java development. In fact, much of this book and many of the examples were orig-
inally developed on OS X. However, due to SWT’s use of native libraries, running
an SWT application on OS X is more complicated than the instructions for Win-
dows and Linux described in the previous sections. This section addresses the
steps necessary to get an SWT application running on OS X; the rest of this section
assumes that you’re using a Mac.
If you examine your Eclipse installation, you’ll notice that instead of the single
executable file that is found on Windows or Linux, there is a directory called
Eclipse.app. Naming the directory with an .app extension and conforming to a
certain specification causes the operating system to treat the directory as an appli-
cation to be launched when double-clicked. To run your own SWT application,
you’ll need to set up the same directory structure. We recommend using Ant or
some other tool to perform this step as part of your standard build process.
Although OS X supports launching Java applications by double-clicking a .jar
file, in order to properly hook an SWT application into the native event queue you
need to launch your code through a small wrapper program. This executable file
is called java_swt, and it can be found at $ECLIPSE_HOME/Eclipse.app/Contents/
MacOS/java_swt. This program will launch first and will load your application’s
.class files after it has set things up for you.
We’ll assume you’re assembling an application named Foo. Follow these steps:
1 Create a directory called Foo.app, which will eventually hold your complete
application.
2 After you’ve built a .jar containing your application’s files as usual, copy it,
along with the SWT/JFace .jar files and any other necessary third-party librar-
ies, to Foo.app/Contents/Resources/Java. The SWT native libraries (files
ending in .jnilib) should be put in Foo.app/Contents/Resources/Java/dll.
Finally, copy the java_swt executable to Foo.app/Contents/MacOS.
3 Once the file is copied, you must also make sure the executable permis-
sion is set on the file. If you’re using Ant, remember that the copy task
doesn’t preserve file permissions. If your application doesn’t launch when
clicked, and there are no error messages, check that the permissions are
set correctly.
322 APPENDIX A
Creating projects with SWT/JFace
4 Once you’ve placed your application’s files, you need to create couple of
additional files describing your application to the operating system. Both
files belong in Foo.app/Contents:
■ The file PkgInfo should contain a single line of text. If you’ve regis-
tered as an Apple developer and received a creator code for your
application, use it.
■ A bit more complicated is the Info.plist file, which contains XML
describing various aspects of your application. We don’t have space to
discuss the format of this file in detail here; a working version is available
from this book’s website, and you can easily customize it for your needs.
Of particular note are the CFBundleExecutable entry, which tells the
OS to execute java_swt when the application is clicked, and an entry
allowing you to specify a file containing the icon that should be dis-
played for your application. At the bottom of the file is an entry that
describes the environment to be used when the JVM is launched.
Change the ClassPath attribute to name the .jar files used by your own
application, and change the MainClass attribute so it names the class
containing your application’s main() method.
These instructions seem complicated, but it’s fairly simple to get things up and
running, especially if you look at a working example. Additionally, these tasks are
all easily scriptable using Ant, so they can be automated.
A.2 SWT/JFace in standalone applications
Even without the Eclipse platform, the process of building an SWT/JFace project
is straightforward. The only real work involves telling the Java compiler where to
find the libraries. The steps are listed in table A.3.
Table A.3 Preparing an SWT/JFace application for standalone development
Goal Procedure
1 Add the neces-
sary SWT/JFace
library files to
the Java class-
path.
1. Add the SWT library or libraries (described earlier) to your compilation
path. Then, add the library files needed for JFace.
2. Add the -Djava.library.path= option to the compiler command fol-
lowed by the directory containing the native graphics library. The path to
this library was described earlier.
3. As a Windows example, the compiler command would have the following
option: –Djava.library.path=
C:\eclipse\plugins\org.eclipse.swt.win32
3.0.0\os\win32\x86.
SWT/JFace in standalone applications 323
With the WidgetWindow project set up, you can begin building classes and display-
ing their GUIs. Fortunately, programming with the SWT and JFace libraries is sim-
pler than preparing the Workbench to compile their applications.
324
OLE and ActiveX
in SWT/JFace
COM simplified 325
In earlier chapters, we explored how SWT is built in layers: a small library of C
code built with Java Native Interface (JNI) interacts with the underlying operating
system to provide the necessary building blocks for more elaborate capabilities.
One of the design goals of the native layer was for it to be very small, often provid-
ing simple wrappers around native APIs. Using this novel approach, the OTI/IBM
team has been able to give programmers unprecedented access to the native capa-
bilities of all supported platforms. In so doing, the team chose not limit itself to
the features common to all platforms. Among these platforms, Microsoft Windows
offers a unique capability that has appealed to Visual Basic programmers for many
years: reusable binary objects, otherwise known as COM objects.
SWT/JFace programmers haven’t been left out; this appendix covers the
nature and depth of COM support in SWT. Specifically, you’ll see how you can
include ActiveX controls and OLE documents inside your applications in just a
few SWT method calls. So that you can fully take advantage of this feature, we’ll
first review some basic COM features and general principles.
B.1 COM simplified
Microsoft designed the Component Object Model (COM) to try to solve a simple
problem: how to reuse binary objects. Previous solutions based solely on shared
libraries (Dynamic Link Libraries [DLLs]) showed that they weren’t practical for
C++ programming and that managing their proliferation on a given system was in
itself a major cause of application problems. In the process of designing a replace-
ment solution, Microsoft felt it should also address a new class of problems for the
time: location transparency.
In the end, the new technology was built to provide a unique solution for situ-
ations using three distinct types of objects:
■ In-process objects share the same address space as the client code using them
(the code is inside DLLs).
■ Local out-of-process objects are located on the same computer as the client
code but reside in a separate address space (inside a separate EXE file).
■ Remote objects are located inside an EXE or DLL on a different machine and
are accessible via remote procedure calls.
These are important concepts for anyone interested in doing COM with SWT/JFace.
326 APPENDIX B
OLE and ActiveX in SWT/JFace
B.1.1 IUnknown/IDispatch
COM is based on the notion of interfaces. Interfaces allow the logical grouping of
functionalities as well as their discovery at runtime by querying the objects them-
selves. Each interface has an identifier (IID) that uniquely defines both the meth-
ods available and their physical placement relative to one another in memory.
Physically, interfaces are organized into vtables (arrays of function pointers). The
notion of physical ordering of these functions is crucial, as you’ll see when we
investigate the details of SWT programming. COM makes widespread usage of Glo-
bally Unique Identifiers (GUIDs). Specific GUID uses include object identifiers, type
library identifiers, and interface identifiers. The algorithm for generating these
IDs is beyond the scope of this book, but it’s described on the Microsoft Develop-
ers Library web site (msdn.microsoft.com).
The way COM interfaces are versioned may surprise Java programmers: An
interface that has been published can’t be modified. Instead, it must be extended
via an entirely new interface. According to Microsoft’s best practices, the new
interface should have the same base name followed by a version number that
increases for each new version. For example, when Microsoft needed to give users
more control over the web browser ActiveX control, it extended the original
IWebBrowser interface with a richer IWebBrowser2.
Unlike the Java model, where class files contain enough metadata to allow the
reflection API to return a complete description of objects and methods, the COM
runtime discovery model is based on the existence of IUnknown, a core interface
that all others extend. Given a specific GUID, QueryInterface returns a pointer to
the interface implementation. The two other IUnknown functions, AddRef and
Release, are responsible for tracking the number of references to the interface
and returning all allocated resources to the operating system. Reference counting
is an important aspect of COM programming and is the cause of many bugs that
are difficult to identify.
SWT fully adheres to Microsoft’s guidelines for reference counting, but some-
times you’ll need to remember these simple rules: Clients are responsible for call-
ing AddRef and Release on every interface they query; and both calls must be
made on the same interface reference, to allow an object to track the references
on a per-interface basis rather than for the whole object. These important func-
tions are listed in table B.1.
COM simplified 327
Using this simple design, and with the aid of a small runtime library that provides
support for registering, discovering, and instantiating objects, it’s possible to start
creating powerful reusable binary entities using a language like C or C++. Objects
can then be segregated into families based on their implementing predefined sets
of interfaces, all deriving from the core IUnknown. Over the years, Microsoft has
defined several such families: scriptable objects, ActiveX controls, active docu-
ments, and so on. Some of these definitions have gradually evolved toward fewer
mandatory interfaces and more optional behaviors.
Although a powerful concept, this interface proved too complicated for high-
level languages like VBScript, JScript, and the first versions of Visual Basic. To allow
these interpreter-based languages (and other scripting languages) to access COM
objects, Microsoft defined another key COM interface. IDispatch allows object
capabilities to be queried by name rather than by interface identifier. Like all the
other COM interfaces, IDispatch extends IUnknown. Each method that needs to be
publicized is given a unique dispatch identifier that can be used to invoke it. COM
automation (or just automation) is the process of letting client code interface with a
COM object using the IDispatch-based discovery and invocation mechanism. The
flexibility it provides comes at a price: the automation querying and invocation pro-
cess is significantly slower that the default binary binding used for non-automation
calls. The functions provided by this interface are shown in table B.2.
Table B.1 Functions of the IUnknown COM interface
IUnknown function Description
AddRef Increases the reference count for this interface
QueryInterface Returns pointers to supported interfaces
Release Decreases the reference count for this interface
Table B.2 Functions of the IDispatch COM interface
IDispatch function Description
AddRef Increases the reference count for this interface
GetIDsOfNames Maps a single member and an optional set of argument names to a
corresponding set of integer dispatch IDs (DISPIDs)
GetTypeInfo Gets the type information for an object
continued on next page
328 APPENDIX B
OLE and ActiveX in SWT/JFace
SWT provides methods for two of these functions. Provided with an optional list of
method names, GetIDsOfNames() returns a list of matching dispatch IDs
(DISPIDs). These can be used in subsequent calls to the Invoke() method to trig-
ger their execution. Using this simple mechanism, objects can expose both meth-
ods and properties. COM recognizes four reasons to call Invoke():
■ To call a method (DISPATCH_METHOD)
■ To retrieve the value of a property (DISPATCH_PROPERTYGET)
■ To modify the value of a property (DISPATCH_PROPERTYPUT)
■ To modify the value of a property that is a reference to another object
(DISPATCH_PROPERTYPUTREF)
NOTE You may wonder why there’s no way to get the value of a property that is a
reference to an object. This situation is covered by DISPATCH_PROPERTYGET
via the fact that all automation methods manipulate a universal data type
called Variant. A variant is a unique way to represent all the possible data
types supported by automation-capable languages. You can find the na-
ture of the content of a given variant by ORing predefined constants. Pos-
sible contents include a simple string (BSTR in COM parlance), a
primitive type, or a reference to an object. Object references come in two
flavors: a reference to an IUnknown and a reference to an IDispatch in-
stance. Variants are a rich data type, and at this point SWT supports only a
portion of the complete specification. Notably absent is support for Safe-
Arrays (the Visual Basic way of dealing with arrays) and user-defined
types (the Visual Basic types).
B.1.2 Object hosting
The ability to reuse the capabilities of an external object by embedding the object
directly inside your application lies at the heart of client-side COM programming.
COM provides two types of user experiences for interacting with embedded
GetTypeInfoCount Retrieves the number of type information interfaces that an object pro-
vides (either 0 or 1)
Invoke Provides access to properties and methods exposed by an object
QueryInterface Returns pointers to supported interfaces
Release Decreases the reference count for this interface
Table B.2 Functions of the IDispatch COM interface (continued)
IDispatch function Description
COM simplified 329
objects. In the first scenario, the embedded object retains its own interface that
users see in a window that’s separate from the main application window. In the sec-
ond scenario, known as in-place activation, the user can interact with the embedded
object without leaving the container document or application. In this scenario, the
container and the embedded object collaborate to provide a composite menu bar
where commands and features from both applications are available at the same
time. The richer of the two scenarios, in-process activation is also more compli-
cated to program, because it requires (among other things) that mouse and key-
board events be routed properly. COM allows both local servers (standalone EXEs
like Microsoft Word) and in-process servers (DLLs) to be in-place-activated.
In both scenarios, the container must implement a number of predefined
COM interfaces in order for the embedded object to communicate with it.
Microsoft refers to these mandatory interfaces as sites. The complete description
of all the site interfaces and the features they provide is beyond the scope of this
book. In most cases, the interfaces implemented by the SWT programmers are
enough; however, in some situations you’ll need to extend one of the default site
classes and implement additional site interfaces. Hosting an ActiveX control ver-
sus an OLE document requires the implementation of two sets of COM interfaces,
described in tables B.3 and B.4. One of the examples later in this appendix shows
how to create a custom container by extending an existing one.
Table B.3 Document site interfaces
Interface Description
IAdviseSink Receives general notifications from the embedded object
IOleClientSite Manages general communication with the container
IOleInPlaceSite Manages in-place activation of the hosted control
IOleDocumentSite Provides a means to activate a hosted document
IUnknown The fundamental COM interface
Table B.4 Control site interfaces
Interface Description
IAdviseSink Receives general notifications from the embedded object
IOleControlSite Manages general communication with the container
IOleInPlaceSite Manages in-place activation of the hosted control
IUnknown The fundamental COM interface
330 APPENDIX B
OLE and ActiveX in SWT/JFace
B.1.3 Object instantiation
For the most part, instantiating a COM object is a straightforward task. The simplest
case involves a single call to CoCreateInstance(). However, more complex object-
instantiation strategies involve calling OleCreate() and passing it an instance of
IStorage that represents either a new document or one that you intend to edit; or
calling CoGetClassObject() to obtain an instance of an ActiveX IObjectFactory or
IObjectFactory2, and then calling their respective CreateInstance()or CreateIn-
stanceLic() method to obtain the new object’s IUnknown instance.
You use the latter approach to instantiate ActiveX controls that need a license
key to operate. Microsoft added licensing to ActiveX controls in order to prevent
programmers from creating their own applications by reusing the controls redis-
tributed with other applications; you had to purchase the development version of
the controls to use them. SWT contains a default implementation of these instanti-
ation strategies, but you may need to replicate them inside your code to address
current limitations or bugs in SWT. The beauty of the SWT COM library layering is
that you’ll be able to do so easily.
B.1.4 Event handling
The COM object embedding model includes a rich mechanism for dispatching
and handling events. It’s based on several simple notions. A sink interface is an
interface exposed by a COM client; it’s called by a COM server as a callback for the
purpose of sinking (handling) event notifications. In order for a server to dispatch
events to a client’s sink interface, the client code needs a process to pass a sink ref-
erence to the server. This is done via server connection points. A connection point is
the server-based mechanism that handles notification to the client’s sink inter-
face. A server exposes all of its connection points by implementing the IConnec-
tionPointContainer interface. Clients call FindConnectionPoint(), passing it the
GUID of an interface to get a reference to the IConnectionPoint exposed by the
server for this sink interface. IConnectionPoint contains the Advise() and Unad-
vise() methods to start and stop the flow of incoming events on the sink inter-
face, respectively.
B.1.5 Threading model
The COM threading model is based on the notion of apartments. An apartment is
an arbitrary construct meant to help the COM runtime library make the right
decisions about how to route method calls to a COM object. The simplest of all
scenarios is the single-threaded apartment (STA) model where the runtime takes care
The SWT COM library 331
of all concurrency problems (which happens when multiple threads in the client
code call the same method on the same object at the same time) transparently.
This is done by creating a hidden window and using Windows’ default message-
passing mechanism to ensure that all the method calls are serialized.
In the multithreaded apartment (MTA) model, each COM object must be multi-
thread-aware to ensure that no data corruption can arise as the result of two simul-
taneous calls from two distinct client threads. In recent versions of Windows,
Microsoft has added more threading models that are beyond the scope of this book.
Like Swing, SWT doesn’t contain any synchronization code to guard against
resource corruption due to concurrency. The rationale behind this decision is
that in most cases, the performance trade-off is too great to be justifiable. Conse-
quently, synchronization is entirely your responsibility. To avoid introducing syn-
chronization code, the SWT team chose to support only the STA threading model
where no special code is required; all synchronization issues are handled by the
COM runtime.
B.2 The SWT COM library
True to the general philosophy adopted for SWT, support for COM comes in the
form of a minimal amount of C code coupled with a series of Java classes building
on these foundations. The interesting side effect is that SWT COM programming is
very similar to C++ COM programming. This can be a double-edged sword. The
bonus is that whenever you’re in doubt about how to use a specific SWT feature,
you can look for help in the Microsoft documentation. The trade-off is that you’ll
sometimes be looking at unusual and nonintuitive Java code. As you get more
familiar with code from both languages, you’ll come to enjoy the outcome and
forget about the means.
In the following sections, we’ll cover the parts of the SWT COM library shown
in figure B.1. We’ll begin with a tour of the native language part of the library and
then look at the user-oriented Java classes that use it. The OleEventTable, Ole-
EventSink, and OlePropertyChangeSink classes are only visible inside the
org.eclipse.swt.ole.win32 package.
B.2.1 The native language support library
When you look at figure B.1, don’t be fooled by the names of the packages. The
code inside org.eclipse.swt.internal.ole.win32 isn’t just for SWT developers,
and you’ll often find yourself referring to it for advanced SWT COM applications.
332 APPENDIX B
OLE and ActiveX in SWT/JFace
The org.eclipse.swt.internal.ole.win32.COM class
As we discussed, the COM threading model supports several options. The COM
specification mandates that every thread that wants to use COM must first call the
runtime to specify a threading model. SWT performs this mandatory initialization
for you inside a static block located in the COM class. The default threading model
is apartment-threaded; therefore you don’t have to do anything special to ensure
that all calls to embedded COM objects are serialized.
The class has no constructor or instance members, but it contains a long
series of constants and static methods. The static methods are mostly native
methods named after their C equivalents. Their role is to expose the COM run-
time to Java. The method signature is often identical to the original Windows
Figure B.1 Core components of the SWT COM library
The SWT COM library 333
API. So, when in doubt, look at the original Microsoft documentation for expla-
nations and examples.
Half the constants are instances of another class from the same package. SWT
stores objects and interfaces unique identifiers using the GUID class For the most
part you need not concern yourself with GUID because it contains no methods.
However, it has an interesting public static final field named sizeof that con-
tains the size of the structure in bytes. The COM SWT code uses this pattern in all
classes that map to a native structure (more on this in section B.2.2).
Chances are, all the interfaces you’ll ever need to access are defined in COM as
public constants. The following examples were taken from the source code and
show how you should define any interface not already included:
public static final GUID IIDIUnknown =
IIDFromString("{00000000-0000-0000-C000-000000000046}");
public static final GUID IIDIDispatch =
IIDFromString("{00020400-0000-0000-C000-000000000046}");
IIDFromString() returns an instance of GUID based on the string representation
of an interface identifier. Similarly, CLSIDFromProgID() and CLSIDFromString() let
you find an object’s GUID from the same string representation or from the object’s
program identifier. To instantiate a COM object, you need to find either of these
two values. The IsEqualGUID() method lets you compare two GUIDs for identity,
which you need to do to implement the QueryInterface() when creating custom
COM interfaces.
The COM class also contains the low-level SWT code to access native drag and
drop: the RegisterDragDrop(), RevokeDragDrop(), and DoDragDrop() methods.
The latest version of SWT introduced a new cross-platform level of abstraction that
uses this code. More interestingly, the class lets you manipulate OLE storage files.
StgCreateDocfile() allows you to create a new file; StgIsStorageFile() lets you
test if a file is an OLE storage file; a call to ReleaseStgMediums() is necessary to
release the memory allocated by COM to an open storage file; and StgOpenStor-
age() is used to open a storage file.
If you’re familiar with Visual Basic, you know how simple it is to deal with
strings. This simplicity comes at a price for people programming with lower-level
languages. OLE strings, otherwise known as BSTR, can be manipulated using the
SysAllocString(), SysFreeString(), and SysStringByteLen() methods. Some-
times COM requires that newly allocated memory be placed under the control of
its runtime (often the case when dealing with automation) to allow sharing of that
memory between different process address spaces. You can use CoTaskMemAlloc()
334 APPENDIX B
OLE and ActiveX in SWT/JFace
and CoTaskMemFree(), respectively, to allocate or free blocks of memory compati-
ble with COM.
Several of the methods from the COM class come with multiple prototypes, due
to the strongly typed nature of Java. For example, the MoveMemory() method
comes in 16 different flavors, one for each of the main types of COM structures
you may have to manipulate. Keep in mind that using them takes you one step
closer to function pointers (and therefore dangerously closer to memory leaks)
than the makers of Java intended.
The most unconventional part of the COM class is a series of VtblCall() native
static methods with different parameter combinations. These cover the method
signatures for all the COM interfaces supported by SWT. The first two parameters
are the index of the method that needs to be called in the vtable followed by the
address of the table. The native code uses the index to find the address of the
method to call inside the vtable and calls it with the remaining parameters. In the
following example, int COM.VtblCall(int fnNumber, int ppVtbl, GUID arg0,
int[] arg1) is called to implement the QueryInterface() method from IUnknown:
public int QueryInterface(GUID riid, int ppvObject[]) {
return COM.VtblCall(0, address, riid, ppvObject);
}
The org.eclipse.swt.internal.ole.win32.COMObject class
Although it isn’t composed of native methods, the COMObject class belongs to the
lower level of the COM library. Its purpose is to provide a Java representation of
the vtable at the heart of every COM object. The class contains 80 public methods
with the same signature—public int methodXX(int[] args)—and an equal num-
ber of matching callbacks prototyped static int callbackXX(int[] callback-
Args). Each method is a placeholder for the matching method inside the vtable of
the COM interface.
By default, the 80 methodXX() methods return a constant called COM.E_NOTIMPL
that tells the caller that the method isn’t implemented. This avoids COM errors
and gives you room to implement complex COM interfaces. All COM interfaces
extend one another to form a hierarchy, and each level of inheritance translates
into an extension of the methods in the vtable. Provided that some of the stan-
dard COM interfaces are two or three levels down from IUnknown, the creators of
SWT have tried to anticipate future growth.
The class constructor is an array of int. Its size is the number of methods in
the vtable, and its content is the number of parameters each vtable method takes.
Be sure you don’t make any mistakes when you create this array, or you’ll be in for
The SWT COM library 335
difficult debugging and crashes. Internally, the constructor uses this information
to create an array of callbacks, one for each of the methods in the vtable. The
native layer uses these callbacks to invoke Java code when COM needs to invoke a
method from your interface.
Program identifiers revisited
Table B.5 contains the program identifiers for several common applications you
may encounter in your exploration of the SWT COM library.
If you don’t find the application you’re looking for, open the standard Microsoft Reg-
istry Editor that comes with Windows and look under the key My Computer\
HKEY_CLASSES_ROOT. It contains a list of IDs for all the applications installed on your
machine. Figure B.2 shows the program ID for the Web Browser control (the reus-
able part of Internet Explorer). Unless you have a specific reason not to do so, it’s
good practice to leave the terminating version number out of the name. COM uses
the CurVer key to find out which version is current and uses it automatically.
Microsoft created this mechanism to allow the transparent migration of appli-
cations. However, some vendors don’t follow this guideline; in this case you’ll have
Table B.5 Common program identifiers
Program identifier Description
Shell.Explorer Internet Explorer
Word.Application Microsoft Office Word application (as an out-of-process server)
Word.Document Microsoft Office Word document
Excel.Application Microsoft Office Excel application (as an out-of-process server)
Excel.Sheet Microsoft Office Excel document
Excel.Chart Microsoft Office Excel chart
PowerPoint.Show Microsoft Office PowerPoint presentation
Visio.Drawing Visio document
PDF.PdfCtrl.5 Adobe Acrobat PDF Reader 5.0
MediaPlayer.MediaPlayer Windows Media Player
Agent.Control Microsoft Agent control
DHTMLEdit.DHTMLEdit DHTML Edit control for IE5
InternetShortcut Internet shortcut
336 APPENDIX B
OLE and ActiveX in SWT/JFace
to keep the version number as an integral part of the name (see Adobe Acrobat in
the table B.5).
B.2.2 The Java COM library
The org.eclipse.swt.internal.ole.win32 and org.eclipse.swt.ole.win32 pack-
ages sit directly above the native library. The second package contains all the high-
level code necessary to write COM client code with SWT. As shown in figure B.1,
three classes consist of implementation details that aren’t exposed outside of the
package boundaries. OleEventTable() is a lookup mechanism that maps an event
type to a specific listener, and OleEventSink() is the heart of SWT’s ability to
receive and dispatch COM events to your code; it contains a partial IDispatch
implementation that can be a source of ideas for how to implement one yourself.
Note that the OLE class contains mostly constants and a utility method to convert
COM errors into SWT exceptions.
The org.eclipse.swt.internal.ole.win32.IUnknown class
By now you’re familiar with the role played by the IUnknown COM interface in the
discovery process of COM features. Even though it’s described as a COM interface,
the SWT team chose to implement it as a Java class. Its constructor takes one
parameter: int address. Its value is the address of the vtable containing the
implementation of the interface. All the methods of the COM IUnknown interface
are implemented as normal Java methods with parameters similar to those of the
native COM counterpart. These methods are implemented by calling COM.Vtbl-
Call() with all the parameters and the index of the native method in the vtable.
The following snippets show the implementation of QueryInterface() and
AddRef(), which are the first two physical methods in the IUnknown COM interface:
Figure B.2 The program ID for the reusable Web Browser control
The SWT COM library 337
public int QueryInterface(GUID riid, int ppvObject[]) {
return COM.VtblCall(0, address, riid, ppvObject);
}
public int AddRef() {
return COM.VtblCall(1, address);
}
Figure B.3 is a class diagram showing all the COM interfaces declared in the SWT
COM library. In section B.3.3, we explain how to add new interface declarations
when these aren’t enough.
The org.eclipse.swt.ole.win32.OleFrame class
To embed a COM object (ActiveX control or OLE document) in your SWT applica-
tion, you need to create a container window. As you’ve seen, COM mandates that
this container implement certain interfaces in order for the embedded object to
dialog with it. SWT provides the OleFrame class for that purpose. Although the
Figure B.3 COM interfaces derived from IUnknown
338 APPENDIX B
OLE and ActiveX in SWT/JFace
class is derived from Composite, it makes no sense to assign it a layout or try to add
Control children. The only reason for inheriting from Composite is to access the
window-management capabilities offered by Composite, in order to implement the
IOleInPlaceFrame COM interfaces.
Internally, OleFrame handles sizing, menu management, and window place-
ment. Looking at figure B.3, you’ll notice that IOleInPlaceFrame isn’t on the dia-
gram. SWT doesn’t require that you declare a COM interface (create a class
derived from IUnknown that lists all its methods) in order to implement it. All that
is required is that you create an instance of COMObject with public methods map-
ping the methods exposed by the COM interface.
When activated, OLE documents negotiate with the container to display their
menu bar. Using public methods from OleFrame, your application can contribute
menu items to the final menu bar. When adding menu items, you can choose
between three locations on the menu bar—File (on the far left), Container (in
the middle), or Window (far right, before Help)—by calling SetFileMenus(),
SetContainerMenus(), and SetWindowMenus(), respectively. All three methods take
an array of SWT MenuItem. Just before displaying the menu bar, the embedded
object calls IOleInPlaceFrame.InsertMenus(); at that point OleFrame merges your
items with those from the embedded object.
The org.eclipse.swt.ole.win32.OleClientSite class
The OleClientSite class implements a complete COM site. Aside from implement-
ing the mandatory IUnknown, IOleClientSite, and IAdviseSink, the class also imple-
ments in-place activation via the optional IOleInPlaceSite and IOleDocumentSite.
This class contains several useful public methods. doVerb() plays an important
role in the activation process, as you’ll see later. SaveFile() can be used to save
the current OLE document to a normal file (includeOleInfo = false) or to a
storage file (includeOleInfo = true). showProperties() lets you display all the
properties of the embedded COM object in a separate window, provided the
object implements the ISpecifyPropertyPages interface. The only control you
have over the window is its title, because it’s created by the COM runtime via a call
to the standard COM.OleCreatePropertyFrame().
queryStatus() is a helper method that accepts the ID of a command and
returns a bitwise OR’d combination of OLECMDF_SUPPORTED, OLECMDF_ENABLED, and
OLECMDF_LATCHED indicating the status of the specified command. This method is
usually called before a call to exec() to verify that the command is available
before executing it. Both functionalities are based on querying the embedded
The SWT COM library 339
object for its IOleCommandTarget interface and subsequently calling the QuerySta-
tus() or Exec() method on this interface.
You may be faced with situations where the site doesn’t implement some inter-
faces that are necessary to provide more control over the embedded COM object.
Fortunately, the SWT team structured the code in a way that makes it easy to
extend. You need to follow three rules:
1 The constructor of your derived class must call the parent constructor
before anything else.
2 You need to override the protected createCOMInterfaces (where you cre-
ate one COMObject instance for each COM interface you want your site to
support) and disposeCOMInterfaces (where you call the dispose()
method for each of the COMObject instances previously created).
3 You must ensure that your new QueryInterface() method properly dele-
gates to its parent (we present a complete example in section B.3.3).
The org.eclipse.swt.ole.win32.OleControlSite class
The OleControlSite class inherits from OleClientSite and provides the
extended capabilities necessary to host an ActiveX control. The visible differ-
ences from the parent class are full support for events and property change notifi-
cations from the ActiveX control, simplified access to well-known control
properties (straight method calls instead of COM automation calls), and direct
access to ambient properties.
You can access the container’s ambient properties via calls to the setSiteProp-
erty() and getSiteProperty() methods. For example, the Web Browser control
has properties that determine whether the browser should support embedded
ActiveX controls or JavaScript scripts. The font as well as color of the ActiveX con-
trol are accessible via setFont(), getFont(), setBackground(), getBackground(),
setForeground(), and getForeground().
addEventListener() allows you to register instances of OleListener in order to
receive specific events. You can register a single listener instance for several event
types, in which case your handler will probably contain an if statement based on
the value of OleEvent.type. Alternatively, you can register different listeners for
the various events your application needs to handle. When you’re no longer inter-
ested in receiving an event, don’t forget to call the removeEventListener()
method. Similar methods exist for receiving notifications about changes in the
value of a property.
340 APPENDIX B
OLE and ActiveX in SWT/JFace
The org.eclipse.swt.ole.win32.OleAutomation class
Dealing with dispatch interfaces (COM interfaces that extend IDispatch) can lead
to code that’s hard to read, involving many Variant instances copied to and from
arrays. OleAutomation provides a wrapper to manipulate the functionality deliv-
ered by the IDispatch COM interface. Two constructors are available. The first
takes an instance of OleClientSite (remember that OleControlSite extends Ole-
ClientSite, which guarantees that the class works for both ActiveX controls and
OLE documents) and uses package-level methods to obtain the client’s private
instance of the org.eclipse.swt.internal.ole.win32.IDispatch class. The sec-
ond constructor directly takes an instance of IDispatch as its unique parameter.
Both constructors acquire an ITypeInfo reference via a call to QueryInterface()
on the object.
Internally, this reference is used in the implementation of all the public meth-
ods involved in describing the dispatch interface. This gives you access to the com-
plete type library for the interface. The first method, getTypeInfoAttributes(),
returns a structure of type TYPEATTR that contains a high-level description of the
interface. The description includes such information as the interface GUID, the
number of variables it exposes, and its total number of methods. The following
code snippet shows how to access all the variables of an automation interface:
OleControlSite site = new OleControlSite(frame, SWT.NONE, progID);
OleAutomation auto = new OleAutomation(site);
TYPEATTR typeattr = auto.getTypeInfoAttributes();
if (typeattr != null && typeattr.cVars > 0) {
System.out.println("\n\nVariables for " + progID + " :\n");
for (int i = 0; i < typeattr.cVars; i++) {
OlePropertyDescription data = auto.getPropertyDescription(i);
System.out.println("PROPERTY (id = " + data.id + ") :"
+ "\n\tName : " + data.name + "\n\tType : "
+ getTypeName(data.type) + "\n");
}
}
Based on a program ID similar to those listed in table B.5, we create a control site
and then use it to create an OleAutomation wrapper.
The cVars field contains the number of variables exposed by the interface. Succes-
sive calls to getPropertyDescription() return OlePropertyDescription instances.
The class contains the description for an Automation property. Its type field con-
tains an OR’ed combination of the different variant types described in OLE.java
(OLE.VT_XXXX). Similarly, we could enumerate all the public methods of an inter-
face by calling the getFunctionDescription() method with successive integer val-
ues, provided this index remains inferior to typeattr.cFuncs.
b
Acquire
TYPEATTR
c
Loop over
properties
b
c
Doing COM with SWT 341
Besides providing a description of the interface, OleAutomation also contains
methods to simplify accessing the properties of the COM object (setProperty()
and getProperty()). As you may recall from the general discussion on COM and
automation, properties are exposed via public getters and setters rather than data.
Consequently, setProperty() and getProperty() are convenience wrappers
around the more general invoke() method. All automation calls into the object
ultimately translate into a call to IDispatch.Invoke() using one of the four stan-
dard dispatch codes (DISPATCH_XXXX constants from COM) as the fourth parameter.
Finally, getIDsOfNames() is a thin wrapper that simplifies calling GetIDsOfNames()
from the underlying IDispatch interface.
B.3 Doing COM with SWT
You should now have an idea about how to embed a COM object in an SWT-based
application. In this section, we’ll put this understanding to the test and write some
examples, as well as explore patterns that will help you write more complex code.
B.3.1 A simple example
Before we dive further into the full life cycle of a COM object embedded inside an
SWT container, we’ll write the simplest possible example. Despite its simplicity,
listing B.1 shows several important aspects of SWT COM programming. Its purpose
is to embed an instance of Internet Explorer inside a SWT frame and display the
home page of the Manning Publications web site.
package com.swtjface.AppB;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.ole.win32.*;
public class SimpleBrowser {
private Shell shell;
private OleAutomation automation;
public Shell open(Display display) {
this.shell = new Shell(display);
shell.setLayout(new FillLayout());
OleFrame frame = new OleFrame(shell, SWT.NONE);
OleControlSite controlSite =
new OleControlSite(frame, SWT.NONE, "Shell.Explorer");
automation = new OleAutomation(controlSite);
boolean activated =
Listing B.1 SimpleBrowser.java
342 APPENDIX B
OLE and ActiveX in SWT/JFace
(controlSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE) == OLE.S_OK);
this.openURL("html://www.manning.com/");
shell.open();
return shell;
}
public void openURL(String url) {
int[] rgdispid =
automation.getIDsOfNames(new String[]{"Navigate", "URL"});
int dispIdMember = rgdispid[0];
Variant[] rgvarg = new Variant[1];
rgvarg[0] = new Variant(url);
int[] rgdispidNamedArgs = new int[1];
rgdispidNamedArgs[0] = rgdispid[1];
Variant pVarResult =
automation.invoke(dispIdMember, rgvarg, rgdispidNamedArgs);
}
public static void main(String[] args) {
Display display = new Display();
Shell shell = (new SimpleBrowser()).open(display);
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
Creating a COM object
The first step creates the container where the COM object (ActiveX control or
OLE document) will be embedded. For that we instantiate an OleFrame, as follows:
Display display = new Display();
Shell shell = new Shell(display);
OleFrame frame = new OleFrame(shell, SWT.NONE);
SWT provides two site implementations, one for OLE documents (OleClientSite)
and one for ActiveX controls (OleControlSite). When in doubt about which to
use for a COM object you want to embed, look at its type library to see if it imple-
ments either the IOleDocument or IOleControl interface. To do so, you can use
Microsoft’s OLE View, which is distributed with all major development tools and
presented by msdn.microsoft.com (see figure B.4).
The constructor for OleClientSite lets you create a site based on a program ID
(see table B.5 for a list of program IDs for known applications) or a filename. In
the latter case, the shell does all the work of matching it to the corresponding
Doing COM with SWT 343
program ID based on the file extension. Behind the scenes, OleClientSite trans-
parently creates an instance of IStorage that it then passes to the object:
OleClientSite clientSite =
new OleClientSite(frame, SWT.NONE, "Word.Document");
File file = new File ("C:\\file1.doc");
OleClientSite clientSite =
new OleClientSite(frame, SWT.NONE, file);
Embedding an ActiveX control is much simpler and only involves creating an
instance of OleControlSite by passing its constructor the control’s program ID:
OleControlSite controlSite =
new OleControlSite(frame, SWT.NONE, "Shell.Explorer");
Activating an object
Creating an object isn’t enough to make it become visible inside its container. It
needs to be activated by the container. Activation is controlled by the doVerb()
method. Table B.6 lists all the possible values for the method’s unique parameter.
In most cases, you’ll us OLE.OLEIVERB_INPLACEACTIVATE to activate an ActiveX con-
trol in place. OLE documents work differently; the COM runtime must first start
Figure B.4 The type library for Internet Explorer displayed in Microsoft OLE View
344 APPENDIX B
OLE and ActiveX in SWT/JFace
the associated application and ask it on behalf of your container to open the doc-
ument in the site you supply.
People have reported trouble activating certain documents, particularly Microsoft
Office documents. In these cases, better results have been reported using
OLE.OLEIVERB_SHOW as the activation verb.
Also remember that OLE documents are complete applications hosted inside
your container. It’s a common mistake to activate an OLE document in a con-
tainer that doesn’t have a menu bar—some applications will forgive you, others
won’t. Remember: always create your application’s menu bar before activating an
OLE document, as in the following snippet.
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
Menu bar = new Menu(shell, SWT.BAR);
shell.setMenuBar(bar);
OleFrame frame = new OleFrame(shell, SWT.NONE);
OleClientSite clientsite;
try {
clientsite = new OleClientSite(frame, SWT.NONE, "PowerPoint.Slide");
shell.layout();
clientsite.doVerb(OLE.OLEIVERB_SHOW);
} catch (SWTException ex) {
System.out.println("Failed to create <> : " +
ex.getMessage());
return;
}
shell.open();
Table B.6 Standard verbs for manipulating OLE objects
ProgID Description
OLE.OLEIVERB_DISCARDUNDOSTATE Closes the OLE object and discards the undo state
OLE.OLEIVERB_HIDE Hides the OLE object
OLE.OLEIVERB_INPLACEACTIVATE Opens the OLE object for editing in place
OLE.OLEIVERB_OPEN Opens the OLE object for editing in a separate window
OLE.OLEIVERB_PRIMARY Opens the OLE object for editing (the action that occurs
when a user double-clicks on the object inside the container)
OLE.OLEIVERB_PROPERTIES Requests the OLE object properties dialog
OLE.OLEIVERB_SHOW Shows the OLE object
OLE.OLEIVERB_UIACTIVATE Activates the UI for the OLE object
Before activating
OLE document
Activation of Microsoft
Office OLE document
Doing COM with SWT 345
while (shell != null && !shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
Saving changes to an OLE document
At this point, we’ve successfully activated an OLE document inside an SWT con-
tainer, and the user would like to save her changes. The first step is to call isDirty()
from the OleClientSite to test that the file needs saving. When it is the case, we can
proceed to call the save() method, passing it a standard java.io.File instance and
a boolean indicating whether to save the file as a standard file (includeOleInfo =
false) or a storage file (includeOleInfo = true). It’s a good practice to save the
document to a temporary file and replace the original file only if the operation is
successful. The following snippet illustrates the process:
if (clientSite.isDirty()) {
File tempFile = new File(file.getAbsolutePath() + ".tmp");
file.renameTo(tempFile);
if (clientSite.save(file, true)){
// save was successful so discard the backup
tempFile.delete();
} else {
// save failed so restore the backup
tempFile.renameTo(file);
}
}
Disposing of an object
The examples we’ve looked at so far have been simple in the sense that the con-
tainer was only dealing with a single embedded object. However, nothing prevents
your container from embedding several objects. OLE documents negotiate with
their container about the content of the main menu toolbar. Consequently, your
container must implement a strict control over the activation process. You should
activate each COM object individually when doing so makes the most sense—for
example, upon receiving a mouse double-click event—and deactivate them
before activating the next one. To deactivate an object, call the deactivateIn-
PlaceClient() method from its OleClientSite.
When you’re done working with an embedded COM object, you must remem-
ber to perform one last task. The class diagram in figure B.1 showed that OleFrame,
OleClientSite, and OleControlSite are all subclasses of org.eclipse.swt.wid-
gets.Composite. As such, it’s imperative that you dispose of them by calling dis-
pose(). Unless you’ve saved all changes made to an OLE document prior to calling
dispose(), they will be lost.
346 APPENDIX B
OLE and ActiveX in SWT/JFace
Handling properties
To access automation properties, you must first get their dispatch identifier
(dispid) by calling getIDsOfNames() on the OleAutomation wrapper. You can use
the resulting int in subsequent calls to getProperty() or setProperty(). Also
keep in mind that all property values have the Variant type, which is the standard
automation data type. A common source of mistakes is improperly initializing a
variant by selecting the wrong type attributes, especially when dealing with vari-
ants that are references rather than contain data. The following snippet reads the
Document property from an automation server:
OleAutomation server = new OleAutomation(…);
int[]documentID = server.getIDsOfNames(new String[]{"Document"});
if (documentID == null) return null;
Variant pVarResult = server.getProperty(documentID[0]);
Interacting with an object
One of the compelling reasons for embedding COM objects (ActiveX controls or
OLE documents) in your application is the ability to inherit portions of the
object’s native user interface inside your own. However, this is only a small part of
the possible interactions.
Using the invoke() method from OleAutomation gives you access to the entire
object model of a COM component. Using it is a simple extension of what we did
to access a property. A call to getIDsOfNames() with the name of a command
returns its dispid, and once again all values have the Variant type. (Note that
dealing with Microsoft Word presents some unique problems: When you’re invok-
ing a command that doesn’t return a value, it’s preferable to use the invokeNoRe-
ply() method.)
SWT also gives you access to the event model of an embedded COM object by
registering instances of OleListener with an OleControlSite. You’ll have to dig
inside each type library to find the specific int value for the event you wish to sub-
scribe to. As we’ve discussed, you can either register the same listener for multiple
events or use distinct listeners for each event.
All handlers implement one unique method: void handleEvent(OleEvent
event). By reading the type library, you’ll find the number and type of parameters
associated with the event. SWT copies them into an array that’s publicly accessible
from the event as public Variant[] arguments. The parameters are ordered from
left to right in the prototype from the type library. For example, the following
information is from the Excel 10.0 type library. In this scenario, SeriesIndex
would be arguments[0] and PointIndex would be stored in arguments[1]:
Doing COM with SWT 347
dispinterface ChartEvents {
...
[id(0x00000602), helpcontext(0x00010602)]
void SeriesChange(
[in] long SeriesIndex,
[in] long PointIndex);
...
}
B.3.2 SWT COM programming patterns
What seems at first like a disconcerting way of writing Java code has identifiable
patterns that are repeated throughout. Understanding them is the key to writing
more serious COM-related code with SWT. Let’s review some of these patterns.
Null-terminated strings
In some instances, you’ll be forced to deal with the fact that C/C++ strings are ter-
minated by the null-end-of-string character (\0). This code snippet shows how to
create a null-terminated string from a Java String:
String lpsz = "This is a string";
char[] buffer = (lpsz +"\0").toCharArray();
The next snippet shows a way to turn a null-terminated string back into a Java
String. We hope that future versions of SWT will include a way to find the length
of a native string directly:
public static String getString(int addr) {
String str = null;
TCHAR buffer = new TCHAR (0, 256);
OS.MoveMemory (buffer, addr, 256);
str = buffer.toString(0, buffer.strlen());
return str;
}
Pointer to structure
A common situation in SWT Windows/COM programming has to do with han-
dling pointers. Typically you’ll deal with a pointer to a native Windows structure, a
pointer to a string, or a pointer to a native type. Many of the Windows APIs manip-
ulate 32-bit quantities that are pointers to complex data structures. The creators
of SWT mapped these structures to Java classes with public data members and no
methods. The many versions of MoveMemory() contain the necessary JNI code to
initialize the public data members of all the supported structures one field at a
time. As we previously discussed, each structure includes the following line of
code, where XXX is the size of the structure in bytes:
Assume String is shorter
than 256 characters
Trim excess characters
348 APPENDIX B
OLE and ActiveX in SWT/JFace
public static final int sizeof = XXX;
The pointers are mapped to Java int. In the following snippet, we use an int as a
pointer to a GUID and copy the data into an already allocated GUID object:
GUID guid = new GUID();
COM.MoveMemory(guid, riid, GUID.sizeof);
A typical misconception could lead you to declare only the guid variable and not
allocate the memory for the structure, which would cause a memory violation error.
Pointer to pointer to an interface
Another recognizable pattern in COM programming with SWT has to do with the
notion of pointers to pointers. Many COM methods take one or more parameters
that are pointers to interface pointers. In the following code snippet, we’re look-
ing at this coding pattern in the context of obtaining a temporary instance of
IStorage (similar code is invoked every time you create a new automation docu-
ment with SWT):
int[] tempStg = new int[1];
int grfMode = COM.STGM_READWRITE |
COM.STGM_SHARE_EXCLUSIVE |
COM.STGM_DELETEONRELEASE;
int result = CO .StgCreateDocfile(null, grfMode, 0, tmpStg);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_CANNOT_CREATE_FILE, result);
IStorage st = new IStorage(tmpStg [0])
An int array with a size of 1 is created. This is a pointer (the reference to the
array) to a pointer (the first value of the array).
The array is passed to a method that expects a pointer to a pointer to a COM interface.
All COM methods return an HRESULT: a 4-byte value where the sign bit is used to
communicate the presence/absence of an error. Errors are reported using the
static method error() defined in the org.eclipse.swt.internal.win32.OS class.
The method builds an error message based on the error code and throws an
SWTException. Note that SWTException extends RuntimeException; consequently,
the exception isn’t declared in any method signature, and handling it is left to
your discretion.
If there are no errors, the method initializes the first value of the array with the
address of the reference. All that’s left is to instantiate the proper IUnknown
derived class, which we do by passing the address to the constructor.
b Allocate int array
c Method call
d Status check
e Create reference
b
c
d
e
Doing COM with SWT 349
B.3.3 Advanced topics
Now that we’ve discussed the standard methods for incorporating COM inside SWT
code, it’s time to go further. This section will explain how to customize applications
with your own OLE/COM interfaces and QueryInterfaces. Then, we’ll investigate
more advanced data structures such as IDispatch parameters and SafeArrays.
Adding new interfaces to the org.eclipse.swt.internal.ole.win32 package
Despite the long list of interfaces supplied in the org.eclipse.swt.inter-
nal.ole.win32 package, you may need an interface that isn’t defined. Listing B.2
shows how to create a Java class that describes a COM interface. In the simpler
cases, your interface will inherit directly from IUnknown and add one or more
methods; our next example will show a slightly more complicated scenario.
package org.eclipse.swt.internal.ole.win32;
public class IPersistFile extends IPersist {
public IPersistFile(int address) {
super(address);
}
public int IsDirty() {
return COM.VtblCall(4, address);
}
public int Load(String szFileName, int dwMode) {
char[] fileName = (szFileName + "\0").toCharArray();
int pszFileName = 0;
COM.MoveMemory(pszFileName, fileName, 4);
return COM.VtblCall(5, address, pszFileName, dwMode);
}
public int Save(String szFileName, boolean fRemember) {
char[] fileName = (szFileName + "\0").toCharArray();
int pszFileName = 0;
COM.MoveMemory(pszFileName, fileName, 4);
return COM.VtblCall(6, address, pszFileName, fRemember);
}
public int SaveCompleted(int pszFileName) {
return COM.VtblCall(7, address, pszFileName);
}
public int GetCurFile() {
return COM.VtblCall(8, address);
}
}
According to the Microsoft documentation, IPersistFile extends IPersist, which
inherits from IUnknown. Before starting the implementation, we must count the
Listing B.2 IPersistFile.java
350 APPENDIX B
OLE and ActiveX in SWT/JFace
number of methods already implemented by the complete chain of parent inter-
faces. The index of the first new method is the total plus one: in this case, 4. IUnknown
contains three methods (index 0 to 2), and IPersist contains a single method
(index 3). For the sake of simplifying the code, it directly accesses the address field
from the IUnknown class. Unfortunately at this point address has package-only visi-
bility, which is the reason for the package declaration on the first line of the listing.
Alternatively, we could have replaced every reference to address with a call to the
public method getAddress(). Finally, notice that the body of the Save() and Load()
methods uses the null-terminated strings pattern we just described.
Implementing a known COM interface
Let’s walk through the steps of the complete implementation of a standard COM
interface. We’ll implement IDocHostUIHandler; the reason for this choice will
become evident at the end of this appendix.
COMObject contains a long list of empty methods. This is our first stop: We need
to create an instance that maps to the methods of IDocHostUIHandler. The follow-
ing snippet shows how to do this. Each of the interface’s methods is mapped to a
locally defined method of the Java class taking the same number of parameters as
its COM counterpart:
iDocHostUIHandler = new COMObject(new int[]{2, 0, 0, 4, 1, 5, 0,
0, 1, 1, 1, 3, 3, 2, 2, 1, 3, 2}) {
public int method0(int[] args)
{return QueryInterface(args[0], args[1]);}
public int method1(int[] args)
{return AddRef();}
public int method2(int[] args)
{return Release();}
public int method3(int[] args)
{return ShowContextMenu(args[0], args[1], args[2], args[3]);}
public int method4(int[] args)
{return GetHostInfo(args[0]);}
public int method5(int[] args)
{return ShowUI(args[0], args[1], args[2], args[3], args[4]);}
public int method6(int[] args)
{return HideUI();}
public int method7(int[] args)
{return UpdateUI();}
public int method8(int[] args)
{return EnableModeless(args[0]);}
public int method9(int[] args)
{return OnDocWindowActivate(args[0]);}
public int method10(int[] args)
{return OnFrameWindowActivate(args[0]);}
public int method11(int[] args)
b
Interface
signature
c Method
implementations
Doing COM with SWT 351
{return ResizeBorder(args[0], args[1], args[2]);}
public int method12(int[] args)
{return TranslateAccelerator(args[0], args[1], args[2]);}
public int method13(int[] args)
{return GetOptionKeyPath(args[0], args[1]);}
public int method14(int[] args)
{return GetDropTarget(args[0], args[1]);}
public int method15(int[] args)
{return GetExternal(args[0]);}
public int method16(int[] args)
{return TranslateUrl(args[0], args[1], args[2]);}
public int method17(int[] args)
{return FilterDataObject(args[0], args[1]);}
};
The Microsoft specification shows that IDocHostUIHandler contains 18 methods.
The array contains the number of input parameters for each of these 18 methods.
Method0() is mapped to a privately defined QueryInterface method that takes two
parameters. The rest of the code maps the other methods to other private meth-
ods while preserving the same ordering as in the COM interface definition.
Rolling your own QueryInterface
Of all the methods that you’ll implement when designing custom interface imple-
mentations, QueryInterface() presents the most difficulties. The following code
demonstrates several useful patterns for implementing your own:
protected int QueryInterface(int riid, int ppvObject) {
int result = super.QueryInterface(riid, ppvObject);
if (result == COM.S_OK)
return result;
if (riid == 0 || ppvObject == 0)
return COM.E_INVALIDARG;
GUID guid = new GUID();
COM.MoveMemory(guid, riid, GUID.sizeof);
if (COM.IsEqualGUID(guid, COM.IIDIDocHostUIHandler)) {
COM.MoveMemory(ppvObject,
new int[]{iDocHostUIHandler.getAddress()},
4);
AddRef();
return COM.S_OK;
}
COM.MoveMemory(ppvObject, new int[] {0}, 4);
return COM.E_NOINTERFACE;
}
b
c
b Signature
c Delegation
d
Check
requested
interface
QueryInterface must increment reference
count before returning interface
Return error-free status code
Clear pointer
352 APPENDIX B
OLE and ActiveX in SWT/JFace
In general, it’s a good idea to make all your COM interface implementation meth-
ods protected or with limited visibility, because these methods exist only so you
can call them in the context of your COM object. QueryInterface takes only two
parameters. In C++, riid is a reference to an interface ID that translates into a
Java int.
This implementation of QueryInterface was taken from a class extending OleCli-
entSite, for the purpose of creating an extended client site. This new site imple-
ments one more interface than the default OleClientSite. First, the code
attempts to delegate to the parent QueryInterface. If the parent returns S_OK,
then the interface was found and its address is already inside ppvObject. All that’s
left is to return the status code.
Next we must check that the GUID of the requested interface matches an inter-
face supported by this object. In this case, the new client site adds support for
COM.IIDIDocHostUIHandler. If the two GUIDs are identical, then we need to copy
the address of the private instance of the class that implements IDocHostUIHan-
dler to the result pointer.
Passing IDispatch references as parameters
A common situation may require that you pass a reference to an IDispatch as a
parameter to a method exposed by the COM object you host inside your applica-
tion. The following is the Interface Definition Language (IDL) description for a
method from the Microsoft Excel object model. The _Chart interface contains
the SetSourceData() method, which takes a Range pointer as its first parameter.
Looking at the object model also shows that the Range interface is derived from
IDispatch:
[id(0x00000585), helpcontext(0x00010585)]
void SetSourceData(
[in] Range* Source,
[in, optional] VARIANT PlotBy);
The proper way to invoke SetSourceData() consists of passing the range reference
as a byRef Variant, as follows:
{
Variant rangeVar = //execute some method on another automation object
IDispatch rangeDisp = rangeVar.getDispatch();
OleAutomation range = rangeVar.getAutomation();
rgdispid = chart.getIDsOfNames(new String[]{"SetSourceData",
"Source"});
int hGlobal = OS.GlobalAlloc(OS.GMEM_FIXED, 4);
OS.Memmove(hGlobal, new int[] {rangeDisp.getAddress()}, 4);
b
c
d
Obtain reference
to method
b
c
Check
requested
interface
Doing COM with SWT 353
int ptr = OS.GlobalLock(hGlobal);
Variant rangeRefVar =
new Variant(ptr, OLE.VT_BYREF | OLE.VT_DISPATCH);
chart.invoke(rgdispid[0],
new Variant[]{rangeVar},
new int[]{rgdispid[1]});
}
As usual, we must get the method’s dispid from its name.
We create a pointer to the Range reference by allocating 4 bytes of memory and
copying the address of Range to it.
Using our new pointer to the Range, we can create a new Variant using the
OLE.VT_BYREF | OLE.VT_DISPATCH style. VT_BYREF indicates that the variant con-
tains a pointer to something, and VT_DISPATCH indicates that the something is an
IDispatch reference.
Anatomy of a storage file
The example in listing B.3 shows how to explore the content of a storage file. The
code also shows how to use a class derived from IEnum to perform an enumeration.
package com.swtjface.AppB;
import java.io.File;
import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.ole.win32.*;
public class Storage {
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java Storage ");
return;
}
String fileName = args[0];
parseFile(new File(fileName));
}
public static void parseFile(File file) {
char[] fileName = (file.getAbsolutePath() + "\0").toCharArray();
IStorage storage = null;
if (COM.StgIsStorageFile(fileName) == COM.S_OK) {
int mode = COM.STGM_READ | COM.STGM_TRANSACTED |
COM.STGM_SHARE_EXCLUSIVE;
int[] address = new int[1];
int result = COM.StgOpenStorage(fileName, 0, mode, 0, 0, address;
if (result != COM.S_OK)
Listing B.3 Storage.java
d Create
variant
b
c
d
Method takes null-
terminated string
Get IStorage reference (pointer in address[0])
354 APPENDIX B
OLE and ActiveX in SWT/JFace
OLE.error(OLE.ERROR_CANNOT_OPEN_FILE, result);
storage = new
IStorage(address[0]);
int[] ppEnum = new int[1];
result = storage.EnumElements(0, 0, 0, ppEnum);
if (result != COM.S_OK)
OLE.error(OLE.ERROR_ACTION_NOT_PERFORMED, result);
IEnumSTATSTG enum = new IEnumSTATSTG(ppEnum[0]);
// loop over the file content
int rgelt = OS.GlobalAlloc(OS.GMEM_FIXED | OS.GMEM_ZEROINIT,
STATSTG.sizeof);
int[] pceltFetched = new int[1];
enum.Reset();
while (enum.Next(1, rgelt, pceltFetched) == COM.S_OK
&& pceltFetched[0] == 1) {
STATSTG statstg = new STATSTG();
COM.MoveMemory(statstg, rgelt, STATSTG.sizeof);
System.out.println(getString(statstg.pwcsName));
}
OS.GlobalFree(rgelt);
enum.Release();
storage.Release();
}
}
public static String getString(int addr) {
String str = null;
TCHAR buffer = new TCHAR (0, 256);
OS.MoveMemory (buffer, addr, 256);
str = buffer.toString(0, buffer.strlen());
return str;
}
}
Looking inside a SafeArray
When Microsoft needed to add support for arrays to automation, it created the
notion of SafeArray: a structure that describes the characteristics of an array and
holds its data. Dealing with SafeArrays was deemed complicated enough that
Microsoft created a specific API for that purpose. For memory, the anatomy of a
SafeArray is as follows (the offset and size information will help you understand
the code that follows):
typedef struct tagSAFEARRAYBOUND {
ULONG cElements; // offset 0, size 4
LONG lLbound; // offset 4, size 4
} SAFEARRAYBOUND;
typedef struct tagSAFEARRAY {
Dereference pointer; get IStorage
Get
IEnumSTATSTG
Access STATSTG
structure one
at a time
Release
interfaces
Doing COM with SWT 355
USHORT cDims; // offset 0, size 2
USHORT fFeatures; // offset 2, size 2
ULONG cbElements; // offset 4, size 4
ULONG cLocks; // offset 8, size 4
PVOID pvData; // offset 12, size 4
SAFEARRAYBOUND rgsabound[ ... ]; // offset 16
} SAFEARRAY;
Unfortunately there is currently no special support for SafeArray in SWT. How-
ever, based on the C definition of the SafeArray structure, it’s possible to display
their content. The following is an extract from the type library for the Web
Browser ActiveX control:
interface DWebBrowserEvents : IUnknown {
...
[helpstring("Fired when a new hyperlink is being navigated to.")]
HRESULT _stdcall BeforeNavigate(
[in] BSTR URL, long Flags, BSTR TargetFrameName,
VARIANT* PostData,
BSTR Headers, [in, out] VARIANT_BOOL* Cancel);
...
}
The Microsoft web site states that PostData (parameter number 4) is a Variant that
contains a reference to a Variant that is itself a SafeArray. The following code uses
some of the simpler patterns we reviewed to parse the content of an array:
public void handleEvent(OleEvent event) {
Variant varPostData = event.arguments[4];
int pPostData = varPostData.getByRef();
short[] vt_type = new short[1];
OS.MoveMemory(vt_type, pPostData, 2);
if (vt_type[0] == (short)(OLE.VT_BYREF | OLE.VT_VARIANT)) {
int[] pVariant = new int[1];
OS.MoveMemory(pVariant, pPostData + 8, 4);
vt_type = new short[1];
OS.MoveMemory(vt_type, pVariant[0], 2);
if (vt_type[0] == (short)(OLE.VT_ARRAY | OLE.VT_UI1)) {
int[] pSafearray = new int[1];
OS.MoveMemory(pSafearray, pVariant[0] + 8, 4);
short[] cDims = new short[1];
OS.MoveMemory(cDims, pSafearray[0], 2);
System.out.println("total dimensions= "+cDims[0]);
int[] pvData = new int[1];
OS.MoveMemory(pvData, pSafearray[0] + 12, 4);
int offset = 0; int arrayboundOffset = 0;
for (int i = 0; i < cDims[0]; i++) {
int[] cElements = new int[1];
Check second
Variant type:
SafeArray of
unsigned char
Establish pointer
to SafeArray
Iterate through dimensions
356 APPENDIX B
OLE and ActiveX in SWT/JFace
OS.MoveMemory(cElements,pSafearray[0]+16+arrayboundOffset,4);
arrayboundOffset += 8;
System.out.println("dim "+i+" has "+cElements[0]+"elements");
for (int j = 0; j < cElements[0]; j++) {
char[] ui1_data = new char[1];
OS.MoveMemory(ui1_data, pvData[0]+offset, 1);
System.out.println("data at "+j+" is "+ui1_data[0]);
offset += 1;
}
}
}
}
}
B.3.4 A final example
Let’s work on something more elaborate that brings together everything we’ve
covered so far. The enhanced version of our SimpleBrowser from listing B.1,
shown in listing B.4, is now capable of displaying a personalized context menu as
well as saving the content of the page to a file.
package com.swtjface.AppB;
import org.eclipse.swt.SWT;
import org.eclipse.swt.internal.ole.win32.*;
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.ole.win32.*;
import org.eclipse.swt.widgets.*;
public class BetterBrowser {
private Shell shell;
private OleAutomation automation;
static final int DocumentComplete = 104;
static final int NavigateComplete = 101;
private int globalDispatch;
public Shell open(Display display) {
this.shell = new Shell(display);
shell.setLayout(new FillLayout());
OleFrame frame = new OleFrame(shell, SWT.NONE);
OleControlSite controlSite = new ExtWebBrowser(frame, SWT.NONE,
"Shell.Explorer");
automation = new OleAutomation(controlSite);
boolean activated =
First 4 bytes of SafeArrayBound: number of elements
Jump to next SafeArrayBound
Listing B.4 BetterBrowser.java
Doing COM with SWT 357
(controlSite.doVerb(OLE.OLEIVERB_INPLACEACTIVATE) == OLE.S_OK);
OleListener listener = new OleListener() {
public void handleEvent(OleEvent event) {
switch (event.type) {
case DocumentComplete : {
Variant varResult = event.arguments[0];
IDispatch dispatch = varResult.getDispatch();
Variant variant = new Variant(automation);
IDispatch top = variant.getDispatch();
varResult = event.arguments[1];
String url = varResult.getString();
if (globalDispatch != 0 && dispatch.getAddress()
== globalDispatch) {
/* final document complete */
globalDispatch = 0;
}
System.out.println("DocComplete");
break;
}
case NavigateComplete : {
Variant varResult = event.arguments[0];
IDispatch dispatch = varResult.getDispatch();
if (globalDispatch == 0)
globalDispatch = dispatch.getAddress();
System.out.println("NavComplete");
break;
}
}
Variant[] arguments = event.arguments;
for (int i = 0; i < arguments.length; i++)
arguments[i].dispose();
}
};
controlSite.addEventListener(DocumentComplete, listener);
controlSite.addEventListener(NavigateComplete, listener);
this.openURL("http://www.manning.com");
shell.open();
return shell;
}
public void openURL(String url) {
int[] rgdispid = automation.getIDsOfNames
(new String[]{"Navigate", "URL"});
int dispIdMember = rgdispid[0];
Variant[] rgvarg = new Variant[1];
rgvarg[0] = new Variant(url);
int[] rgdispidNamedArgs = new int[1];
rgdispidNamedArgs[0] = rgdispid[1];
Variant pVarResult = automation.invoke(dispIdMember, rgvarg,
rgdispidNamedArgs);
}
358 APPENDIX B
OLE and ActiveX in SWT/JFace
public static void main(String[] args) {
Display display = new Display();
Shell shell = (new BetterBrowser()).open(display);
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
public OleAutomation getHtmlDocument(OleAutomation browser) {
int[] htmlDocumentID =
browser.getIDsOfNames(new String[]{"Document"});
if (htmlDocumentID == null) return null;
Variant pVarResult = browser.getProperty(htmlDocumentID[0]);
if (pVarResult == null || pVarResult.getType() == 0) return null;
//IHTMLDocument2
OleAutomation htmlDocument = pVarResult.getAutomation();
return htmlDocument;
}
class ExtWebBrowser extends OleControlSite {
COMObject iDocHostUIHandler;
public ExtWebBrowser(Composite parent, int style, String progId) {
super(parent, style, progId);
}
protected void createCOMInterfaces () {
super.createCOMInterfaces();
iDocHostUIHandler =
new COMObject(new int[]{2, 0, 0, 4, 1, 5, 0, 0, 1,
1, 1, 3, 3, 2, 2, 1, 3, 2}){
public int method0(int[] args)
{return QueryInterface(args[0], args[1]);}
public int method1(int[] args) {return AddRef();}
public int method2(int[] args) {return Release();}
public int method3(int[] args)
{return ShowContextMenu(args[0], args[1], args[2],
args[3]);}
public int method4(int[] args)
{return GetHostInfo(args[0]);}
public int method5(int[] args)
{return ShowUI(args[0], args[1], args[2], args[3],
args[4]);}
public int method6(int[] args) {return HideUI();}
public int method7(int[] args) {return UpdateUI();}
public int method8(int[] args)
{return EnableModeless(args[0]);}
public int method9(int[] args)
Doing COM with SWT 359
{return OnDocWindowActivate(args[0]);}
public int method10(int[] args)
{return OnFrameWindowActivate(args[0]);}
public int method11(int[] args)
{return ResizeBorder(args[0], args[1], args[2]);}
public int method12(int[] args)
{return TranslateAccelerator(args[0], args[1], args[2]);}
public int method13(int[] args)
{return GetOptionKeyPath(args[0], args[1]);}
public int method14(int[] args)
{return GetDropTarget(args[0], args[1]);}
public int method15(int[] args)
{return GetExternal(args[0]);}
public int method16(int[] args)
{return TranslateUrl(args[0], args[1], args[2]);}
public int method17(int[] args)
{return FilterDataObject(args[0], args[1]);}
};
}
protected void disposeCOMInterfaces() {
super.disposeCOMInterfaces();
if (iDocHostUIHandler != null)
iDocHostUIHandler.dispose();
iDocHostUIHandler = null;
}
protected int QueryInterface(int riid, int ppvObject) {
int result = super.QueryInterface(riid, ppvObject);
if (result == COM.S_OK)
return result;
if (riid == 0 || ppvObject == 0)
return COM.E_INVALIDARG;
GUID guid = new GUID();
COM.MoveMemory(guid, riid, GUID.sizeof);
if (COM.IsEqualGUID(guid, COM.IIDIDocHostUIHandler)) {
COM.MoveMemory(ppvObject, new int[]
{iDocHostUIHandler.getAddress()}, 4);
AddRef();
return COM.S_OK;
}
COM.MoveMemory(ppvObject, new int[]{0}, 4);
return COM.E_NOINTERFACE;
}
//~- IDocHostUIHandler -----------------------------
int EnableModeless(int EnableModeless) {
return COM.E_NOTIMPL;
}
int FilterDataObject(int pDO, int ppDORet) {
return COM.E_NOTIMPL;
}
int GetDropTarget(int pDropTarget, int ppDropTarget) {
360 APPENDIX B
OLE and ActiveX in SWT/JFace
return COM.E_NOTIMPL;
}
int GetExternal(int ppDispatch) {
return COM.E_NOTIMPL;
}
int GetHostInfo(int pInfo) {
return COM.E_NOTIMPL;
}
int GetOptionKeyPath(int pchKey, int dw) {
return COM.E_NOTIMPL;
}
int HideUI() {
return COM.E_NOTIMPL;
}
int OnDocWindowActivate(int fActivate) {
return COM.E_NOTIMPL;
}
int OnFrameWindowActivate(int fActivate) {
return COM.E_NOTIMPL;
}
int ResizeBorder(int prcBorder, int pUIWindow, int fFrameWindow) {
return COM.E_NOTIMPL;
}
int ShowContextMenu(int dwID, int ppt,
int pcmdtReserved, int pdispReserved) {
int [] pts = new int[2];
OS.MoveMemory(pts, ppt, 8);
System.out.println(dwID);
Menu menu = new Menu (shell, SWT.POP_UP);
MenuItem item = new MenuItem (menu, SWT.PUSH);
item.setText ("Save Source");
item.addListener (SWT.Selection, new Listener () {
public void handleEvent (Event e) {
System.out.println ("Save Selected");
if (globalDispatch != 0) {
IUnknown iuk = new IUnknown(globalDispatch);
int[] ppvObject = new int[1];
if (iuk.QueryInterface(COM.IIDIPersistFile, ppvObject)
== COM.S_OK) {
IPersistFile pf = new IPersistFile(ppvObject[0]);
pf.Save("c:\\test.html", false);
pf.Release();
}
}
}
});
item = new MenuItem (menu, SWT.PUSH);
item.setText ("View Source");
item.addListener (SWT.Selection, new Listener () {
public void handleEvent (Event e) {
Doing COM with SWT 361
System.out.println ("View Selected");
}
});
menu.setLocation (pts[0], pts[1]);
menu.setVisible (true);
Display display = getShell().getDisplay();
while (!menu.isDisposed () && menu.isVisible ()) {
if (!display.readAndDispatch ()) display.sleep ();
}
menu.dispose ();
return COM.S_OK;
}
int ShowUI(int dwID, int pActiveObject, int pCommandTarget,
int pFrame,int pDoc) {
return COM.E_NOTIMPL;
}
int TranslateAccelerator(int lpMsg, int pguidCmdGroup,
int nCmdID) {
Menu menubar = getShell().getMenuBar();
if (menubar != null && !menubar.isDisposed()
&& menubar.isEnabled()) {
Shell shell = menubar.getShell();
int hwnd = shell.handle;
int hAccel = OS.SendMessage(hwnd, OS.WM_APP + 1, 0, 0);
if (hAccel != 0) {
MSG msg = new MSG();
OS.MoveMemory(msg, lpMsg, MSG.sizeof);
if (OS.TranslateAccelerator(hwnd, hAccel, msg) != 0)
return COM.S_OK;
}
}
return COM.S_FALSE;
}
int TranslateUrl(int dwTranslate, int pchURLIn, int ppchURLOut) {
return COM.E_NOTIMPL;
}
int UpdateUI() {
return COM.E_NOTIMPL;
}
}
}
362
Changeable GUIs
with Draw2D
Understanding Draw2D 363
The SWT/JFace toolset has two shortcomings that we haven’t addressed. The
first involves building truly custom widgets. Because it relies on native widgets,
SWT/JFace makes it difficult to extend the Control class. So, you can’t create
your own components.
SWT/JFace’s second deficiency involves building graphical editors. These appli-
cations are similar to normal GUIs, but they allow you to manipulate diagrams and
save their models to a file. Generally, these diagrams represent large systems, like
those found in Computer-Aided Design (CAD), Unified Modeling Language
(UML) software, and graphical software development tools such as Microsoft’s
Visual Studio. With great pains, SWT/JFace can be used to build a graphical edi-
tor, but the toolset wasn’t designed for this purpose. We need a tool that specifi-
cally addresses the requirements of building graphical editors.
In response to these concerns, the Eclipse designers created the Draw2D and
Graphical Editing Framework (GEF) libraries. The Draw2D tool lets you render
GUI components with whatever appearance and functionality you prefer. It pro-
vides this capability by creating a high-level drawing region that operates indepen-
dently from the native platform. The GEF library combines these Draw2D figures
into a framework suitable for graphical editing.
This appendix presents Draw2D, and appendix D covers GEF. Because GEF
requires Draw2D to provide its graphics, these two appendices can be taken as a
whole. Old-fashioned at heart, we’ll present these toolsets in the context of build-
ing a flowchart editor. Our first step involves creating the graphical region and the
shapes needed to represent different types of operation. This is a job for Draw2D.
C.1 Understanding Draw2D
The Draw2D library provides a great deal of freedom in generating custom com-
ponents, but you pay a price in the amount of code needed to implement them.
Draw2D relies on many constructs from SWT (not JFace), but you must draw and
design most of the graphical components within it. You also need to specify their
event responses and any drag-and-drop capability. Essentially, the Draw2D library
serves as a complete graphics package, with the additional feature that these
graphics can be moved and associated with events.
This section begins the discussion by providing an overview of Draw2D’s cen-
tral classes and their functions. Then, we’ll intersperse theoretical discussion with
the development of the flowchart’s graphics. We’ll cover the drag-and-drop capa-
bility as well as the process of adding Connector objects between shapes. Let’s start
with the basics.
364 APPENDIX C
Changeable GUIs with Draw2D
C.1.1 Using Draw2D’s primary classes
If you’ve understood our discussion of SWT so far, then Draw2D won’t present
much difficulty. As shown in table C.1, the two libraries use related classes and
provide similar structures for drawing, event handling, and component layout. In
fact, all Draw2D GUIs must be added to an SWT Canvas. The first difference is that
whereas a normal Canvas adds a GC object to provide graphics, a Canvas in a
Draw2D application uses an instance of a LightweightSystem.
LightweightSystems function similarly to Display objects in SWT. They have no
visual representation but provide event handling and interaction with the exter-
nal environment. As the name implies, LightweightSystems operate at a level
removed from the operating system. This means you lose the advantages of SWT/
JFace’s heavyweight rendering, such as its rapid execution and native look and
feel. However, now you can truly customize the appearance and operation of
your components.
Without question, the most important class in Draw2D is the Figure, and the
majority of our Draw2D discussion will focus on its methods and subclasses. Like
an SWT Shell, it must be added to a LightweightSystem in order to provide a basis
for the GUI’s appearance. Like an SWT Control, it provides for resizing and relo-
cating, adding Listeners and LayoutManagers, and setting colors and fonts. It also
functions like a Composite in SWT, providing methods for adding and removing
other Figure objects—children—within its frame. This is shown in figure C.1.
However, unlike Widget and Control objects, you can easily subclass Figures.
Their graphical aspects can be represented by a drawing or image. Not only can
Table C.1 Three primary classes of the Draw2D library
Class Function Similar SWT class
LightweightSystem High-level environment for rendering images Display
Figure Component or container within a Light-
weightSystem object
Shell, Control, Composite
Graphics Provides a graphical region within a Figure GC
Graphics
Figure
Graphics
Figure
Graphics
Figure
Container Figure
Lightweight System
Canvas
Figure C.1
Class relationships within
Draw2D user interfaces
Understanding Draw2D 365
Figures use separate Listener interfaces, they can also perform the majority of
their event handling by themselves. Figures can even initiate specific kinds of
events to alert other objects in the GUI.
To add images and drawings to Figures, you need to use instances of the
Graphics class. It functions similar to SWT’s GC (graphics context) class, and it pro-
vides methods for incorporating graphics in a given area. It also contains many of
the same methods as GC, particularly for drawing lines and shapes, displaying
images, and working with fonts. However, the Graphics class provides one very dif-
ferent capability: Its objects can be moved, or translated, within the Lightweight-
System. This means that when you want to change the position of a graphical
component, Draw2D provides its own drag-and-drop capability to translate a Fig-
ure to the desired location.
C.1.2 The Flowchart application
UML has long been preeminent in modeling soft-
ware, but flowcharts are still helpful in depicting
sequential operations within a program. Our
Draw2D example focuses on drawing a simple flow-
chart, as shown in figure C.2.
This appendix provides the code needed to cre-
ate this figure in Draw2D. Appendix D will show
you how to build a full flowchart editor based on
the Figures we build here.
At the time of this writing, the Draw2D/GEF
plug-ins aren’t included in Eclipse and must be
downloaded separately. Currently, you can acquire
the GEF Software Development Kit (SDK) from
www.eclipse.org/gef. This file, which contains the
GEF and the Draw2D libraries, can be quickly inte-
grated by placing it in the $ECLIPSE directory and
decompressing its contents. Doing so will place the
Draw2D/GEF plug-ins in the $ECLIPSE/plugins directory and their features in the
$ECLIPSE/features directory.
Because the code in this appendix is lengthy, we recommend that you down-
load our files from the Manning web site (www.manning.com/scarpino). However,
if you intend to build your own application, start by adding a com.swtjface.AppB
package to the WidgetWindow project. Then, create a classpath variable,
Figure C.2
A simple flowchart. Not much
help for complex projects, but
always good for nostalgia.
366 APPENDIX C
Changeable GUIs with Draw2D
Draw2D_LIB, pointing to $ECLIPSE/plugins/org.eclipse.draw2d_x.y.z/draw2d.jar.
Add this variable to the project.
The Draw2D library incorporates many classes and capabilities, and this
appendix can’t cover every facet of its operation. Therefore, we’ll concentrate on
those classes that perform the main work of the toolset. This means investigating
the Figure class and its subclasses in greater depth.
C.2 Draw2D Figures
As you’ll see, it takes a fair amount of code to build a Draw2D GUI. However,
unlike those in an SWT/JFace GUI, Draw2D elements can be moved and manipu-
lated. These components, including the overall container, are descendents of
Draw2D’s main class, Figure. This class contains a number of subclasses that pro-
duce the visual aspects of the toolset’s GUI. Figure C.3 shows a small but impor-
tant subset.
These subclasses will be used extensively in the flowchart editor, particularly those
involving Connections and Layers. But first, we need to explore Figures in general.
Figure
Clickable Label Layer ScrollPane Shape
Button Toggle LayeredPane FreeformLayer
PolyLine
PolyLine
Connection
Freeform
LayeredPane
Scalable
LayeredPane ConnectionLayer Connection
Figure C.3 The Draw2D Figure class and a portion of its subclasses. Many of these play
an important role in the flowchart editor presented in appendix D.
Draw2D Figures 367
C.2.1 Figure methods
Like the SWT Control class, the Figure class contains many methods for manipu-
lating its properties. We can’t describe all 137 of them, but we can divide them
into four main categories:
■ Working with the Figure’s visual aspects
■ Event handling
■ Keeping track of parents and children
■ Managing graphics
If you’ve come this far, then you can probably figure out all you need to know
from the Draw2D Javadocs. However, we’ll provide a brief description of these cat-
egories here.
Working with a Figure’s visual aspects
The methods in the first category are exactly like those in SWT. These include get-
ting and setting the Figure’s bounds, location, and size. The Figure’s maximum
and minimum size can be controlled as well as its border size and visible area.
This category also provides methods for changing the Figure’s foreground and
background color and getting/setting its focus and visibility parameters.
Event handling in Draw2D
The process of handling events in Draw2D is also similar to SWT, but it provides a
few new events and listeners. Unlike SWT, Figures can handle many of their own
events. The entire list of listeners and their handling methods is shown in
table C.2.
Table C.2 Figure methods for event listening and handling
Draw2D listener Event-handling method(s)
addFocusListener() handleFocusGained()
handleFocusLost()
addKeyListener() handleKeyPressed()
handleKeyReleased()
addMouseListener() handleMouseDoubleClicked()
handleMousePressed()
handleMouseReleased()
continued on next page
368 APPENDIX C
Changeable GUIs with Draw2D
The first five methods look and act just like those in SWT, with addListener()
receiving untyped Events. But the last three methods are unique to Draw2D.
The addAncestorListener() method responds to any changes to the Figure’s
ancestors and functions like the Swing implementation. Similarly, the FigureLis-
tener responds whenever the Figure is moved.
The last method, addPropertyChangeListener(), lets you create your own
events. This process starts by associating a property, such as a Figure’s location, with
a String descriptor. Then, when firePropertyChange() is invoked with this String,
any PropertyChangeListeners listening for this property change respond. We’ll
revisit this subject in greater depth when we discuss the GEF and its model classes.
Parent and child Figures
SWT and JFace allow components to be included in other components by provid-
ing a Composite class. But in Draw2D, any Figure can be a container, and any Fig-
ure can be contained. Therefore, Draw2D uses the term parent to refer to the
outer graphic and child to refer to the graphic contained within. You create and
manipulate these relationships with the methods listed in table C.3.
addMouseMotionListener() handleMouseDragged()
handleMouseEntered()
handleMouseExited()
handleMouseHovered()
handleMouseMoved()
addListener() N/A
addAncestorListener() N/A
addFigureListener() N/A
addPropertyChangeListener() N/A
Table C.3 Parent/child methods of the Figure class
Method Function
add(Figure, Object, int) Adds a child Figure with the given constraint and
List index
getChildren() Returns a List of child Figures
continued on next page
Table C.2 Figure methods for event listening and handling (continued)
Draw2D listener Event-handling method(s)
Draw2D Figures 369
In SWT, Buttons and Labels add themselves to Composites by identifying parents in
their constructors. In Draw2D, a parent Figure uses its add() method to include
Figures in its List of children. This method can include an optional constraint
(such as the child’s size or location) and/or an index in the parent’s List. Parent
Figures can obtain this List with the getChildren() method, and children can
access their parent with getParent(). Parents can also enable or disable children
with setChildrenEnabled() or alter an aspect of the child with setConstraint().
Managing graphics
Although Draw2D provides a Graphics class that performs most of the duties of
SWT’s GC, Figures have a few graphical methods of their own. Not only can they
control their display with paint(), they can also use paintBorder() and paintCli-
entArea() to select which section to show. Figures can display their children with
paintChildren() or use paintFigure() to only show themselves. There are also a
number of repaint() methods available, which work similarly to those in SWT.
Draw2D contains methods for finding information about the user’s selection
location. This is different from SWT because Draw2D is particularly concerned
with precise mouse movements, whereas an SWT GUI is only concerned about the
selected Control. These methods include FindMouseEventAt(), FindFigureAt(),
and FindFigureAt().
C.2.2 Using Labels and Clickables
The first Figure subclasses for our investigation are the simplest: Labels and
Clickables. These objects look and act similarly to their SWT counterparts, but
there are a few interesting concerns that you need to keep in mind.
Labels
Draw2D Labels resemble those of SWT but contain more methods for text mea-
surement and image location. You can measure the parameters of the Label’s
String through getTextBounds() and getTextLocation(). Similarly, if the Label is
getParent() Returns the Figure’s parent Figure
setChildrenEnabled(boolean) Enables or disables the Figure’s children
setConstraint(Figure, Object) Sets a constraint for the given child Figure
Table C.3 Parent/child methods of the Figure class (continued)
Method Function
370 APPENDIX C
Changeable GUIs with Draw2D
associated with an Image, then getIconBounds() and getIconAlignment() will pro-
vide information about the Image.
Clickables
This class, which includes Buttons and Toggles, provides binary information con-
cerning the user’s preferences. Like SWT Buttons, they can be configured with
style bits to appear like toggle buttons, checkboxes, or regular pushbuttons. You
can also control their selection and add images or text. But there are two main
differences between Draw2D Clickables and SWT Buttons. The first is that Click-
ables can take the appearance of any Draw2D Figure. The second has to do with
Clickable event handling.
Draw2D user interfaces are generally more complex than those created with
SWT and JFace. Therefore, a Clickable’s state information is managed by a But-
tonModel or ToggleModel object. This separates the component’s appearance from
its behavior and enables you to develop the two aspects independently. You can
also contain these Model objects in a ButtonGroup, which manages multiple Click-
ables at once.
Clickables update their Model objects by calling fireChangeEvent(), which
works like the Figure’s firePropertyChangeEvent(). Clickable properties, such as
MOUSEOVER_PROPERTY and PRESSED_PROPERTY, are represented by constants in the
Model class. When they change, the Model may fire a number of Draw2D events or
inform its ButtonGroup by default.
Example application
The code in listing C.1 won’t be used in our flowchart editor, but it shows how
Draw2D Clickables, Models, and ButtonGroups work together. In this case, we use
the CheckBox subclass of Clickable and associate it with a ToggleModel.
package com.swtjface.AppC;
import org.eclipse.swt.widgets.*;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.Label;
import org.eclipse.draw2d.geometry.*;
public class Draw2D_Example
{
public static void main(String args[])
{
final Label label = new Label("Press a button!");
Shell shell = new Shell();
Listing C.1 Draw2D_Example.java
Draw2D Figures 371
LightweightSystem lws = new LightweightSystem(shell);
Figure parent = new Figure();
parent.setLayoutManager(new XYLayout());
lws.setContents(parent);
Clickable above = new CheckBox("I'm above!");
parent.add(above, new Rectangle(10,10,80,20));
ButtonModel aModel = new ToggleModel();
aModel.addChangeListener(new ChangeListener()
{
public void handleStateChanged(ChangeEvent e)
{
label.setText("Above");
}
});
above.setModel(aModel);
Clickable below = new CheckBox("I'm below!");
parent.add(below, new Rectangle(10,40,80,20));
ButtonModel bModel = new ToggleModel();
bModel.addChangeListener(new ChangeListener()
{
public void handleStateChanged(ChangeEvent e)
{
label.setText("Below");
}
});
below.setModel(bModel);
ButtonGroup bGroup = new ButtonGroup();
bGroup.add(aModel);
bGroup.add(bModel);
bGroup.setDefault(bModel);
parent.add(label, new Rectangle(10,70,80,20));
shell.setSize(130,120);
shell.open();
shell.setText("Example");
Display display = Display.getDefault();
while (!shell.isDisposed())
{
if (!display.readAndDispatch())
display.sleep ();
}
}
}
As you can see, a Draw2D application is just an SWT Shell with a LightweightSys-
tem and Figures. It’s important to understand that the ChangeListener is created
by the button’s Model and responds to any mouse action, including clicks and
372 APPENDIX C
Changeable GUIs with Draw2D
hovering. Also, because the two Models are added to the ButtonGroup, only one of
them can be selected at a time.
In order for the parent Figure to understand the Rectangle constraints of its
children, you must configure it with a LayoutManager called XYLayout. We’ll now
focus on LayoutManagers and how they enable you to determine how children are
arranged within Figures.
C.3 Using LayoutManagers and panes
LayoutManagers, like SWT’s Layout classes, specify how child components should
be positioned and sized in a container. This section describes LayoutManager’s
subclasses and how you can use them.
In addition, we’ll go over Draw2D’s panes: ScrollPanes, LayerPanes, and their
subclasses. Draw2D has no Composite class, but these panes generally serve as
background containers for its GUIs. As you’ll see, these window-like classes pro-
vide a number of capabilities that make it simple to build graphical editors. We’ll
finish this section by creating the first flowchart Figure by extending the Free-
formLayeredPane class.
C.3.1 Understanding LayoutManager subclasses
In SWT, containers rely on a default layout policy for their children; but Draw2D
demands that you choose a LayoutManager subclass. Two of these, FlowFigureLay-
out and ScrollBarLayout, are only useful for specific Figures, so we’ll concentrate
on three (see table C.4).
It’s important to understand that when a parent Figure uses its add() method with
a position constraint, its LayoutManager is responsible for interpreting the con-
straint and setting the child’s location as needed.
Table C.4 LayoutManager subclasses
Subclass Description
AbstractHintLayout Uses hint constraints to determine the size of the child Figures, calculat-
ing one dimension based on a specified value for the other
DelegatingLayout Allows children to set their own size according to a Locator constraint
XYLayout Gives the parent the responsibility for sizing and positioning its children
according to a Rectangle constraint
Using LayoutManagers and panes 373
We’ll choose the XYLayout for our editor. Now we need a suitable container
class: We’ll choose the LayeredPane.
C.3.2 LayeredPanes
Since Draw2D applications can become very complex, a LayeredPane provides
many levels for displaying Figures. Using transparent Layers, you can separate the
graphical aspects of your GUIs. Different Layers can have different properties,
including separate LayoutManagers. This will be important for our editor, because
we add not only Figures but also Connections and feedback.
The first step in understanding how LayeredPanes work is learning about Lay-
ers. These transparent objects can be manipulated as individual Figures, and the
Layer class contains two methods of its own: containsPoint() and findFig-
ureAt(). These objects have fixed boundaries, but the FreeformLayer subclass can
be extended in all directions. This is necessary for a graphical editing application
whose drawings are larger than the window’s visible region.
A LayeredPane adds new Layers with its add() method, which specifies the
Layer object, a key to identify it, and an index representing its position. It can also
remove Layers or change their positions in its stack.
By choosing subclasses of LayeredPane, you can increase its capabilities. If
you’d like to be able to zoom in on sections of the pane, choose ScalableLayered-
Pane. Use FreeformLayeredPane if you’d like to extend the window in all direc-
tions. If you want both capabilities, use ScalableFreeformLayeredPane. In our
case, we’re only interested in extensibility; listing C.2 shows the FreeformLayered-
Pane that we’ll use as the basis of our editor.
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
public class ChartFigure extends FreeformLayeredPane
{
public ChartFigure()
{
setLayoutManager(new FreeformLayout());
setBorder(new MarginBorder(5));
setBackgroundColor(ColorConstants.white);
setOpaque(true);
}
}
Listing C.2 ChartFigure.java
374 APPENDIX C
Changeable GUIs with Draw2D
We configure the FreeformLayeredPane with its appearance constraints, but we
don’t add any Layers yet. That will happen later in the editor’s development.
C.3.3 ScrollPanes and Viewports
Before ending our discussion of Draw2D’s panes, we need to briefly mention
ScrollPanes. These classes are easy to understand and function by creating
Scrollbars on top of another Figure. The bars’ visibility can be configured so that
they are always showing, never showing, or shown only when needed.
At any given time, only a section of the ScrollPane can be seen. This visible
region is called a Viewport. These work similarly to Layers but provide more
methods for controlling size and shape. There is also a FreeformViewport for
panes that can be extended in all directions.
Now that we’ve built the primary container for our application, we need to cre-
ate the shapes that will be added to its diagram. For this, we need to investigate
Draw2D’s Graphics class and its drawing capability.
C.4 Using the Graphics class to create Shapes
In SWT, graphic contexts (GCs) can either be created as separate objects or obtained
as part of a PaintEvent. But in Draw2D, a Figure can acquire a Graphics object by
one of the paint methods described in section C.2.1. The vast majority of the Graph-
ics methods are exactly the same as those in GC; the only important difference is
that Draw2D allows a Graphics object to move through its translate() method.
However, Draw2D provides more powerful capabilities for creating and manip-
ulating Shapes. As you’ll see, it has packages of helpful classes for working with
geometry and graphs.
C.4.1 Using the Graphics class
As we’ve mentioned, the Graphics methods are nearly identical to those of SWT’s
GC. Therefore, in this subsection we’ll create the classes that represent the compo-
nents shown in figure C.2. To clarify, these three Figures function as follows:
■ DecisionFigure—Contains a question. One input, two outputs (Yes or No).
■ ProcessFigure—Contains an action to be followed. One input, one output.
■ TerminatorFigure—Represents the start or end of the flowchart. If it’s used
as a start, only the output should be connected. If it’s used as an end, only
the input should be connected.
Using the Graphics class to create Shapes 375
In each case, the Figure’s size is controlled by a variable called bounds. Its text is
set with a message String. These constraints are controlled outside of their Figure
classes, so you won’t be able to view them yet.
The code for these classes, including the paintFigure() method that creates
the Graphics object, is shown in listings C.3 through C.5.
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class DecisionFigure extends ActivityFigure
{
FixedAnchor inAnchor, yesAnchor, noAnchor;
public DecisionFigure()
{
inAnchor = new FixedAnchor(this);
inAnchor.place = new Point(1, 0);
targetAnchors.put("in_dec",inAnchor);
noAnchor = new FixedAnchor(this);
noAnchor.place = new Point(2, 1);
sourceAnchors.put("no",noAnchor);
yesAnchor = new FixedAnchor(this);
yesAnchor.place = new Point(1, 2);
sourceAnchors.put("yes",yesAnchor);
}
public void paintFigure(Graphics g)
{
Rectangle r = bounds;
PointList pl = new PointList(4);
pl.addPoint(r.x + r.width/2, r.y);
pl.addPoint(r.x, r.y + r.height/2);
pl.addPoint(r.x + r.width/2, r.y + r.height-1);
pl.addPoint(r.x + r.width, r.y + r.height/2);
g.drawPolygon(pl);
g.drawText(message, r.x+r.width/4+5, r.y+3*r.height/8);
g.drawText("N", r.x+7*r.width/8, r.y+3*r.height/8);
g.drawText("Y", r.x+r.width/2-2, r.y+3*r.height/4);
}
}
Listing C.3 DecisionFigure.java
376 APPENDIX C
Changeable GUIs with Draw2D
Because of the DecisionFigure’s irregular diamond shape, we need to create a
separate Polygon by specifying a series of Points. Thankfully, the ProcessFigure is
a Rectangle and is much easier to code.
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class ProcessFigure extends ActivityFigure
{
FixedAnchor inAnchor, outAnchor;
public ProcessFigure()
{
inAnchor = new FixedAnchor(this);
inAnchor.place = new Point(1, 0);
targetAnchors.put("in_proc", inAnchor);
outAnchor = new FixedAnchor(this);
outAnchor.place = new Point(1, 2);
sourceAnchors.put("out_proc", outAnchor);
}
public void paintFigure(Graphics g)
{
Rectangle r = bounds;
g.drawText(message, r.x + r.width/4, r.y + r.height/4);
g.drawRectangle(r.x, r.y, r.width-1, r.height-1);
}
}
Since the TerminatorFigure contains two arcs on either side, it isn’t nearly as easy
to draw as the ProcessFigure. However, its code is easy to understand.
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class TerminatorFigure extends ActivityFigure
{
FixedAnchor inAnchor, outAnchor;
public TerminatorFigure()
{
inAnchor = new FixedAnchor(this);
Listing C.4 ProcessFigure.java
Listing C.5 TerminatorFigure.java
Using the Graphics class to create Shapes 377
inAnchor.place = new Point(1, 0);
targetAnchors.put("in_term",inAnchor);
outAnchor = new FixedAnchor(this);
outAnchor.place = new Point(1, 2);
sourceAnchors.put("out_term",outAnchor);
}
public void paintFigure(Graphics g)
{
Rectangle r = bounds;
g.drawArc(r.x + r.width/8, r.y, r.width/4, r.height-1, 90, 180);
g.drawLine(r.x + r.width/4, r.y, r.x + 3*r.width/4, r.y);
g.drawLine(r.x + r.width/4, r.y + r.height-1, r.x + 3*r.width/4,
r.y + r.height-1);
g.drawArc(r.x + 5*r.width/8, r.y, r.width/4, r.height-1, 270, 180);
g.drawText(message, r.x+3*r.width/8, r.y+r.height/8);
}
}
Clearly, there’s a great deal more to these classes than just drawings. The added
complexity is present for two reasons. First, these Figures need to be connected to
other Figures, which means they need ConnectionAnchors (called FixedAnchors).
Second, these Figures will play an important role in the full flowchart editor that
we’ll create in appendix D. Many of their methods can’t be explained until then
(but they’re worth waiting for!).
Since all these Figures extend from an ActivityFigure, it would be a good
idea to show what that is. This superclass contains all the methods common to our
DecisionFigure, ProcessFigure, and TerminatorFigure. As you can see from
listing C.6, most of its methods keep track of Connections and their anchors.
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
import java.util.*;
abstract public class ActivityFigure
extends Figure
{
Rectangle r = new Rectangle();
Hashtable targetAnchors = new Hashtable();
Hashtable sourceAnchors = new Hashtable();
String message = new String();
Listing C.6 ActivityFigure.java
378 APPENDIX C
Changeable GUIs with Draw2D
public void setName(String msg)
{
message = msg;
repaint();
}
public ConnectionAnchor ConnectionAnchorAt(Point p)
{
ConnectionAnchor closest = null;
long min = Long.MAX_VALUE;
Hashtable conn = getSourceConnectionAnchors();
conn.putAll(getTargetConnectionAnchors());
Enumeration e = conn.elements();
while (e.hasMoreElements())
{
ConnectionAnchor c = (ConnectionAnchor) e.nextElement();
Point p2 = c.getLocation(null);
long d = p.getDistance2(p2);
if (d < min)
{
min = d;
closest = c;
}
}
return closest;
}
public ConnectionAnchor getSourceConnectionAnchor(String name)
{
return (ConnectionAnchor)sourceAnchors.get(name);
}
public ConnectionAnchor getTargetConnectionAnchor(String name)
{
return (ConnectionAnchor)targetAnchors.get(name);
}
public String getSourceAnchorName(ConnectionAnchor c)
{
Enumeration enum = sourceAnchors.keys();
String name;
while (enum.hasMoreElements())
{
name = (String)enum.nextElement();
if (sourceAnchors.get(name).equals(c))
return name;
}
return null;
}
public String getTargetAnchorName(ConnectionAnchor c)
{
Enumeration enum = targetAnchors.keys();
Using the Graphics class to create Shapes 379
String name;
while (enum.hasMoreElements())
{
name = (String)enum.nextElement();
if (targetAnchors.get(name).equals(c))
return name;
}
return null;
}
public ConnectionAnchor getSourceConnectionAnchorAt(Point p)
{
ConnectionAnchor closest = null;
long min = Long.MAX_VALUE;
Enumeration e = getSourceConnectionAnchors().elements();
while (e.hasMoreElements())
{
ConnectionAnchor c = (ConnectionAnchor) e.nextElement();
Point p2 = c.getLocation(null);
long d = p.getDistance2(p2);
if (d < min)
{
min = d;
closest = c;
}
}
return closest;
}
public Hashtable getSourceConnectionAnchors()
{
return sourceAnchors;
}
public ConnectionAnchor getTargetConnectionAnchorAt(Point p)
{
ConnectionAnchor closest = null;
long min = Long.MAX_VALUE;
Enumeration e = getTargetConnectionAnchors().elements();
while (e.hasMoreElements())
{
ConnectionAnchor c = (ConnectionAnchor) e.nextElement();
Point p2 = c.getLocation(null);
long d = p.getDistance2(p2);
if (d < min)
{
min = d;
closest = c;
}
}
return closest;
380 APPENDIX C
Changeable GUIs with Draw2D
}
public Hashtable getTargetConnectionAnchors()
{
return targetAnchors;
}
}
We’ll describe these ConnectionAnchors and Connections shortly. But first, we
need to address Draw2D’s package for geometry and shapes.
C.4.2 Draw2D geometry and graphs
You’ve seen how Points and Rectangles are used, but Draw2D provides many
more classes for incorporating shapes in GUIs. For higher-precision measure-
ments, Draw2D provides PrecisionPoints, PrecisionRectangles, and Precision-
Dimensions. It contains Ray objects that function like mathematical vectors and a
Transform class to translate, rotate, and scale graphical Points and dimensions.
The org.eclipse.draw2d.graph package contains a number of useful classes
for creating and analyzing directed graphs. Along with basic Nodes and Edges, this
package also provides a DirectedGraphLayout for arranging them. Graph theory is
far beyond the scope of this appendix, but if it interests you, this package should
prove helpful.
Draw2D’s Figures aren’t connected by Edges, but by Connection objects. To fin-
ish our flowchart diagram, we need to show you how this class operates.
C.5 Understanding Connections
The FixedAnchor class has figured prominently in our code listings so far. These
objects (subclasses of AbstractConnectionAnchor) enable you to add lines, or Con-
nections, between two Figures. Because Connections create relationships between
components, they’re fundamental in system models and diagrams. However, man-
aging Connections and their ConnectionAnchors can be complicated, so it’s impor-
tant that you understand how they function.
C.5.1 Working with ConnectionAnchors
ConnectionAnchors don’t have a visual representation. Instead, they specify a point
on a Figure that can receive Connections. You add them by identifying the Figure
Understanding Connections 381
in the ConnectionAnchor’s constructor method. This Figure is called the anchor’s
owner, not its parent.
The difficulty in working with anchors isn’t adding them, but placing them
appropriately. For this reason, the only method required by the ConnectionAnchor
interface is getLocation() (see listing C.7).
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class FixedAnchor
extends AbstractConnectionAnchor
{
Point place;
public FixedAnchor(IFigure owner)
{
super(owner);
}
public Point getLocation(Point loc)
{
Rectangle r = getOwner().getBounds();
int x = r.x + place.x * r.width/2;
int y = r.y + place.y * r.height/2;
Point p = new PrecisionPoint(x,y);
getOwner().translateToAbsolute(p);
return p;
}
}
The getLocation() method is called whenever the owner’s location changes. The
Point returned by the method tells the GUI where the anchor should be posi-
tioned. In our case, we use getOwner() to obtain the owner’s bounds and a con-
straint called place. This variable specifies the anchor’s location as a proportion
of the owner’s dimensions. This way, if the Figure’s size changes, the anchor will
still be positioned properly.
For example, we want the input connection into our DecisionFigure to be
located at the top of its bounds and halfway across its width. We set this in our
class as follows:
Listing C.7 FixedAnchor.java
382 APPENDIX C
Changeable GUIs with Draw2D
inAnchor = new FixedAnchor(this);
inAnchor.place = new Point(1, 0);
targetAnchors.put("in_dec",inAnchor);
Here, place is set to (1,0) to tell the anchor to be located at 1/2 its width and 0/2
its height, as measured from the top, leftmost corner of the Figure’s enclosing
Rectangle. The anchor is then placed in a Hashtable with a String key. This
doesn’t mean anything in Draw2D, but it will be important when we use this Fig-
ure in the GEF editor.
C.5.2 Adding Connections to the GUI
Working with Connections is easier than dealing with their anchors, because
Draw2D takes care of drawing the line. Draw2D’s implementation of the Connec-
tion interface is PolylineConnection, which is a connected line. Our subclass of
PolylineConnection is PathFigure (see listing C.8).
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
public class PathFigure extends PolylineConnection
{
public PathFigure()
{
setTargetDecoration(new PolylineDecoration());
setConnectionRouter(new ManhattanConnectionRouter());
}
}
Of course, Connections are more than connected lines. We need to set their
source and target Figures, and we can configure their appearance and routing.
With regard to appearance, you can add decorations to the start and end of the
Connection by calling setSourceDecoration() or setTargetDecoration(). In our
case, we create a new PolylineDecoration for the end of the Connection, which
looks like a triangle tip.
In addition to decorators, you can add Labels or other Figures to Connections
by using a ConnectionEndpointLocator. These objects are created with a Connec-
tion object and a boolean value representing whether the Figure should be
added at the start or end. Then, setVDistance() tells the new Figure how far away
it should be from the Connection, and setUDistance() specifies the distance to
the Connection’s source or target.
Listing C.8 LiPathFigure.java
Putting it all together 383
The Connection’s router refers to the path it takes from one anchor to the
next. The four subclasses of AbstractConnectionRouter are listed in table C.5.
As you can see in figure C.2, our PathFigures always bend at right angles; this is
because we chose to use the ManhattanConnectionRouter. It’s important to note,
though, that if your LayeredPane contains a ConnectionLayer, you can also use it
to set the routing.
Now that you understand Draw2D’s Figures and Connections, we’ll combine
the two in our final section.
C.6 Putting it all together
We’re nearly ready to add the main class of the diagram. But to allow users to repo-
sition Figures, you need to understand how drag-and-drop works in Draw2D. We’ll
also present the FigureFactory class so that you can centralize Figure allocation.
C.6.1 Drag-and-drop in Draw2D
We’ve already mentioned a number of important listeners and events in Draw2D,
but none of them involved DragSources, DropTargets, or anything resembling the
drag-and-drop capability of SWT. This is because at the time of this writing,
Draw2D has yet to incorporate this feature. Therefore, our Dnd class, shown in
listing C.9, relies on the Figure’s ability to translate itself according to the distance
between its present and future locations.
Table C.5 AbstractConnectionRouter subclasses
Subclass Description
AutomaticRouter Positions Connections so that they never inter-
sect, or intersect as little as possible
ManhattanConnectionRouter Positions Connections so that all bends are
made with right angles
ConnectionRouter.NullConnectionRouter Positions Connections in a straight line from
the source anchor to the target
BendpointConnectionRouter Creates moveable points (Bendpoints) for
each bend in the Connection
384 APPENDIX C
Changeable GUIs with Draw2D
package com.swtjface.AppC;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class Dnd extends MouseMotionListener.Stub
implements MouseListener
{
public Dnd(IFigure figure)
{
figure.addMouseMotionListener(this);
figure.addMouseListener(this);
}
Point start;
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
public void mouseDoubleClicked(MouseEvent e){}
public void mousePressed(MouseEvent e)
{
start = e.getLocation();
}
public void mouseDragged(MouseEvent e)
{
Point p = e.getLocation();
Dimension d = p.getDifference(start);
start = p;
Figure f = ((Figure)e.getSource());
f.setBounds(f.getBounds().getTranslated(d.width, d.height));
}
};
Because this class extends MouseMotionListener.Stub, it doesn’t need to add all
the methods for a MouseMotionListener. But because it needs to respond to
mouse clicks, it implements MouseListener and needs to add all the methods for
this interface.
C.6.2 Creating Figures with a FigureFactory
To prevent outside methods from directly invoking constructor methods, the edi-
tor uses the factory pattern for its Figures. This is a single class whose static methods
create new Figures for insertion into the GUI. The code for the FigureFactory is
shown in listing C.10.
Listing C.9 Dnd.java
Putting it all together 385
package com.swtjface.AppC;
import org.eclipse.draw2d.IFigure;
public class FigureFactory
{
public static IFigure createTerminatorFigure()
{
return new TerminatorFigure();
}
public static IFigure createDecisionFigure()
{
return new DecisionFigure();
}
public static IFigure createProcessFigure()
{
return new ProcessFigure();
}
public static PathFigure createPathFigure()
{
return new PathFigure();
}
public static ChartFigure createChartFigure()
{
return new ChartFigure();
}
}
We’ve created all the Figures needed for the flowchart and the factory class that
creates them. Now we can add the final executable that combines them.
C.6.3 The Flowchart class
To finish the application, listing C.11 presents the Flowchart class.
package com.swtjface.AppC;
import org.eclipse.swt.widgets.*;
import org.eclipse.draw2d.*;
import org.eclipse.draw2d.geometry.*;
public class Flowchart
{
Listing C.10 FigureFactory.java
Listing C.11 Flowchart.java
386 APPENDIX C
Changeable GUIs with Draw2D
public static void main(String args[])
{
Shell shell = new Shell();
shell.setSize(200,300);
shell.open();
shell.setText("Flowchart");
LightweightSystem lws = new LightweightSystem(shell);
ChartFigure flowchart = new ChartFigure();
lws.setContents(flowchart);
TerminatorFigure start = new TerminatorFigure();
start.setName("Start");
start.setBounds(new Rectangle(40,20,80,20));
DecisionFigure dec = new DecisionFigure();
dec.setName("Should I?");
dec.setBounds(new Rectangle(30,60,100,60));
ProcessFigure proc = new ProcessFigure();
proc.setName("Do it!");
proc.setBounds(new Rectangle(40,140,80,40));
TerminatorFigure stop = new TerminatorFigure();
stop.setName("End");
stop.setBounds(new Rectangle(40,200,80,20));
PathFigure path1 = new PathFigure();
path1.setSourceAnchor(start.outAnchor);
path1.setTargetAnchor(dec.inAnchor);
PathFigure path2 = new PathFigure();
path2.setSourceAnchor(dec.yesAnchor);
path2.setTargetAnchor(proc.inAnchor);
PathFigure path3 = new PathFigure();
path3.setSourceAnchor(dec.noAnchor);
path3.setTargetAnchor(stop.inAnchor);
PathFigure path4 = new PathFigure();
path4.setSourceAnchor(proc.outAnchor);
path4.setTargetAnchor(stop.inAnchor);
flowchart.add(start);
flowchart.add(dec);
flowchart.add(proc);
flowchart.add(stop);
flowchart.add(path1);
flowchart.add(path2);
flowchart.add(path3);
flowchart.add(path4);
new Dnd(start);
new Dnd(proc);
new Dnd(dec);
new Dnd(stop);
Display display = Display.getDefault();
while (!shell.isDisposed())
{
Putting it all together 387
if (!display.readAndDispatch())
display.sleep();
}
}
}
Although the code for this class is long, its operation is easy to understand. After
the ChartFigure is added to the LightweightSystem, four component Figures are
created and initialized. These components are connected with four PathFigures.
After all the Figures are added to the diagram, the code associates a Dnd object
with each component.
The diagram we’ve created is more interesting than many of our SWT GUIs,
but it leaves much to be desired. We’d like to add and remove Figures and the
Connections between them. We want to resize them and set their messages during
operation. Finally, we’d like to persist our flowcharts in a file so we don’t have to
rebuild them every time we close the application.
All of this is possible, but it’s not easy. If you thought the code in this appendix
was involved, you haven’t seen anything yet. In appendix D, we’ll introduce the
Graphical Editing Framework.
388
The Graphical Editing
Framework (GEF)
A GEF overview 389
GEF development is, without question, the most complex topic thus far—it would
take an entire book to examine the GEF toolset in full. So, this appendix will only
describe the structure and function of a simple (but complete) graphical editor.
Building a graphical editor involves much more than Draw2D Figures: It
requires a sound knowledge of plug-ins, Model-View-Controller (MVC) architec-
ture, JavaBean components, JFace Viewers, JFace Actions, JFace properties, and
many of the classes that make up the Eclipse Workbench. Although this appendix
won’t attempt to explain any of these concepts in depth, we’ll clarify how they
work together in the GEF. Learning to build a graphical editor isn’t easy, but with
sufficient experience, you can create powerful applications with reusable, inter-
changeable code.
GEF development is complicated but not impossible. How do you eat a two-ton
elephant? One bite at a time.
D.1 A GEF overview
Before we go into the nuts and bolts of GEF development, it will be helpful to dis-
cuss how the machine works as a whole. A graphical editor functions by allowing a
user to create a visual representation of a complex system. The editing process is
performed by adding graphical elements to a container, setting their properties,
and creating relationships between them. Once these elements and relationships
are set, the editor must be able to persist the editor’s state in a file. Of course, this
file doesn’t keep track of every color, dimension, and pixel in the editor. Instead,
it contains the diagram’s information—its meaning—which has been separated
from its appearance.
D.1.1 Separation of concerns theory
Not only does GEF development split information and appearance, it also requires
classes for every separable aspect of the editor. That is, a GEF editor isn’t a single,
monolithic application, but a combination of many small objects that communicate
using standard interfaces. This modular structure makes editor code easy to replace
and maintain. However, the multiplicity of parts makes the learning curve steep.
Figure D.1 shows how the MVC architecture provides a separation of concerns.
The View is the easiest to understand, since it provides the component’s display.
The Model aspect is more subtle; put simply, it holds the properties of the editor
that can be modified by the user. These could include the size and location of the
390 APPENDIX D
The Graphical Editing Framework (GEF)
editor’s components and the presence and placement of the connections
between them.
The Controller manages the component’s interaction with the rest of the GUI.
It receives notice of user input and directs changes to its Model and View objects.
It keeps track of connections between components and any message communica-
tion. In essence, the Controller aspect takes care of everything that isn’t related to
the Model or View.
D.1.2 Separation of concerns: GEF implementation
Every editable component in a GEF editor consists of three objects that provide its
MVC structure. The View aspect is generally implemented as a Figure or Image.
The Controller is a subclass of AbstractGraphicalEditPart. A Model class extends
only Object. Figure D.2 shows the classes that will be used to create our Decision
component and the naming conventions for each.
Thankfully, we created the View aspects of the editor’s components in appen-
dix C. We can now show how these aspects work together during editing.
Controller
(Interface/
Management)
View
(Appearance)
Model
(Information)
Figure D.1 MVC architecture for
graphical editors
DecisionPart
(Controller)
DecisionFigure
(View)
Decision
(Model)
Should I?
Y
N
Figure D.2 The flowchart’s Decision
component and the classes used to
represent its Model, View, and Controller
A GEF overview 391
NOTE Although the EditPart object makes up the Controller aspect of a GEF
component, the entire MVC combination is generally referred to as an
EditPart, or component, or just part. Therefore, we’ll refer to the aspects
described in figure D.2 collectively as a DecisionPart.
D.1.3 MVC interaction
It isn’t difficult to see how the Model, View, and Controller classes function indi-
vidually. The main obstacle to understanding the GEF is dealing with their interac-
tions, both between themselves and with the rest of the application. Even the
simplest editing modification requires a complex data exchange involving Tools,
Requests, EditPolicys, Commands, and PropertyChangeEvents. We’ll cover these
topics in staggering detail to enable you to customize your GEF editor. But since
you’re still in the first section, a quick analogy will be helpful.
Think about how your nervous system works. Your senses perceive a stimulus
and send their impression to the nervous system. The nervous system, functioning
like a switchboard, updates the brain with the new information. The brain sends a
response, and the nervous system extends or retracts muscles to move the skele-
ton. This interaction is shown in figure D.3.
The Brain
Nervous
System
Senses
Muscular/
Skeletal System
Figure D.3 The GEF/nervous system analogy, part 1
392 APPENDIX D
The Graphical Editing Framework (GEF)
When you examine the interaction between the classes that make up GEF’s
MVC architecture, the process may seem similar. When the user causes an event, a
Tool object sends a Request to the selected EditPart. This EditPart uses a List of
EditPolicys to create a Command that updates the Model class. When the Model
changes, it fires a PropertyChangeEvent. After receiving this event, the EditPart
modifies the component’s Figure (View) by invoking one of its refresh() meth-
ods. This process is shown in figure D.4.
This comparison isn’t perfect, but it provides a framework for understanding
the many interfaces and objects that take part in the editing process. As we
progress into greater detail, it’s easy to lose sight of the big picture; we hope you’ll
keep this analogy in mind.
D.1.4 Building the flowchart editor
A graphical editor requires classes for the Model, View, and Controller aspects of
each component. For the flowchart editor, the top-level (parent) component will
be the Chart, which serves as the main container for the rest of the GUI elements.
We’ve already created the View (ChartFigure), so we need to build a Controller
(ChartPart) and a Model (Chart).
The Model Object
The EditPart
(Controller)
Object
The Active
Tool
The Figure
(View)
getABC() (....)
setABC() (....)
getXYZ() (....)
setXYZ() (....)
EditPolicy
getGommand
(Request)
(....)
Refresh(ABC
(....)
RefreshXYZ
(....)
EditPart.
getCommand
(Request)
setConstraint
(ABC)
setConstraint
(XYZ)
Command
Property
Change
Request
Refresh
Figure D.4 The GEF/nervous system analogy, part 2
A GEF overview 393
The three shapes in the editor, corresponding to the Decision, Terminator,
and Process components, also require MVC triples. This means building Edit-
Parts and Model classes in addition to the Figures created in appendix C.
Because these three components have so much in common, we’ll show how to
create an abstract class called an Activity; then, each concrete class will extend
the ActivityPart, ActivityFigure, or Activity class. In addition, we’ll show how
to build an MVC triple for connections: Path, PathPart, and PathFigure.
Once we’ve finished with the individual components, we’ll explain how they
communicate. This will require Commands, Requests, and EditPolicys. In addition,
we’ll show how a palette adds components to the editor and how an EditorPart
keeps track of the entire application.
This may seem confusing, but figure D.5, which depicts the full class hierarchy
of the FlowchartProject, should help.
Table D.1 shows our plan of attack for building the graphical editor. Since the
editing process begins with adding components from the editor’s palette, that’s
where we’ll start.
Table D.1 Creating the flowchart editor using the GEF
Goal Procedure
1 Create Figure objects
to represent elements
of the flowchart
(already accomplished).
1. Create a container to serve as the application’s top-level Figure.
2. Build child Figures to be placed in the container.
3. Extend the ConnectionAnchor and PolylineConnection
classes to provide connections between Figures.
2 Create the project,
FlowchartProject.
1. Create a blank Java plug-in project for the flowchart.
2. Configure plugin.xml to reflect the editor’s configuration.
3. Add the class libraries needed for Draw2D, GEF, and Workbench
integration.
4. Build an organized package structure to hold the project’s classes.
5. Add the Figure classes to the appropriate package.
3 Build the palette for the
flowchart editor and the
drag-and-drop ability.
1. Create a subclass of PaletteViewer.
2. Add the tool entries needed for selection, marquee selection, and
connections to a PaletteGroup.
3. Add the template entries needed to add components to the Graph-
icalViewer to a secondary group.
4. Create a class to provide drag-and-drop between the palette and the
main viewer.
continued on next page
394 APPENDIX D
The Graphical Editing Framework (GEF)
Since this section has summarized the entire GEF development, you may feel over-
whelmed. Don’t worry! All of this will be become clearer as you start program-
ming. Let’s begin by creating the project, aptly named FlowchartProject.
4 Add Model classes for
the Figures.
1. Build a top-level Model class (AbstractChartElement) incorporat-
ing the methods needed for firing PropertyChangeEvents.
2. Create an abstract class (Activity) that will be extended by the
components.
3. Add Model classes for the components: Decision, Process, and
Terminator.
4. Create a Model class for the container (Chart), with methods for
handling children.
5. Create a Model class for the connections (Path).
6. Build a factory class (ModelFactory) that will convert templates
into Models.
5 Add Commands to pro-
vide interfaces to the
Model classes.
1. Build Commands for creating and deleting components from the
editor.
2. Build Commands for making connections and changing component
shapes.
6 Create EditParts to
combine the Model and
Figure classes.
1. Create an EditPart (ChartPart) for the container.
2. Create an abstract EditPart for Process, Terminator, and
Decision components.
3. Build individual concrete EditParts for the components.
4. Add an EditPart (PathPart) for the component connections.
7 Create EditPolicys to
provide manipulation of
the EditPart objects.
1. Create an EditPolicy for the container (LayoutPolicy).
2. Create an EditPolicy for general components
(ComponentPolicy).
3. Create an EditPolicy for the node components (NodePolicy).
8 Enable Actions to pro-
vide multiple methods
of editing.
1. Create a ContextMenuProvider for immediate Undo, Redo,
Delete, and Save.
2. Create RetargetActions to enable users to edit with the Eclipse
Workbench.
3. Add these RetargetActions to an ActionBarContributor.
9 Create the overall
FlowchartEditor
class.
Create a FlowchartEditor class that will
1. Save a Chart object to a file and retrieve Chart objects from files.
2. Configure and initialize a GraphicalViewer and a Palette-
Viewer.
3. Use a KeyHandler and a CommandStack to keep track of user
activity.
Table D.1 Creating the flowchart editor using the GEF (continued)
Goal Procedure
Creating the FlowchartProject 395
D.2 Creating the FlowchartProject
Although much of this book was written for both Eclipse-based and standalone
Java development, this section assumes you’re building this project using Eclipse.
A user can run normal Java applications whenever he pleases, but Eclipse editors
are activated only when an appropriate file is selected for editing. This means
Eclipse needs to know in advance which editor should be used for a given file
type. In our case, the Workbench needs to know that the flowchart editor should
FlowchartEditor
GraphicalViewer
Flowchart
Palette
The Editor
The Parent
EditPartChartPart
ChartFigure Chart
Activity
Part PathPart
Activity
Figure Activity PathFigure Path
Decision
Part
Process
Part
Terminator
Part
Decision
Figure Decision
Process
Figure Process
Terminator
Figure Terminator
Initialization
The Child
EditParts
RootEditPart
Figure D.5 Class structure of the FlowchartEditor application
396 APPENDIX D
The Graphical Editing Framework (GEF)
be activated whenever the user edits a flowchart file, designated by *.fcf. A
Draw2D application won’t do the job: We need a plug-in.
To begin building this plug-in project, follow these steps:
1 Select File->New->Project.
2 Choose Plug-in Development and Plug-in Project in the New Project dia-
log. Click Next.
3 Call the project FlowchartProject and click Next.
4 Use the default values for Plug-in Project Structure and click Next once
more.
5 In the Plug-in Content dialog, you need to make two changes. First, use
swtjface as the provider name. Then, leaving the checkboxes checked,
change the Class Name field to com.swtjface.flowchart.Flowchart-
ProjectPlugin. Click Finish.
6 Now that you’ve created the project, you need to tell the Workbench what
the editor is and what resources it needs to function. You do this by setting
the parameters in the project’s plugin.xml file.
D.2.1 Configuring the Plugin.xml file
Every Eclipse plug-in describes its characteristics and resource requirements in its
plugin.xml file. You can modify this file with Eclipse’s Plug-in Manifest Editor or
code it directly. The plugin.xml code for our flowchart editor is shown in
listing D.1.
Listing D.1 The plugin.xml file
Identifies
project’s plug-in
information
Creating the FlowchartProject 397
NOTE Since every editor requires an icon, we’ve chosen to use the eclipse32.gif
image from org.eclipse.platform_x.y.z. This file must be added to the
project in order for the plug-in to function.
The first sections of this file specify the identification information about the plug-
in and the libraries it needs to operate. The plug-in class, FlowchartProject-
Plugin, has already been created and added to the com.swtjface.flowchart pack-
age; this file shouldn’t be modified.
The important configuration information for our editor is contained in the
tags, including the main class for the editor and the
contribution class needed to incorporate Workbench Actions into our editor. The
line extensions="fcf" ensures that the editor will be activated whenever the user
creates a file with the fcf suffix.
Along with the extension for the editor, many GEF projects incorporate a wiz-
ard to build an initial *.fcf file for the editor. Doing so is straightforward but
beyond the scope of this appendix. For further information about plug-ins, wizard
Lists plug-ins
needed for
project
Provides
information
about editor
398 APPENDIX D
The Graphical Editing Framework (GEF)
extensions, and XML configuration, we recommend Eclipse in Action, by David Gal-
lardo, Ed Burnette, and Robert McGovern (Manning, 2003).
D.2.2 Adding class libraries
Depending on which version of Eclipse you use, the necessary plug-ins may have
already been added to the project. If you open the Plug-in Dependencies in the
Package Explorer, you may already see a list of jar files; if so, you can skip this sub-
section. If not, you need to include a number of class libraries. Since the boot.jar
and runtime.jar files were automatically added during project creation, add the
JFACE_LIB and WORKBENCH_LIB variables created in appendix A and the DRAW2D_LIB
variable created in appendix C. You also need to add the OSGI_LIB variable cre-
ated in chapter 4.
Unlike the other graphical applications in this book, GEF editors need to be
integrated in the Eclipse Workbench. This means you need to add even more
libraries. Table D.2 lists the jar files required to work with Workbench parts and
recommended names for their classpath variables.
Once we’ve created these classpath variables and added them to Flowchart-
Project, we can begin adding packages and classes.
D.2.3 Adding packages and classes
GEF projects keep their code organized with a series of packages that represent
different aspects of the editor. Package names may differ from one application to
the next, but table D.3 lists those used in the flowchart editor. We recommend
that you add them to the FlowchartProject inside the src directory.
Table D.2 Additional libraries needed for GEF applications
Classpath variable Library file
GEF_LIB $ECLIPSE/plugins/org.eclipse.gef_x.y.z/gef.jar
UI_EDITORS_LIB $ECLIPSE/plugins/org.eclipse.ui.editors_x.y.z/editors.jar
UI_IDE_LIB $ECLIPSE/plugins/org.eclipse.ui.ide_x.y.z/ide.jar
UI_LIB $ECLIPSE/plugins/org.eclipse.ui_x.y.z/ui.jar
UI_VIEWS_LIB $ECLIPSE/plugins/org.eclipse.ui.views_x.y.z/views.jar
Creating the FlowchartProject 399
Since the Figure objects for this project
have already been written, we can add them
to the project. To do this, we move Activity-
Figure.java, ChartFigure.java, DecisionFig-
ure.java, FigureFactory.java, FixedAnchor
.java, PathFigure.java, ProcessFigure.java,
and TerminatorFigure.java to the com.swtj-
face.flowchart.figures package. The end
result of this process is shown in figure D.6.
Now that we’ve added these files, we’ve
completed the View aspect of the editor.
However, these Figures aren’t much use
unless users can add them to the editor.
Toward this end, our next goal is to dis-
cuss GEF palettes.
Table D.3 Class packages in the flowchart editor
Package Function
com.swtjface.flowchart Editor’s EditorPart and plug-in
com.swtjface.flowchart.actions Classes that create and manage Actions
com.swtjface.flowchart.commands Classes used to modify the Model properties
com.swtjface.flowchart.dnd Classes that provide the drag-and-drop capability
com.swtjface.flowchart.editpart Editor’s EditParts
com.swtjface.flowchart.figures Graphics used to create EditPart visuals
com.swtjface.flowchart.model Information contained in the EditParts
com.swtjface.flowchart.palette GUI element used to instantiate EditParts
com.swtjface.flowchart.policies Policies available for the EditParts
Figure D.6
The package structure for
FlowchartProject
400 APPENDIX D
The Graphical Editing Framework (GEF)
D.3 Creating the editor’s PaletteViewer
Look at figure D.7. In the simplest terms, it shows a Canvas with a LightweightSys-
tem object—just like any Draw2D application. What differentiates a GEF editor
from a Draw2D application or text editor is its Viewer. Viewer classes, as described
earlier, rest on top of a component and control its appearance and event handling.
In this case, we have two of them: a Viewer that represents the main editor and one
that contains the palette. Since the palette is the first object a user will come in
contact with, we’ll start our GEF discussion by examining the PaletteViewer.
The PaletteViewer class builds components and handles events for the left-
hand section of the Canvas, whose default width is 125 pixels. Like the viewer on
the right-hand side, it implements the GraphicalViewer interface. But Palette-
Viewer has a number of distinguishing features:
■ The ability to add buttons that provide editing functions, called ToolEntrys
■ The ability to add buttons that create new components, called TemplateEn-
trys
■ Configuration information contained in a single object, the PaletteRoot
This PaletteRoot is important for a PaletteViewer because it provides the entries
that will be available to the user. Like a Model class, it contains the palette’s
Figure D.7
The flowchart editor in its
dazzling glory
Creating the editor’s PaletteViewer 401
information. The getPaletteRoot() method configures one of these objects by
creating and populating a List of PaletteGroups. In FlowchartPalette, the first
PaletteGroup, toolGroup, contains a List of tool-related entries. The second, tem-
plateGroup, contains a List of template-related entries. The code is shown in
listing D.2, and we recommend that you add this to the com.swtjface.flow-
chart.palette package.
package com.swtjface.flowchart.palette;
import java.util.*;
import com.swtjface.flowchart.model.*;
import org.eclipse.gef.palette.*;
import org.eclipse.jface.resource.*;
public class FlowchartPalette
{
public static final String
TERMINATOR_TEMPLATE = "TERM_TEMP",
DECISION_TEMPLATE = "DEC_TEMP",
PROCESS_TEMPLATE = "PROC_TEMP";
public static PaletteRoot getPaletteRoot()
{
PaletteRoot root = new PaletteRoot();
PaletteGroup toolGroup = new PaletteGroup("Chart Tools");
List toolList = new ArrayList();
ToolEntry tool = new SelectionToolEntry();
toolList.add(tool);
root.setDefaultEntry(tool);
tool = new MarqueeToolEntry();
toolList.add(tool);
tool = new ConnectionCreationToolEntry(
"Connection_Tool", "Used to connect multiple components", null,
ImageDescriptor.getMissingImageDescriptor(),
ImageDescriptor.getMissingImageDescriptor() );
toolList.add(tool);
toolGroup.addAll(toolList);
Listing D.2 FlowchartPalette.java
Create palette
entries that
activate tools
Add tool entry list to group
402 APPENDIX D
The Graphical Editing Framework (GEF)
PaletteGroup templateGroup =
new PaletteGroup("Chart Templates");
List templateList = new ArrayList();
CombinedTemplateCreationEntry entry = new
CombinedTemplateCreationEntry(
"Terminator", "Start or End Component", TERMINATOR_TEMPLATE,
new ModelFactory(TERMINATOR_TEMPLATE),
ImageDescriptor.getMissingImageDescriptor(),
ImageDescriptor.getMissingImageDescriptor());
templateList.add(entry);
entry = new CombinedTemplateCreationEntry(
"Process", "Action within a flowchart", PROCESS_TEMPLATE,
new ModelFactory(PROCESS_TEMPLATE),
ImageDescriptor.getMissingImageDescriptor(),
ImageDescriptor.getMissingImageDescriptor());
templateList.add(entry);
entry = new CombinedTemplateCreationEntry(
"Decision", "Choosing between 'Yes' and 'No'", DECISION_TEMPLATE,
new ModelFactory(DECISION_TEMPLATE),
ImageDescriptor.getMissingImageDescriptor(),
ImageDescriptor.getMissingImageDescriptor());
templateList.add(entry);
templateGroup.addAll(templateList);
List rootList = new ArrayList();
rootList.add(toolGroup);
rootList.add(templateGroup);
root.addAll(rootList);
return root;
}
}
As you can see, a PaletteRoot is a collection of PaletteGroups, which are collec-
tions of entries. These entries, represented by the ToolEntry and CombinedTem-
plateCreationEntry classes, create buttons that will be added to the palette.
Except for the SelectionTool and the MarqueeSelectionTool, these entries are
initialized with descriptors, images, and classes that implement the CreationFac-
tory interface. But before we can discuss their constructor methods, we need to
explain how Tools and templates work.
D.3.1 Handling events with the ToolEntry and Tool classes
The first three entries in our palette are ToolEntrys, which provide the ability to
select and connect existing components. Whenever any of these entries are
Create palette
entries that
activate tools
Add template entry list to group
Add both groups to palette
Creating the editor’s PaletteViewer 403
clicked, they create a new Tool object. The top tool entry, labeled Select, creates a
SelectionTool; the Marquee entry creates a MarqueeSelectionTool; and the
Connection_Tool entry creates a ConnectionCreationTool.
The entries are simple to understand, but what exactly is a Tool? A Tool pro-
vides a distinctive means of interpreting keyboard and mouse events. For exam-
ple, when you click a component with the SelectionTool activated, there will be a
different result than if the ConnectionCreationTool had been activated. This is
because the two Tools have different handlers for MouseEvents; they also interact
differently with components and their EditParts. These Tool/EditPart interac-
tions are accomplished through Requests.
Table D.4 lists a group of important Tools provided in GEF, their functions, and
the Requests they send to EditParts during activation.
It’s important to note that DragTrackers such as ResizeTracker and Connection-
BendpointTracker are also GEF Tools. They determine how DragEvents affect an
EditPart. Whereas a Tool’s activation is independent of the components in the edi-
tor, DragTrackers are specified in EditParts. In many cases, a high-level Tool trans-
fers its event-handling authority to the DragTracker associated with the EditPart.
For example, when a user clicks a Decision component, the SelectionTool will
activate. But if the user presses the button and moves the mouse, then the Selec-
tionTool delegates authority to the DecisionPart’s DragTracker.
Table D.4 Class packages in the FlowchartProject project
Tool Tool description Requests
ConnectionBendpoint
Tracker
Creates or moves Bendpoints within a
Connection
BendpointRequest
ConnectionCreationTool Tells the EditPart that it will be the
start of a new connection
ConnectionCreation
Request
CreationTool Creates new EditParts (components) CreateRequest
MarqueeSelectionTool Selects all the EditParts within the
marquee
SelectionRequest
ResizeTracker Tells the EditPart to change its size ChangeBounds
Request
SelectionTool Tells an EditPart that it has been
selected or that the mouse cursor has
come in contact with the component
SelectionRequest
LocationRequest
404 APPENDIX D
The Graphical Editing Framework (GEF)
Requests
Requests are the means by which Tools perform editing. When a component is
clicked with the SelectionTool activated, the Tool sends a SelectionRequest or a
LocationRequest to the EditPart. Similarly, when the ConnectionCreationTool is
activated, the tool sends a CreateConnectionRequest. In each case, the Request
provides the EditPart with information about the event, such as which key was
pressed or which button was clicked.
When an EditPart receives a Request, it responds with a Command object if one
is available. This Command tells the Tool how the EditPart should be altered when
the event occurs. Once the Tool receives a Command, it takes responsibility for mod-
ifying the EditPart by invoking the Command’s execute() method. We’ll discuss
Commands in depth shortly.
We need to mention two points about Requests. First, there is no subpackage
(such as com.swtjface.flowchart.requests) for Requests because GEF already
provides all the classes that will be needed in most editors. However, users can cre-
ate their own Tools and Requests as needed.
Second, although Requests are generally categorized according to their class,
they’re further distinguished by a TYPE field. This integer makes the Request’s
function more specific. For example, when the mouse hovers over an EditPart,
the SelectionTool sends a LocationRequest to the component. Because this Loca-
tionRequest’s TYPE field is REQ_SELECTION_HOVER, the part knows that the mouse is
hovering above it.
EditDomains and Tools
Although EditDomain objects operate behind the scenes, it’s important to know
what they are and how they relate to palettes and palette entries. EditDomains keep
track of an editor’s state information, and part of this information consists of which
Tool is currently active. The EditDomain sets the editor’s default Tool, which is usu-
ally the SelectionTool, and manages the process of switching from one Tool to the
next. It ensures that only one Tool is active at any time and directs events to it.
This object also plays a role in creating an editor’s palette. The EditDomain
ensures that the PaletteViewer receives the PaletteRoot containing the List of
ToolEntrys and TemplateEntrys. Then, it determines which Tool in the List is the
default tool and activates this Tool when the editor initializes.
D.3.2 Creating components with templates
At the time of this writing, the GEF documentation describes many classes that
create and handle templates, but it never explains exactly what a template is. An
Creating the editor’s PaletteViewer 405
examination of the code tells us that a template is any object that can be matched to a
component. If you’d like to number your components, then you can use ints or
chars as your templates. For our editor, we’ll use Strings. That is, TERM_TEMP is the
template that corresponds to the Terminator component, PROC_TEMP represents
the Process, and DEC_TEMP represents the Decision.
TemplateEntry objects
Just as a ToolEntry creates Tool objects, TemplateEntrys create templates. After
clicking a TemplateEntry in the palette, the user can either drag the template to
the editor or click an area in the editor. Once the drop location is determined,
the editor’s TemplateTransferDropTargetListener determines how the compo-
nent will be created.
In our example, the entry list consists of CombinedTemplateCreationEntrys,
which create both a template and a CreationEntryTool to create the template’s
matching component. The constructor for these entries requires a number of
fields to specify its appearance and operation:
■ label (a String)—The entry’s name
■ shortDesc (a String)—Description when the mouse hovers over the entry
■ template (an Object; a String, in our case)—The component to be created
■ factory (a CreationFactory)—The class that builds the component
■ iconSmall (an ImageDescriptor)—The image shown near the label
■ iconLarge (an ImageDescriptor)—The image shown during the drag
For our flowchart editor, we’ll use getMissingImageDescriptor() to provide the
icons. These are the small, red squares provided by the JFace library.
So far, we’ve discussed every aspect of palette entry constructors except the
CreationFactory.
Converting templates to Model classes with a CreationFactory
Components are created when the user drags a template from the palette and
drops it in a container. The CreationTool tells the editor which component to
build by identifying a class that implements the CreationFactory interface.
This important interface contains only two methods: getNewObject() receives
a template object and returns a newly created Model object for the requested
component, and getObjectType() returns the template created by the palette
tool. The code in listing D.3 shows how these methods are used in the flowchart
406 APPENDIX D
The Graphical Editing Framework (GEF)
editor’s ModelFactory class. We recommend that you place this class in the
com.swtjface.flowchart.model package.
package com.swtjface.flowchart.model;
import org.eclipse.gef.requests.CreationFactory;
import com.swtjface.flowchart.palette.*;
public class ModelFactory
implements CreationFactory
{
private String template;
public ModelFactory(Object str)
{
template = (String) str;
}
public Object getNewObject()
{
if (FlowchartPalette.TERMINATOR_TEMPLATE.equals(template))
return new Terminator();
if (FlowchartPalette.DECISION_TEMPLATE.equals(template))
return new Decision();
if (FlowchartPalette.PROCESS_TEMPLATE.equals(template))
return new Process();
return null;
}
public Object getObjectType()
{
return template;
}
public static Chart getChart()
{
return new Chart();
}
public Path getPath()
{
return new Path();
}
}
In this case, getNewObject() checks to see if it recognizes the template. If it does, then
the method returns a constructed Model object that contains the component’s infor-
mation. In addition, this class contains two methods, getChart() and getPath(),
Listing D.3 ModelFactory.java
Create Model objects according
to their templates root
Create Model objects
without templates
The Model aspect: Model classes 407
which return Model objects for the Chart and Path components. These objects
require separate methods because they aren’t directly created with templates.
TemplateTransferDropTargetListeners
Like any drag-and-drop operation, a DropTargetListener must be present in
order to respond to a DropTargetEvent. GEF provides a class specifically for
responding to template drops: TemplateTransferDropTargetListener. This class
must be extended to identify the CreationFactory that will construct the Model.
For our flowchart editor, this subclass is FlowchartDropTargetListener; its
code is presented in listing D.4. We recommend that you add this class to the
com.swtjface.flowchart.dnd package.
package com.swtjface.flowchart.dnd;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.dnd.TemplateTransferDropTargetListener;
import org.eclipse.gef.requests.CreationFactory;
import com.swtjface.flowchart.model.ModelFactory;
public class FlowchartDropTargetListener
extends TemplateTransferDropTargetListener
{
public FlowchartDropTargetListener(EditPartViewer viewer)
{
super(viewer);
}
protected CreationFactory getFactory(Object template)
{
return new ModelFactory(template);
}
}
As you can see, the only difference between the FlowchartDropTargetListener
and the TemplateTransferDropTargetListener is the ModelFactory class. Now that
you know how these Model objects are created, you need to learn how they work.
D.4 The Model aspect: Model classes
The fundamental question in building Model classes is this: What information
should be saved to a file? You don’t need to persist each pixel in the main window.
Listing D.4 FlowchartDropTargetListener.java
Identifies class needed to
create Model objects
408 APPENDIX D
The Graphical Editing Framework (GEF)
A good rule of thumb is that every editable aspect of a component should be
saved and incorporated in its Model class. This section will show how these classes
are formed and how their structures are used in the flowchart editor.
D.4.1 Model classes and JavaBeans
The role of a Model class is to keep track of a component’s editable characteris-
tics, called properties. Each property has a mutator method (setXYZ()) to specify its
value and an accessor method (getXYZ()) to acquire it. The Model class also fires
events when these properties change. Both the event and listener classes needed
for this are provided by the java.beans package.
This relationship between Model classes and the JavaBean library is deliberate.
For those unfamiliar with component-based (JavaBean) software development,
the goal is to construct applications with simple, reusable objects that keep track
of information. Java doesn’t provide a specific class for JavaBeans, but instead
gives rules for their interfaces and methods. Because GEF Model classes follow
these rules, they’re considered JavaBeans.
In addition to the accessor and mutator methods, Sun’s JavaBean specification
also describes the event model needed for dealing with PropertyChangeEvents.
The GEF implementation of this model is shown in figure D.8. It’s important to
note that although the methods are contained in the Model class, the EditPart
invokes them.
Model
Creation
EditPart
Creation
Model
Change
EditPart
EventHandling
EventPart/Model
Disposal
Create
PropertyChange
Support
Invoke
addPropertyChange
Listener()
Invoke
fireProperty
Change()
Invoke
PropertyChange()
Invoke
removePropertyChange
Listener()
Figure D.8 The PropertyChangeEvent model for GEF Model classes
The Model aspect: Model classes 409
First, a Model object creates a PropertyChangeSupport instance during its cre-
ation. This enables an EditPart to listen to its PropertyChangeEvents. Then, when
the EditPart is created, it calls the Model’s addPropertyChangeListener()
method to be able to respond to these events. Whenever a property changes, the
Model calls its firePropertyChange() method, and the EditPart handles the
Event with its propertyChange() method. When the component is deallocated,
the EditPart calls the Model’s removePropertyChangeListener() method.
These methods must be available in each Model class you build. Therefore,
you can save yourself effort by creating an abstract class for your Models.
D.4.2 The AbstractChartElement class
Since all Model classes must contain these event-handling methods, it makes
sense to incorporate them in an abstract class. For our project, this class is called
AbstractChartElement. Listing D.5 presents the code for this class; we recom-
mend that you add it to the com.swtjface.flowchart.model package.
NOTE This class provides listeners for receiving events and methods to fire
them, but it doesn’t implement propertyChange(PropertyChangeEvent),
which is the only event-handling method in the PropertyChangeListener
interface. This method is invoked by the EditPart, which controls the
Model and View.
package com.swtjface.flowchart.model;
import java.io.*;
import java.beans.*;
abstract public class AbstractChartElement
implements Cloneable, Serializable
{
public static final String
SIZE = "size", LOC = "location", NAME = "name",
CHILD = "children", TARGETS = "targets", SOURCES = "sources";
transient protected PropertyChangeSupport listeners = new
PropertyChangeSupport(this);
public void addPropertyChangeListener(PropertyChangeListener pcl)
{
listeners.addPropertyChangeListener(pcl);
}
public void removePropertyChangeListener
(PropertyChangeListener pcl)
Listing D.5 AbstractChartElement.java
Properties to be
monitored
Provide property
monitoring
410 APPENDIX D
The Graphical Editing Framework (GEF)
{
listeners.removePropertyChangeListener(pcl);
}
protected void firePropertyChange(String propName,
Object old, Object newValue
{
listeners.firePropertyChange(propName, old, newValue);
}
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException
{
in.defaultReadObject();
listeners = new PropertyChangeSupport(this);
}
}
Each of the property changes has a String as a label. The first three, SIZE, LOC,
and NAME, refer to changes in a component’s size, location, and message, respec-
tively. A CHILD property change is fired whenever a new part is added to the con-
tainer (Chart). Similarly, TARGETS and SOURCES events are fired whenever a new
source or target connection is made or removed.
Another important point about this class is that it implements the Serializ-
able interface. This means concrete subclasses can be converted into bytes and
persisted in a file. The transient keyword preceding the PropertyChangeSupport
declaration means that this class cannot be serialized. Therefore, when the top-
level Model is saved to a file, it won’t include these objects. For this reason, the
readObject() method at the end of the code creates a new PropertyChangeSup-
port object when the Model is deserialized.
By making our Model classes descendants of AbstractChartElement, we ensure
that each of these methods will be available. The first concrete Model class that we’ll
discuss is Chart, which holds the information concerning the editor’s container.
D.4.3 The Chart class
Despite its importance, a Chart object doesn’t hold a great deal of data. Its func-
tion is to keep track of child Model classes by adding and removing them from an
ArrayList. The code for this class is shown in listing D.6; add it to com.swtj-
face.flowchart.model.
Provide property
monitoring
Send alert if property changes
The Model aspect: Model classes 411
package com.swtjface.flowchart.model;
import java.util.*;
public class Chart
extends AbstractChartElement
{
protected List children = new ArrayList();
public List getChildren()
{
return children;
}
public void addChild(Activity child)
{
children.add(child);
firePropertyChange(CHILD, null, child);
}
public void removeChild(Activity child)
{
children.remove(child);
firePropertyChange(CHILD, null, child);
}
}
These methods are straightforward: addChild() and removeChild() perform the
essential job of mutator methods, whereas getChildren() provides access to the
object’s properties. If any properties change, then a PropertyChangeEvent is cre-
ated and fired.
The Chart class may not be exciting, but as you’ll see later, it’s vital in saving
the editor’s contents to a file. Now that you’ve seen how these children are
arranged, let’s look at their abstract superclass, Activity.
D.4.4 The Activity class
For the flowchart editor’s Decision, Process, and Terminator components, five
fields need to be stored:
■ size—The part’s x and y dimensions, represented by a Dimension
■ location—The part’s position, represented by a Point
■ name—The part’s message, represented by a String
■ sources—The part’s SourceConnections, contained in a Vector
■ targets—The part’s TargetConnections, contained in a Vector
Listing D.6 Chart.java
412 APPENDIX D
The Graphical Editing Framework (GEF)
Since this list is the same for each Model, we’ll use the same class, Activity, to
hold the information for the components. This class will contain mutator and
accessor methods for each of the above properties.
Now that we have the Activity class, we can see the entire Model class hierar-
chy, shown in figure D.9.
The full code for the Activity class is shown in listing D.7.
package com.swtjface.flowchart.model;
import java.util.*;
import org.eclipse.draw2d.geometry.*;
import org.eclipse.ui.views.properties.*;
public class Activity
extends AbstractChartElement implements IPropertySource
{
// Information content of the Model class
private String name;
private Point location = new Point(0,0);
private Dimension size = new Dimension(-1,-1);
protected Vector targets = new Vector(2);
protected Vector sources = new Vector(2);
public Dimension getSize()
{return size;}
public void setSize(Dimension dim)
{
if (size.equals(dim)) return;
size = dim;
firePropertyChange(SIZE, null, size);
}
public Point getLocation() {return location;}
public void setLocation(Point place)
{
Listing D.7 Activity.java
AbstractChartElement
Chart Activity Path
Decision Process Terminator
Figure D.9
The Model classes of the
flowchart editor
Accessor/mutator
method for
Model class
The Model aspect: Model classes 413
if (location.equals(place)) return;
location = place;
firePropertyChange(LOC, null, place);
}
public String getName()
{return name;}
public void setName(String str)
{
if (str.equals(name)) return;
name = str;
firePropertyChange(NAME, null, str);
}
public Vector getConnections()
{
Vector v = getSourceConnections();
v.addAll(getTargetConnections());
return v;
}
public Vector getSourceConnections()
{
return (Vector)sources.clone();
}
public void addSourceConnection(Path p)
{
sources.add(p);
firePropertyChange(SOURCES, null, p);
}
public void removeSourceConnection(Path p)
{
sources.remove(p);
firePropertyChange(SOURCES, null, p);
}
public Vector getTargetConnections()
{
return (Vector)targets.clone();
}
public void addTargetConnection(Path p)
{
targets.add(p);
firePropertyChange(TARGETS, null, p);
}
public void removeTargetConnection(Path p)
{
targets.remove(p);
firePropertyChange(TARGETS, null, p);
Accessor/mutator
method for
Model class
414 APPENDIX D
The Graphical Editing Framework (GEF)
}
public Object getEditableValue()
{return null;}
public IPropertyDescriptor[] getPropertyDescriptors()
{
return new IPropertyDescriptor[]
{
new TextPropertyDescriptor(NAME, "Name"),
new TextPropertyDescriptor(SIZE, "Size"),
new TextPropertyDescriptor(LOC, "Location")
};
}
public Object getPropertyValue(Object propName)
{
if (propName.equals(SIZE))
return getSize().width + "," + getSize().height;
else if(propName.equals(LOC))
return getLocation().x + "," + getLocation().y;
else if(propName.equals(NAME))
return getName();
return null;
}
public void setPropertyValue(Object propName, Object value)
{
String str = (String)value;
int comma = str.indexOf(",");
if (propName.equals(SIZE))
setSize(new Dimension(Integer.parseInt
(str.substring(0,comma)),
Integer.parseInt(str.substring(comma+1))));
else if (propName.equals(LOC))
setLocation(new Point(Integer.parseInt
(str.substring(0,comma)),
Integer.parseInt(str.substring(comma+1))));
else if (propName.equals(NAME))
setName(str);
}
public boolean isPropertySet(Object id)
{return true;}
public void resetPropertyValue(Object id)
{}
}
A bit longer than the Chart Model, isn’t it? As you can see, keeping track of many
properties can be complicated, especially Connections. But in addition, we’ve
Interface with
Eclipse
Property
View
Interface
with
Eclipse
Property
View
The Model aspect: Model classes 415
added six methods needed to implement the IPropertySource interface. By doing
so, users can change the size, location, and name of an Activity component
using a Property View. This window is provided by the Eclipse Workbench; an
example is shown in figure D.10.
The IPropertySource methods make it possible to transfer property values
between the Model and Eclipse’s Property View: The first method, getProperty-
Descriptors(), tells the View what properties it needs to display and that input
should be provided through a textbox. The next two methods get and set the
EditPart’s property values; the fourth, resetPropertyValue(), returns the default
property. isPropertySet() returns whether the property value is equal to its
default, and getEditableValue() returns the object responsible for keeping track
of the EditPart’s property.
Now that we’ve taken care of the abstract superclass, we need to create the con-
crete subclasses. The code for these Model classes—Decision, Process, and Ter-
minator—is shown in listings D.8, D.9, and D.10.
package com.swtjface.flowchart.model;
import org.eclipse.draw2d.geometry.Dimension;
public class Decision extends Activity
{
public Decision()
{
setName("Decision");
setSize(new Dimension(100,60));
}
}
Listing D.8 Decision.java
Figure D.10
Example property view for
the flowchart editor
416 APPENDIX D
The Graphical Editing Framework (GEF)
import org.eclipse.draw2d.geometry.Dimension;
public class Process extends Activity
{
public Process()
{
setName("Process");
setSize(new Dimension(80,40));
}
}
package com.swtjface.flowchart.model;
import org.eclipse.draw2d.geometry.Dimension;
public class Terminator extends Activity
{
public Terminator()
{
setName("Term");
setSize(new Dimension(80,20));
}
}
These classes do nothing more than set their message and size during construc-
tion. It’s easy to remove them and use only the Activity Model class. However, for
the purposes of teaching the GEF, we’ve made sure that each MVC triple has its
own Model class.
D.4.5 The Path class
In addition to creating classes for the Activity components, we need to create
Model classes for their Connections. This Path class doesn’t fire PropertyChan-
geEvents or display information in the Property View, but it keeps track of which
Activity objects it connects (source and target) and the names of its anchors
(sourceName and targetName). The code for this class is provided in listing D.11.
package com.swtjface.flowchart.model;
public class Path
extends AbstractChartElement
{
Listing D.9 Process.java
Listing D.10 Terminator.java
Listing D.11 Path.java
The Model aspect: Model classes 417
protected Activity source, target;
protected String sourceName, targetName;
public void attachSource()
{
if (getSource() == null ||
getSource().getSourceConnections().contains(this))
return;
getSource().addSourceConnection(this);
}
public void detachSource()
{
if (getSource() == null)
return;
getSource().removeSourceConnection(this);
}
public void attachTarget()
{
if (getTarget() == null ||
getTarget().getTargetConnections().contains(this))
return;
getTarget().addTargetConnection(this);
}
public void detachTarget()
{
if (getTarget() == null)
return;
getTarget().removeTargetConnection(this);
}
public Activity getSource()
{
return source;
}
public void setSource(Activity e)
{
source = e;
}
public Activity getTarget()
{
return target;
}
public void setTarget(Activity e)
{
target = e;
}
public String getSourceName()
418 APPENDIX D
The Graphical Editing Framework (GEF)
{
return sourceName;
}
public void setSourceName(String s)
{
sourceName = s;
}
public String getTargetName()
{
return targetName;
}
public void setTargetName(String s)
{
targetName = s;
}
}
Again, these methods are easy to understand. The only new concepts involve
attaching and detaching Connections. These functions tell their source and target
Activity Models that a new Connection has been added or removed. This is one
of the few instances where one Model class interacts with another.
The process of modifying components begins with the mutator methods of the
Model classes and the PropertyChangeEvents that they fire. However, these meth-
ods are only invoked by Command objects. Therefore, to continue discussing the
editing process, our next step must involve investigating Commands.
D.5 Changing Model properties with Commands
When we briefly discussed Commands in the last section, we mentioned how they’re
created in response to Requests. We can’t discuss the full process by which a
Request becomes a Command just yet. But in this section, we’ll describe the Com-
mand’s purpose and structure and then build customized classes for our editor.
D.5.1 Commands and CommandStacks
It’s possible to extend the Request class, but doing so is generally unnecessary
since GEF provides so many subclasses of its own. However, you’ll have to build all
your own Command classes; you must do so because Commands interact with Model
objects, which have no standard structure beyond accessor/mutator methods. But
GEF does provide an abstract Command class, and it’s important that you under-
stand how it works.
Changing Model properties with Commands 419
The execute() method performs the real work of the Command by invoking the
mutator methods (setXYZ()) of the Model class. This execute() method is called
by the active Tool after it receives the Command in response to its Request. Commands
can also have other methods and fields associated with them, and these are gener-
ally used to provide information for the execute() method.
Two other important Command methods are undo() and redo(). As expected,
these methods are used to reverse the results of execute() or reinvoke it. For
these methods to work, the editor must keep track of which Commands have been
executed. The data structure used for this task is the CommandStack, which is ini-
tialized during the editor’s construction. This object pushes executed Commands
onto its Undo stack and pushes undone Commands onto its Redo stack. The Redo
stack is cleared whenever a new Command is executed.
Our flowchart editor needs four concrete Command classes. We’ll start with the
first Command that will be executed in a normal GEF editor: the CreateCommand.
D.5.2 The CreateCommand class
The CreateCommand is used to update the Chart container with a new component.
It also initializes the properties of the new component by setting its size and loca-
tion. The execute() method of the CreateCommand is simple and requires only the
Model class of the parent (parent), the added child (child), and the child’s
bounds (rect). The code is provided in listing D.12.
package com.swtjface.flowchart.commands;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import com.swtjface.flowchart.model.*;
public class CreateCommand extends Command
{
private Chart parent;
private Activity child;
private Rectangle rect;
public void execute()
{
if (rect != null)
{
child.setLocation(rect.getLocation());
if (!rect.isEmpty())
child.setSize(rect.getSize());
}
parent.addChild(child);
Listing D.12 CreateCommand.java
420 APPENDIX D
The Graphical Editing Framework (GEF)
}
public void setParent(Chart sa)
{parent = sa;}
public void setChild(Activity activity)
{child = activity;}
public void setConstraint(Rectangle bounds)
{rect = bounds;}
public void redo()
{execute();}
public void undo()
{parent.removeChild(child);}
}
The execute() method calls the setLocation() and setSize() methods of the
Activity object and adds the new child to the Chart with its addChild() method.
The redo() method reinvokes execute(), and undo() calls the removeChild()
method. The setParent(), setChild(), and setConstraint() methods provide
initialization parameters to the Command during its formation.
The CreateCommand class is simple to understand. However, because the Path-
Command deals with Path objects, it’s slightly more complicated.
D.5.3 The PathCommand class
The process of creating a Connection presents greater complications than build-
ing a child Model class in a parent. With connections, or Paths in our case, the
Model must keep track of both of the components to which it’s attached and the
names of the anchors in each component. Also, just as the CreateCommand adds an
Activity to a Chart, this command tells both the source and target Activity
objects to add this Path to their ArrayLists (see listing D.13).
package com.swtjface.flowchart.commands;
import org.eclipse.gef.commands.Command;
import com.swtjface.flowchart.model.*;
public class PathCommand
extends Command
{
protected Activity oldSource, source;
protected Activity oldTarget, target;
Listing D.13 PathCommand.java
Changing Model properties with Commands 421
protected String oldSourceName, sourceName;
protected String oldTargetName, targetName;
protected Path path;
public PathCommand()
{}
public boolean canExecute()
{
return true;
}
public void execute()
{
if (source != null)
{
path.detachSource();
path.setSource(source);
path.setSourceName(sourceName);
path.attachSource();
}
if (target != null)
{
path.detachTarget();
path.setTarget(target);
path.setTargetName(targetName);
path.attachTarget();
}
}
public void redo()
{
execute();
}
public void undo()
{
source = path.getSource();
target = path.getTarget();
sourceName = path.getSourceName();
targetName = path.getTargetName();
path.detachSource();
path.detachTarget();
path.setSource(oldSource);
path.setTarget(oldTarget);
path.setSourceName(oldSourceName);
path.setTargetName(oldTargetName);
path.attachSource();
path.attachTarget();
}
public void setSource(Activity newSource)
422 APPENDIX D
The Graphical Editing Framework (GEF)
{
source = newSource;
}
public void setSourceName(String newSourceName)
{
sourceName = newSourceName;
}
public void setTarget(Activity newTarget)
{
target = newTarget;
}
public void setTargetName(String newTargetName)
{
targetName = newTargetName;
}
public void setPath(Path p)
{
path = p;
oldSource = p.getSource();
oldTarget = p.getTarget();
oldSourceName = p.getSourceName();
oldTargetName = p.getTargetName();
}
}
This Command changes the properties of the Path and its source and target Activ-
ity objects, but not the Chart. It’s important to understand that Connection
objects aren’t considered children of other components; they’re part of an inter-
nal Vector in each EditPart.
Now that you know how new Model classes are created, the next class describes
how they’re removed from the Chart and deallocated.
D.5.4 The DeleteCommand class
The DeleteCommand reverses the actions of both the CreateCommand and the Path-
Command and is performed in two steps. First, it deletes the Path objects associated
with the selected component. This process involves detaching the Path from both
the deleted component and the one to which it was attached. The second step
removes the child Activity from the parent Chart. This is shown in listing D.14.
Changing Model properties with Commands 423
package com.swtjface.flowchart.commands;
import java.util.*;
import org.eclipse.gef.commands.Command;
import com.swtjface.flowchart.model.*;
public class DeleteCommand extends Command
{
private Chart parent;
private Activity child;
private List sourceConnections = new ArrayList();
private List targetConnections = new ArrayList();
private void deleteConnections(AbstractChartElement a)
{
if (a instanceof Chart)
{
List children = ((Chart)a).getChildren();
for (int i = 0; i < children.size(); i++)
deleteConnections((Activity)children.get(i));
}
else
{
sourceConnections.addAll
(((Activity)a).getSourceConnections());
for (int i = 0; i < sourceConnections.size(); i++)
{
Path path = (Path)sourceConnections.get(i);
path.detachSource();
path.detachTarget();
}
targetConnections.addAll
(((Activity)a).getTargetConnections());
for (int i = 0; i < targetConnections.size(); i++)
{
Path path = (Path)targetConnections.get(i);
path.detachSource();
path.detachTarget();
}
}
}
public void execute()
{
deleteConnections(child);
parent.removeChild(child);
}
private void restoreConnections()
{
Listing D.14 DeleteCommand.java
424 APPENDIX D
The Graphical Editing Framework (GEF)
for (int i = 0; i < sourceConnections.size(); i++)
{
Path path = (Path)sourceConnections.get(i);
path.getTarget().addTargetConnection(path);
path.getSource().addSourceConnection(path);
}
sourceConnections.clear();
for (int i = 0; i < targetConnections.size(); i++)
{
Path path = (Path)targetConnections.get(i);
path.getSource().addSourceConnection(path);
path.getTarget().addTargetConnection(path);
}
targetConnections.clear();
}
public void setChild (Activity a)
{child = a;}
public void setParent(Chart c)
{parent = c;}
public void redo()
{execute();}
public void undo()
{
parent.addChild(child);
restoreConnections();
}
}
The code is somewhat involved, but the theory of operation is straightforward.
The execute() method removes the Path objects from both the source and target
Activity objects, and then it removes the deleted Activity objects from the
Chart. The undo() method restores the component’s connections and adds it to
the Chart.
D.5.5 The SetConstraintCommand class
So far, we’ve created Commands that modify every aspect of the editor’s Model
except the appearance of the individual components. Since we want the user to
be able to change the size and shape of Activity objects, we need to create a Com-
mand that invokes their appropriate mutator methods. This is the purpose of the
SetConstraintCommand, which is one of the simplest of the Commands in our project.
Its code is presented in listing D.15.
Changing Model properties with Commands 425
package com.swtjface.flowchart.commands;
import org.eclipse.draw2d.geometry.*;
import com.swtjface.flowchart.model.*;
public class SetConstraintCommand
extends org.eclipse.gef.commands.Command
{
private Point oldPos, newPos;
private Dimension oldSize, newSize;
private Activity act;
public void execute()
{
oldSize = act.getSize();
oldPos = act.getLocation();
act.setLocation(newPos);
act.setSize(newSize);
}
public void setLocation(Rectangle r)
{
setLocation(r.getLocation());
setSize(r.getSize());
}
public void setLocation(Point p)
{newPos = p;}
public void setPart(Activity part)
{this.act = part;}
public void setSize(Dimension p)
{newSize = p;}
public void redo()
{
act.setSize(newSize);
act.setLocation(newPos);
}
public void undo()
{
act.setSize(oldSize);
act.setLocation(oldPos);
}
}
Listing D.15 SetConstraintCommand.java
426 APPENDIX D
The Graphical Editing Framework (GEF)
This Command changes the Activity’s size and location parameters, but not its
name. For this, we’ll use a direct statement from the Activity’s EditPart, which
we’ll discuss next.
D.6 The Controller aspect: EditPart classes
Now that we’ve handled the View and Model aspects of the application’s compo-
nents, we need to start building their Controllers, represented by EditPart
objects. Previously, we described the function of a Controller as “everything else,”
but now we need to be more specific. An EditPart’s activity may be divided into
three main functions:
■ Respond to Model changes and update the component’s View
■ Keep track of the component’s Connections and ConnectionAnchors
■ Activate EditPolicys and associate them with their editing roles
The first function is important to understand. An EditPart’s activate() method
is called during its creation. This invokes the Model’s addPropertyChangeLis-
tener() method and enables the EditPart to respond to property changes in the
Model. This response is performed with the propertyChange() method, which
updates the View with the new information from the Model.
For example, when a SetConstraintCommand is executed, it calls the Model’s
setSize() and setLocation() methods. When these properties change, the two
PropertyChangeEvents are received by the EditPart, which modifies the Figure’s
size and location.
In addition to updating size and location, many EditParts must manage Con-
nection objects. These EditParts need to implement the NodeEditPart interface,
which provides methods for matching Connections with ConnectionAnchors. When
a PathCommand needs to know where to attach a new Connection, it communicates
with a NodeEditPart.
The last EditPart function deals with EditPolicys, which determine the differ-
ent ways the component can be edited. These policies function by creating Com-
mand objects in response to Requests. An EditPart specifies its applicable policies
with the createEditPolicies() method and contains them in a List. We’ll discuss
these objects further in the next section.
Although we refer to these objects as EditParts, all of the GEF Controllers are
really extensions of the AbstractGraphicalEditPart class. This class provides
many of the methods needed for Connection management and child/parent
interaction. It also creates a default DragTracker object to handle DragEvents.
The Controller aspect: EditPart classes 427
The EditPart class hierarchy for our flowchart editor is shown in figure D.11. Just
as we had an abstract class for Activity models, we now have an abstract Activi-
tyPart for our Process, Decision, and Terminator EditParts. The editor also
includes ChartParts for the container and PathParts that extend the Connec-
tionEditPart class.
Before we can discuss the individual classes, we need to show how these objects
are created. Therefore, our next subject is the EditPartFactory class.
D.6.1 Creating new EditParts with EditPartFactory objects
Earlier, we showed how palettes add Model classes to the parent container, but we
didn’t mention how new EditParts are formed. When a new child Model is cre-
ated from its template, the parent Model fires a PropertyChangeEvent. In
response, the parent EditPart invokes its refreshChildren() method. If any child
Models exist without matching EditParts, then this method calls the create-
Child() method.
createChild() accesses the editor’s EditPartFactory object. Just as our Model-
Factory created Model classes according to templates, our PartFactory creates
EditParts according to their Models. The interface specifies only one method,
createEditPart(); as listing D.16 shows, this is the only method we need. If you’re
coding these classes, we recommend that you add this class (and all the classes in
this section) to the com.swtjface.flowchart.editpart package.
AbstractGraphicalEditPart
ChartPart ActivityPart AbstractConnection
Edit Part
DecisionPart ProcessPart PathPart
TerminatorPart
Figure D.11
The EditPart hierarchy
for the flowchart editor
428 APPENDIX D
The Graphical Editing Framework (GEF)
package com.swtjface.flowchart.editpart;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.model.Process;
public class PartFactory implements EditPartFactory
{
public EditPart createEditPart(EditPart context, Object model)
{
EditPart part = null;
if (model instanceof Decision)
part = new DecisionPart();
else if (model instanceof Process)
part = new ProcessPart();
else if (model instanceof Terminator)
part = new TerminatorPart();
else if (model instanceof Path)
part = new PathPart();
else if (model instanceof Chart)
part = new ChartPart();
part.setModel(model);
return part;
}
}
Like the ModelFactory class, the PartFactory is simple. However, the operation of
the individual EditParts is more involved. We’ll begin with the parent EditPart of
the flowchart editor, the ChartPart.
D.6.2 The ChartPart class
A GraphicalViewer object is initialized by specifying the highest-level Model class
in the editor. In our case, this is the Chart class. Afterward, it calls its setCon-
tents() method, which tells the PartFactory to create a new ChartPart. The
viewer’s RootEditPart uses this object to create, activate, and remove child com-
ponents from the editor. The code for this class is presented in listing D.17.
package com.swtjface.flowchart.editpart;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import org.eclipse.draw2d.IFigure;
Listing D.16 PartFactory.java
Listing D.17 ChartPart.java
The Controller aspect: EditPart classes 429
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.editparts.*;
import com.swtjface.flowchart.figures.FigureFactory;
import com.swtjface.flowchart.model.Chart;
import com.swtjface.flowchart.policies.*;
public class ChartPart extends AbstractGraphicalEditPart
implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt)
{
String prop = evt.getPropertyName();
if (Chart.CHILD.equals(prop))
refreshChildren();
}
protected IFigure createFigure()
{
return FigureFactory.createChartFigure();
}
protected void createEditPolicies()
{
installEditPolicy(EditPolicy.LAYOUT_ROLE, new LayoutPolicy());
}
public void activate()
{
if (isActive())
return;
super.activate();
getChart().addPropertyChangeListener(this);
}
public void deactivate()
{
if (!isActive())
return;
super.deactivate();
getChart().removePropertyChangeListener(this);
}
protected Chart getChart()
{
return (Chart)getModel();
}
protected List getModelChildren()
{
return getChart().getChildren();
}
}
Update children if
CHILD property
Start monitoring
property changes
Stop monitoring
property changes
430 APPENDIX D
The Graphical Editing Framework (GEF)
The first method handles the PropertyChangeEvents created by the Chart object.
When invoked, it calls refreshChildren(), which activates child EditParts and
removes deleted children. The next method, createFigure(), builds a ChartFig-
ure using the FigureFactory. The createEditPolicies() method sets two policies
for the part and the roles they will perform. The next two methods take care of
activation and deactivation, and the last two methods access the Model object of
the EditPart and its children.
D.6.3 The ActivityPart class
Because of its connections and properties, the ActivityPart contains more meth-
ods than any other EditPart in our project. But, as shown in listing D.18, the
structure remains similar to that of ChartPart.
It begins with the event-handling method, propertyChange(), and continues
with the methods needed to alter the View. It contains activate() and deacti-
vate() methods, and it adds EditPolicys to its internal List. But after its Model-
accessing methods, the ActivityPart contains four methods related to Connec-
tionAnchor objects. These are the methods that the class must provide as part of
the NodeEditPart interface, which makes the process of adding and removing
Connections possible.
package com.swtjface.flowchart.editpart;
import java.beans.*;
import java.util.*;
import org.eclipse.draw2d.ConnectionAnchor;
import org.eclipse.draw2d.geometry.*;
import org.eclipse.gef.*;
import org.eclipse.gef.requests.DropRequest;
import com.swtjface.flowchart.figures.*;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.policies.*;
abstract public class ActivityPart
extends org.eclipse.gef.editparts.AbstractGraphicalEditPart
implements NodeEditPart, PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent evt)
Listing D.18 ActivityPart.java
The Controller aspect: EditPart classes 431
{
String prop = evt.getPropertyName();
if (Activity.CHILD.equals(prop))
refreshChildren();
else if (Activity.TARGETS.equals(prop))
refreshTargetConnections();
else if (Activity.SOURCES.equals(prop))
refreshSourceConnections();
else if (Activity.SIZE.equals(prop) ||
Activity.LOC.equals(prop) ||
Activity.NAME.equals(prop))
refreshVisuals();
}
protected void refreshVisuals()
{
getActivityFigure().setName(getActivity().getName());
Point loc = getActivity().getLocation();
Dimension size = getActivity().getSize();
Rectangle r = new Rectangle(loc ,size);
((GraphicalEditPart) getParent()).setLayoutConstraint
(this, getFigure(), r);
}
public void activate()
{
if (isActive())
return;
super.activate();
getActivity().addPropertyChangeListener(this);
}
public void deactivate()
{
if (!isActive())
return;
super.deactivate();
getActivity().removePropertyChangeListener(this);
}
protected void createEditPolicies()
{
installEditPolicy(EditPolicy.COMPONENT_ROLE,
new ComponentPolicy());
installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE,
new NodePolicy());
}
Update
feature
according to
property
name
Update name
and bounds
for Figure and
Model
432 APPENDIX D
The Graphical Editing Framework (GEF)
public ConnectionAnchor getSourceConnectionAnchor
(ConnectionEditPart connEditPart)
{
Path Path = (Path) connEditPart.getModel();
return getActivityFigure().
getSourceConnectionAnchor(Path.getSourceName());
}
public ConnectionAnchor getSourceConnectionAnchor
(Request request)
{
Point pt = new Point(((DropRequest)request).getLocation());
return getActivityFigure().getSourceConnectionAnchorAt(pt);
}
public ConnectionAnchor getTargetConnectionAnchor
(ConnectionEditPart connEditPart)
{
Path Path = (Path) connEditPart.getModel();
return getActivityFigure().
getTargetConnectionAnchor(Path.getTargetName());
}
public ConnectionAnchor getTargetConnectionAnchor
(Request request)
{
Point pt = new Point(((DropRequest)request).getLocation());
return getActivityFigure().getTargetConnectionAnchorAt(pt);
}
public String mapSourceConnectionAnchorToName
(ConnectionAnchor c)
{
return getActivityFigure().getSourceAnchorName(c);
}
public String mapTargetConnectionAnchorToName
(ConnectionAnchor c)
{
return getActivityFigure().getTargetAnchorName(c);
}
protected ActivityFigure getActivityFigure()
{
return (ActivityFigure) getFigure();
}
protected Activity getActivity()
{
return (Activity)getModel();
}
protected List getModelSourceConnections()
{
NodeEdit-
Part
interface
methods
The Controller aspect: EditPart classes 433
return getActivity().getSourceConnections();
}
protected List getModelTargetConnections()
{
return getActivity().getTargetConnections();
}
}
The one method not included in the ActivityPart is createFigure(), which is
needed to initialize the component’s View aspect. Because this is the only distin-
guishing factor between the ActivityPart’s subclasses, it must be specified in the
ProcessPart, DecisionPart, and TerminatorPart classes. The code for these
classes is shown in listings D.19, D.20, and D.21.
package com.swtjface.flowchart.editpart;
import org.eclipse.draw2d.IFigure;
import com.swtjface.flowchart.figures.FigureFactory;
public class ProcessPart extends ActivityPart
{
protected IFigure createFigure()
{
return FigureFactory.createProcessFigure();
}
}
package com.swtjface.flowchart.editpart;
import org.eclipse.draw2d.IFigure;
import com.swtjface.flowchart.figures.FigureFactory;
public class DecisionPart extends ActivityPart
{
protected IFigure createFigure()
{
return FigureFactory.createDecisionFigure();
}
}
package com.swtjface.flowchart.editpart;
import org.eclipse.draw2d.IFigure;
Listing D.19 ProcessPart.java
Listing D.20 DecisionPart.java
Listing D.21 TerminatorPart.java
434 APPENDIX D
The Graphical Editing Framework (GEF)
import com.swtjface.flowchart.figures.FigureFactory;
public class TerminatorPart extends ActivityPart
{
protected IFigure createFigure()
{
return FigureFactory.createTerminatorFigure();
}
}
It’s important to note that the ActivityPart object responds to events related to
new and deleted Connections, but the PathPart doesn’t. This is the case because
these events are triggered only once the source and target Connections are added
to the Activity’s Model.
D.6.4 The PathPart class
Since the PathPart doesn’t respond to Connection changes, and its activation and
deactivation are handled by the ConnectionEditPart superclass, all our class
needs to do is specify its applicable policies and the Figure that should be con-
structed upon its creation. The code is shown in listing D.22.
package com.swtjface.flowchart.editpart;
import org.eclipse.draw2d.*;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import com.swtjface.flowchart.figures.FigureFactory;
public class PathPart extends AbstractConnectionEditPart
{
protected void createEditPolicies()
{ }
protected IFigure createFigure()
{
return FigureFactory.createPathFigure();
}
}
Now that we’ve completed building the EditParts for the flowchart editor, we
need to examine their policies. This will enable us to finally show the entire pro-
cess of how a Tool’s Request becomes a Model’s Command.
Listing D.22 PathPart.java
Creating Commands with EditPolicy objects 435
D.7 Creating Commands with EditPolicy objects
Let’s say that your editing project has a ChangeColorCommand, and you want this Com-
mand to execute whenever the component receives a DirectEditRequest. For
another component, you want the ChangeShapeCommand to be executed for this
Request. Clearly, you need to modify the EditPart classes of these components, since
these are the objects that receive Requests. But how do you make this distinction?
The answer involves EditPolicys, which make it possible for EditParts to con-
trol how Commands are created in response to Requests. This section discusses how
EditPolicy objects operate, the policies provided by the GEF, and how they’re
implemented in our editor.
D.7.1 The getCommand() method
Just as execute() makes Command operation possible, the getCommand() method
performs the work for EditPolicys. Once a Tool determines which EditPart
should receive a given Request, it calls the part’s getCommand() method with the
Request object as its parameter. Then, the EditPart iterates through its list of
EditPolicy objects and invokes each of their getCommand() methods. In each case,
if the policy can respond to the Request, it returns a Command object to the Tool,
which executes it.
In addition, EditPolicys provide information to the Command that specify how its
execution should be performed. That is, they tell the Command which Model prop-
erties should be modified and provide any parameters associated with the Request.
D.7.2 GEF policies in the flowchart editor
Although you can create customized EditPolicys from scratch, the GEF toolset
provides a number of helpful abstract classes. To build concrete EditPolicys, you
only need to specify which Model objects and properties should be changed when
the Command executes. This section describes the main abstract policies we’ll need
for our editor and how you can extend them.
The flowchart editor needs three policies in order to function:
■ ComponentPolicy—Removes Activity objects from the Chart
■ NodePolicy—Manages the process of adding new Paths
■ LayoutPolicy—Creates and arranges Activity objects in the Chart
Each of these classes extends an existing GEF policy class. Their inheritance struc-
ture is shown in figure D.12.
436 APPENDIX D
The Graphical Editing Framework (GEF)
The ComponentEditPolicy creates Commands when an EditPart is deleted or
orphaned from a container. The GraphicalEditPolicy contains a number of sub-
classes for creating, deleting, and adding children to a LayoutManager. The Graph-
icalNodeEditPolicy subclass creates Commands for creating connections to and
from a component. The GEF library provides many more policies than those
shown in figure D.12, particularly subclasses of GraphicalEditPolicy; the library’s
documentation summarizes their functions.
Although our naming convention may seem lazy, there is a good reason. As we
add new components and more functionality to the editor, we need to keep track
of component behaviors. If we use names like ChartPolicy and ActivityPolicy,
then it will be difficult to see which capabilities are present and which need to be
added. Therefore, our policy names closely resemble those of their superclasses.
The LayoutPolicy class
The top-level policy in our project is the LayoutPolicy, which handles creating,
deleting, and reshaping components in the ChartPart. This policy places children
according to a Rectangle constraint, which specifies the component’s dimensions
and size. In addition, it lets the user resize children by creating a ResizableEdit-
Policy for each of its children.
AbstractEditPolicy
Component
EditPolicy
Graphical
EditPolicy
Component
Policy
Layout
EditPolicy
GraphicalNode
EditPolicy
ConstrainedLayout
EditPolicy
NodePolicy
XYLayout
EditPolicy
XYLayout
Policy
Figure D.12
The EditPolicy structure of the flowchart editor. Concrete
classes are shown in gray and abstract superclasses in white.
Creating Commands with EditPolicy objects 437
The code for this class is shown in listing D.23. This, and all classes in this sec-
tion, should be added to the com.swtjface.flowchart.policies package.
package com.swtjface.flowchart.policies;
import org.eclipse.draw2d.PositionConstants;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.*;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.*;
import org.eclipse.gef.requests.*;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.commands.*;
public class LayoutPolicy extends XYLayoutEditPolicy
{
protected Command createAddCommand(EditPart childEditPart,
Object constraint)
{
Activity part = (Activity) childEditPart.getModel();
Rectangle rect = (Rectangle)constraint;
CreateCommand create = new CreateCommand();
create.setParent((Chart)(getHost().getModel()));
create.setChild(part);
create.setConstraint(rect);
return create;
}
protected Command createChangeConstraintCommand
(EditPart child, Object constraint)
{
SetConstraintCommand locationCommand =
new SetConstraintCommand();
locationCommand.setPart((Activity)child.getModel());
locationCommand.setLocation((Rectangle)constraint);
return locationCommand;
}
protected Command createChangeConstraintCommand
(ChangeBoundsRequest request, EditPart child, Object constraint)
{
SetConstraintCommand cmd = (SetConstraintCommand)
createChangeConstraintCommand(child, constraint);
return cmd;
}
protected Command getCreateCommand(CreateRequest request)
{
Listing D.23 LayoutPolicy.java
Set parameters of
Command
438 APPENDIX D
The Graphical Editing Framework (GEF)
CreateCommand create = new CreateCommand();
create.setParent((Chart)(getHost().getModel()));
create.setChild((Activity)(request.getNewObject()));
Rectangle constraint = (Rectangle)getConstraintFor(request);
create.setConstraint(constraint);
return create;
}
protected Command getDeleteDependantCommand(Request request)
{return null;}
protected EditPolicy createChildEditPolicy(EditPart child)
{
ResizableEditPolicy policy = new ResizableEditPolicy();
policy.setResizeDirections(PositionConstants.EAST |
PositionConstants.WEST | PositionConstants.NORTH |
PositionConstants.SOUTH);
return policy;
}
}
The createAddCommand() and getDeleteDependantCommand() methods return null
because their functions are already accomplished: getCreateCommand() takes care
of building new components, and getDeleteCommand() deletes them. This second
method is part of our next policy, the ComponentPolicy.
The ComponentPolicy class
The ComponentEditPolicy superclass provides Commands when the user wants to
remove a component from its container (make it an orphan) or delete it alto-
gether. Since our only container in the flowchart is the ChartPart, there is no dif-
ference between becoming an orphan and being deleted. So, the only method in
listing D.24 creates a DeleteCommand.
package com.swtjface.flowchart.policies;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editpolicies.*;
import org.eclipse.gef.requests.*;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.commands.*;
public class ComponentPolicy extends ComponentEditPolicy
{
protected Command createDeleteCommand(GroupRequest request)
{
Listing D.24 ComponentPolicy.java
Specify how
figure can be
resized
Creating Commands with EditPolicy objects 439
Object parent = getHost().getParent().getModel();
DeleteCommand deleteCmd = new DeleteCommand();
deleteCmd.setParent((Chart)parent);
deleteCmd.setChild((Activity)getHost().getModel());
return deleteCmd;
}
}
Because our ActivityParts have so much work to do, they require two policies.
The ComponentPolicy shown in listing D.24 lets them handle their responsibili-
ties as child components. But in order to manage Connection objects, they need
a NodePolicy.
The NodePolicy class
The abstract GraphicalNodeEditPolicy class creates and initializes the parame-
ters of a PathCommand. The subclass in our editor is called NodePolicy, and its
code is shown in listing D.25. The createDummyConnection() serves an interesting
purpose: It doesn’t create a real Connection, but instead displays a new connec-
tion to the user before they choose a target component.
package com.swtjface.flowchart.policies;
import org.eclipse.draw2d.*;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.Request;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.requests.*;
import com.swtjface.flowchart.commands.*;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.figures.*;
import com.swtjface.flowchart.editpart.*;
public class NodePolicy
extends org.eclipse.gef.editpolicies.GraphicalNodeEditPolicy
{
protected Connection createDummyConnection(Request req)
{
PolylineConnection conn = FigureFactory.createPathFigure();
return conn;
}
protecded Command getConnectionCompleteCommand
(CreateConnectionRequest request)
{
PathCommand command = (PathCommand)request.getStartCommand();
Listing D.25 NodePolicy.java
Finish connection
440 APPENDIX D
The Graphical Editing Framework (GEF)
command.setTarget(getActivity());
ConnectionAnchor ctor = getActivityPart().
getTargetConnectionAnchor(request);
if (ctor == null)
return null;
command.setTargetName(getActivityPart().
mapTargetConnectionAnchorToName(ctor));
return command;
}
protected Command getConnectionCreateCommand
(CreateConnectionRequest request)
{
PathCommand command = new PathCommand();
command.setPath(new Path());
command.setSource(getActivity());
ConnectionAnchor ctor = getActivityPart().
getSourceConnectionAnchor(request);
command.setSourceName(getActivityPart().
mapSourceConnectionAnchorToName(ctor));
request.setStartCommand(command);
return command;
}
protected ActivityPart getActivityPart()
{return (ActivityPart) getHost();}
protected Activity getActivity()
{return (Activity) getHost().getModel();}
protected Command getReconnectTargetCommand
(ReconnectRequest request)
{
PathCommand cmd = new PathCommand();
cmd.setPath((Path)request.getConnectionEditPart().getModel());
ConnectionAnchor ctor = getActivityPart().
getTargetConnectionAnchor(request);
cmd.setTarget(getActivity());
cmd.setTargetName(getActivityPart().
mapTargetConnectionAnchorToName(ctor));
return cmd;
}
protected Command getReconnectSourceCommand
(ReconnectRequest request)
{
PathCommand cmd = new PathCommand();
cmd.setPath((Path)request.getConnectionEditPart().getModel());
ConnectionAnchor ctor = getActivityPart().
getSourceConnectionAnchor(request);
cmd.setSource(getActivity());
cmd.setSourceName(getActivityPart().
mapSourceConnectionAnchorToName(ctor));
Start connection
Reconnect target
Reconnect source
Adding Actions to the editor 441
return cmd;
}
protected ActivityFigure getActivityFigure()
{
return (ActivityFigure)((GraphicalEditPart)getHost()).getFigure();
}
}
We’ve presented Tools, Requests, Commands, and EditPolicys. But one class of GEF
objects demands our attention: Actions make it possible for menu items and tool-
bar options to perform the same kind of functionality as Tools, and they’re the
subject of the next section.
D.8 Adding Actions to the editor
Users expect multiple ways to accomplish an editing task. For example, the
Eclipse Workbench lets users copy GUI elements with a keystroke (Ctrl-C), a menu
item (Edit->Copy), or an option in a context menu. GEF enables you to provide
these capabilities through Actions.
These are essentially the same JFace Actions as those discussed in Chapter 4.
They can be associated with text, images, and accelerator keys; and they can
appear as buttons, toolbar items, or options in a menu. However, GEF’s Actions
have two important differences.
First, they’re subclasses of WorkbenchPartAction,
whose hierarchy is shown in figure D.13. Second,
although they invoke run() when activated, their opera-
tion varies from class to class. A SelectionAction func-
tions like a Tool by sending the selected component a
Request. StackActions function by accessing the Com-
mandStack, and EditorPartActions work by accessing
the EditorPart itself.
In order to function, WorkbenchPartActions need to
notify the editor of their presence. This is accomplished
by adding them to the editor’s ActionRegistry.
D.8.1 The ActionRegistry and ContextMenus
Every GraphicalEditor creates an ActionRegistry as part of its initialization and
populates it by calling createActions(). The code is shown here:
Figure D.13
A context menu in a
GEF editor
442 APPENDIX D
The Graphical Editing Framework (GEF)
action = new UndoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
action = new RedoAction(this);
registry.registerAction(action);
getStackActions().add(action.getId());
action = new SelectAllAction(this);
registry.registerAction(action);
action = new DeleteAction((IWorkbenchPart)this);
registry.registerAction(action);
getSelectionActions().add(action.getId());
action = new SaveAction(this);
registry.registerAction(action);
getPropertyActions().add(action.getId());
action = new PrintAction(this);
registry.registerAction(action);
We mention this code for two reasons. First, it’s helpful to know which Actions
have already been added to your GraphicalEditor by default. It also shows that,
in addition to the ActionRegistry, the editor keeps track of certain groups of
Action classes.
These groups include PropertyActions, which deal with changes to the editor’s
state; StackActions, which manipulate the CommandStack; and SelectionActions,
which communicate with selected components. If you intend to add custom
Actions to your editor, you need to register them in the ActionRegistry and add
them to any groups to which they belong. You do so by implementing the create-
Actions() method in your editor.
After you add your Actions to the editor, you need to make them available to the
user. One of the simpler ways to do this involves a ContextMenu, shown in figure D.14.
This menu is easily accessible by right-clicking in the editor’s main window.
WorkbenchPartAction
EditorPart
Action
Print
Action
Selection
Action
CopyTemplate
Action
Stack
Action
Save
Action
Alignment
Action
Delete
Action
DirectEdit
Action
Redo
Action
Undo
Action
Figure D.14
Actions provided
by the GEF
Adding Actions to the editor 443
For our flowchart editor, we’ll only use the Actions that are added by default,
so we won’t need to create any new classes. Instead, we’ll create a ContextMenuPro-
vider and add our desired Actions to it (see listing D.26). We recommend that
you add this class to the com.swtjface.flowchart.actions package.
package com.swtjface.flowchart.actions;
import org.eclipse.jface.action.*;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.gef.*;
import org.eclipse.gef.ui.actions.*;
public class FlowchartContextMenuProvider
extends ContextMenuProvider
{
private ActionRegistry actionRegistry;
public FlowchartContextMenuProvider(EditPartViewer viewer,
ActionRegistry registry)
{
super(viewer);
setActionRegistry(registry);
}
private ActionRegistry getActionRegistry()
{
return actionRegistry;
}
public void setActionRegistry(ActionRegistry registry)
{
actionRegistry = registry;
}
public void buildContextMenu(IMenuManager menu)
{
GEFActionConstants.addStandardActionGroups(menu);
IAction action;
action = getActionRegistry().getAction
(ActionFactory.UNDO.getId());
menu.appendToGroup(GEFActionConstants.GROUP_UNDO, action);
action = getActionRegistry().getAction
(ActionFactory.REDO.getId());
menu.appendToGroup(GEFActionConstants.GROUP_UNDO, action);
action = getActionRegistry().getAction
(ActionFactory.DELETE.getId());
if (action.isEnabled())
menu.appendToGroup(GEFActionConstants.GROUP_EDIT, action);
Listing D.26 FlowchartContextMenuProvider.java
Add menu to editor’s Viewer
Add GEF Action to
ContextMenu
Add GEF Action to
ContextMenu
444 APPENDIX D
The Graphical Editing Framework (GEF)
action = getActionRegistry().getAction
(ActionFactory.SAVE.getId());
if (action.isEnabled())
menu.appendToGroup(GEFActionConstants.GROUP_SAVE, action);
}
}
The buildContextMenu() method acquires a MenuManager and searches through
the ActionRegistry to find desired Actions. Then, it calls the appendToGroup()
method to include them in the context menu.
Context menus are helpful, but it would be more interesting to include our
Actions in the Eclipse Workbench. To accomplish this, we need to use a new kind
of Action.
D.8.2 Redirecting Workbench actions with RetargetAction
The Eclipse Workbench contains a number of global Actions that can be triggered
through its main menu and toolbar. We’d like to redirect them to allow users to
perform editing in our editor and use Actions such as Undo, Redo, and Delete.
The process is simple. First, we need to create a set of RetargetActions and add
them to the editor’s ActionRegistry. Then, these Actions must be made available
to the user. All of this can be accomplished with one class: ActionBarContributor.
RetargetActions
RetargetActions function by directing the effects of the Workbench’s internal
Actions to an application. When we use one of these Actions, its corresponding
menu option is available for our editor. For example, when we add the DeleteRe-
targetAction, the Workbench’s Edit->Delete can be used to delete an EditPart.
Table D.5 shows the RetargetActions provided by the GEF. Our editor uses the
DeleteRetargetAction, the CopyRetargetAction, and the UndoTargetAction.
There is no SaveRetargetAction because saving an editor’s contents is always
directed to the editor being used.
Add GEF Action to
ContextMenu
Adding Actions to the editor 445
The Label column in the table refers to whether the RetargetAction can be given
a custom label, which works like a tooltip. Only UndoRetargetAction and Redo-
RetargetAction are subclasses of LabelRetargetAction; the rest of the Retar-
getActions retain the label specified by the Workbench.
Because GEF makes RetargetActions so easy to use, we don’t need to create
separate classes for them. Instead, we only need a single ActionBarContributor.
The ActionBarContributor class
FlowchartProject’s plugin.xml file specifies its contributorClass field as
com.swtjface.Actions.FlowchartActionBarContributor. This tells the Work-
bench that this class will access and modify its resources. In particular, this class
functions by specifying which global Actions should be redirected and how they
should be made available to the user.
An ActionBarContributor adds Actions to an application’s main menu or
ToolBar/CoolBar. For the flowchart editor, we need to add RetargetActions to the
Workbench’s toolbar. The code for the FlowchartActionBarContributor is pre-
sented in listing D.27. If you’re coding these classes, we recommend that you add
this to the com.swtjface.flowchart.actions package.
package com.swtjface.flowchart.actions;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.gef.ui.actions.*;
public class FlowchartActionBarContributor
Table D.5 GEF retargetable actions
Action Function Label
AlignmentRetargetAction Aligns EditParts No
CopyRetargetAction Copies and pastes components No
DeleteRetargetAction Removes EditParts from the editor No
RedoRetargetAction Reexecutes the given Command Yes
UndoRetargetAction Negates the effect of the last Command execu-
tion
Yes
ZoomInRetargetAction Focuses on a smaller area within the editor No
ZoomOutRetargetAction Views a greater area of editor space No
Listing D.27 FlowchartActionBarContributor.java
446 APPENDIX D
The Graphical Editing Framework (GEF)
extends ActionBarContributor
{
protected void buildActions()
{
addRetargetAction(new UndoRetargetAction());
addRetargetAction(new RedoRetargetAction());
addRetargetAction(new DeleteRetargetAction());
}
public void contributeToToolBar(IToolBarManager toolBarManager)
{
toolBarManager.add(getAction(ActionFactory.UNDO.getId()));
toolBarManager.add(getAction(ActionFactory.REDO.getId()));
toolBarManager.add(getAction(ActionFactory.DELETE.getId()));
}
protected void declareGlobalActionKeys()
{}
}
These methods are easy to understand. The buildActions() method updates the
ActionRegistry with RetargetActions. Then declareGlobalActionKeys() can be
used to match them with keystrokes. The contributeToToolBar() method adds
them to the Workbench’s ToolBarManager.
Although the Actions in the flowchart editor are fairly simple, multifunctional
editors require many more capabilities. To add them, you need a sound under-
standing of how the Request-EditPolicy-Command process works. Therefore,
instead of discussing a new facet of the GEF, we’ll like to present two detailed,
complete examples of how the GEF performs component and connection editing.
D.9 Editing with GEF: two examples
We’ve discussed the GEF’s basic objects and their functions, but you haven’t seen
the full editing process from start to finish. Therefore, this section presents two
examples that show how a user-generated Event results in a modification to an
EditPart’s Model and View aspects. We hope these examples clarify how Tools,
EditParts, and Model classes function, and the relationships between them.
D.9.1 Example 1: deleting a component with a keystroke
Users expect that when they click a component and press the Delete key, the com-
ponent and its connections will disappear. This process is is simple and obvious to
the user, but it takes some time to understand what’s going on under the hood.
Retarget
Workbench Actions
to editor
Use Actions from
Workbench’s toolbar
to editor
Editing with GEF: two examples 447
1: EditorPart sends user-initiated event to Tool
The process of deleting a component has two Events. First, the component needs
to be selected. This could result from a number of actions, but we’ll assume the
user pressed and lifted her mouse button on the component. Next is a KeyEvent
fired by the Delete key.
The editor’s LightWeightSystem forwards the MouseEvent to the editor’s Edit-
Domain. The EditDomain determines which Tool should receive the Event and
invokes the Tool’s mouseDown() method. In our example, the EditDomain transfers
the MouseEvent to the SelectionTool. When the SelectionTool receives it, it
determines whether the cursor was over an EditPart. If so, it sends the EditPart a
SelectionRequest by invoking the part’s getCommand(Request) method.
2: KeyHandler receives Delete keystroke and responds
Once the EditPart is selected, the SelectionTool receives the Delete keystroke
and calls its KeyDown() method. However, this tool can’t recognize the Delete key,
so its method returns false.
But when the user releases the Delete key, the SelectionTool calls its KeyUp()
method, which sends the key to the editor’s KeyHandler. This object has already
been initialized with a HashMap containing pairs of keys and Action objects. There-
fore, it understands that the Delete key corresponds to a DeleteAction. Once the
KeyHandler matches the two, it invokes the DeleteAction’s run() method to exe-
cute the Action.
3: DeleteAction sends DeleteRequest to part
The DeleteAction’s run() method invokes its createRequest() method to gener-
ate a DeleteRequest. It sends the Request object to the selected EditPart by invok-
ing the part’s getCommand(Request) method with a DeleteRequest. If multiple
EditParts have been selected for deletion, then a DeleteRequest is sent to each.
4: EditPart determines which EditPolicy to use
When its getCommand() method is invoked, the EditPart accesses its List of Edit-
Policys, which was populated with createEditPolicies(). The EditPart then
calls the getCommand() method contained in each of its EditPolicy classes, and if
any can accept the DeleteRequest, it returns a Command object. Those that can’t do
so return null. If multiple EditPolicys return a Command, the EditPart combines
them using the chain() method contained in the Command class.
448 APPENDIX D
The Graphical Editing Framework (GEF)
5: Policy returns DeleteCommand to delete EditPart
When the EditPart has finished cycling through its available policies, its getCom-
mand() method completes; it returns a DeleteCommand object if any of these policies
were able to interpret the DeleteRequest. If so, the execute() method of the
DeleteCommand is called. In our code, this method removes the Connection objects
associated with the EditPart. Then, it invokes the parent’s removeChild() method.
6: EditPart’s parent deactivates part
When its removeChild() method is called, the parent Model object removes the
child EditPart from its list of children and fires a PropertyChangeEvent. The par-
ent’s EditPart responds by calling propertyChange(). In our editor, this method
invokes refreshChildren().
This method searches through the parent’s List of child Models and their
EditParts. Since the deleted part’s Model has been removed, the parent invokes
removeChild(), which calls the part’s deactivate() and removeNotify() methods.
These methods tell the part to remove its ConnectionEditParts and children.
Finally, the parent’s removeChildVisual() method removes the child’s Figure
from the editor.
D.9.2 Example 2: how connections are created
To further describe GEF’s Event-Request-Policy-Command-PropertyChangeEvent
methodology, this subsection will present a second example involving connec-
tions between EditParts. So far, we’ve created a great deal of code that creates
and manipulates these objects, but we haven’t described their interrelated activity.
1: User’s palette selection creates Tool
Users start the process by clicking the ConnectionCreationToolEntry in the Flow-
chartPalette. Doing so creates a ConnectionCreationTool object, which now han-
dles all external events.
2: User chooses an EditPart as connection source
If the user clicks an EditPart, the ConnectionCreationTool creates a CreateCon-
nectionRequest and initializes it with the location of the mouse click. The tool
then determines which part has been targeted and sends the request by invoking
the part’s getCommand() method.
Editing with GEF: two examples 449
3: CreateConnectionRequest becomes a Command
When the Editpart receives the request from the tool, it searches its policies in
the EditPolicyIterator to see if any can respond. In the case of our flowchart
editor, the NodePolicy, a subclass of GraphicalNodeEditPolicy, starts the response
by creating a PathCommand and initializing its parameters. These four parameters
are as follows:
■ The Path object, which holds the connection information
■ The Activity object from which the connection starts (source)
■ The ActivityPart’s ConnectionAnchor
■ The String name used to represent the ConnectionAnchor
To initialize the first two fields, the tool creates a new Path object and uses the
selected ActivityPart as the source. Getting the third and fourth fields is more
involved.
This process starts by invoking the part’s getConnectionAnchor() method with
the location of the selection. This method calls getConnectionAnchorAt() method
in the Activity class, which returns the anchor object. To match the anchor to
the terminal name, the policy calls the ActivityPart’s mapConnectionAnchorTo-
Terminal() method, which finds the terminal by calling the ActivityFigure’s
getConnectionAnchorName() method. Once the command is fully initialized with
the anchor and terminal, it’s sent to the ConnectionCreationTool as the return
value of the getCommand() method.
It’s important to understand that this Command won’t be executed immediately.
Instead, it’s stored in the startCommand field of the request and is executed after
the second EditPart has been selected.
4: Tool creates new Path object
When the ConnectionCreationTool receives the command, it sets the editor’s state
to STATE_CONNECTION_STARTED. Then, it uses its handleMove() method to update
the editor’s appearance. This means creating a Path object between the source’s
anchor and the current mouse position. The process of providing this graphical
update, or feedback, begins with invoking the source ActivityPart’s showSource-
Feedback() method with a new CreateConnectionRequest. The part passes this
request to its policies and, by default, invokes the showSourceFeedback() method
of the GraphicalNodeEditPolicy. This method calls the createDummyConnection()
method of our NodePolicy, which returns the new Path object.
450 APPENDIX D
The Graphical Editing Framework (GEF)
5: User moves mouse and chooses second EditPart
As the user moves the pointer, the ConnectionCreationTool continually checks
whether the mouse is pointing to an EditPart. If so, the target Activity provides
feedback by moving the Connection’s endpoint to one of its ConnectionAnchors.
The tool also sends the part an updated ConnectionRequest by invoking the part’s
getCommand() method.
As before, the request is sent to the target part’s ActivityPolicy, which
updates the PathCommand created by the source part. This update involves setting
the Command’s target field equal to the target Activity and setting the targetName
field equal to name of the target’s ConnectionAnchor.
If the user clicks a second EditPart, then the tool changes the state from
STATE_CONNECTION_STARTED to STATE_TERMINAL. It also erases the dummy Polyline-
Connection and begins creating the connection.
6: PathCommand executes
The PathCommand’s execute() method creates the Connection. First, it sets the
Path’s source, sourceName, target, and targetName fields equal to the source
Activity, the name of the source’s ConnectionAnchor, the target Activity, and
the name of the target’s ConnectionAnchor, respectively. Finally, it informs the
source and target that they’re the source and target of a new connection.
Both the source and target Activities fire PropertyChangeEvents, and their
ActivityParts respond by invoking refreshSourceConnections() and refresh-
TargetConnections(). Since these parts have Path objects without PathParts, this
method creates PathParts using the PartFactory.
Now that you have a thorough understanding of Tools, Actions, Requests,
EditPolicys, and Commands, it’s time to work with the class that brings them all
together. The next section deals with the EditorPart.
D.10 Introducing the EditorPart
If you’ve come this far, you have our respect. Learning how GEF operates is diffi-
cult, but you’re near the end of the road. We’re now going to discuss the object
that brings everything together: EditorPart. This section will cover this class and
the GraphicalViewer that does most of the work. We’ll finish by showing the final
code for the FlowchartEditor.
Introducing the EditorPart 451
D.10.1 Working with EditorParts and GraphicalEditors
Graphical components in the Eclipse Workbench are divided into views and edi-
tors. Views, which extend the ViewPart class, organize and display information
about the Workbench. Editors function by allowing the user to manipulate and
save files; they descend from the EditorPart class.
Both EditorPart and its superclass, WorkbenchPart, are abstract classes with
abstract methods. Therefore, if you’re seeking to build an Eclipse editor, you must
provide code for each of these methods, shown in table D.6.
The two most important of these are init() and createPartControl(). The Work-
bench calls init() when the user opens a file with the supported extension.
Then, to display the editor, the workbench calls createPartControl(). Like the
createContents() method of a JFace Window, this method embodies the editor’s
appearance within a Composite object.
The nature of this Composite determines how the editor looks and acts. For
text editors, this is one large Text box. Graphical editors use a Canvas, but there’s
much more to a graphical editor than this object. To provide added functionality,
GEF supplies an EditorPart subclass, GraphicalEditor.
The documentation recommends using the GraphicalEditor class as a refer-
ence, but we’ll directly integrate one in our flowchart editor. This class provides a
number of important capabilities to the editor, such as an ActionRegistry, a
Table D.6 Abstract methods of the WorkbenchPart and EditorPart classes
Method Function
WorkbenchPart.createPartControl
(Composite)
Specifies the Composite control that provides the
editor’s appearance
WorkbenchPart.setFocus() Gives the focus property to the editor
EditorPart.init(IEditorSite,
IEditorInput)
Initializes the editor with the given location and input
(file)
EditorPart.isDirty() Returns whether the editor content has changed
EditorPart.doSave
(ProgressMonitor)
Specifies actions when editor content is saved to its
file
EditorPart.doSaveAs() Specifies actions when editor content is saved to a
new file
EditorPart.isSaveAllowed() Specifies whether the SaveAs operation is enabled
EditorPart.gotoMarker() Changes the selection based on the presence of
markers
452 APPENDIX D
The Graphical Editing Framework (GEF)
CommandStack, an EditDomain, and a SelectionSynchronizer to coordinate selec-
tions across multiple viewers. Its most important feature is the GraphicalViewer,
which accomplishes the main work of a GEF editor.
D.10.2 Understanding the GraphicalViewer
Earlier, we mentioned that JFace Viewers serve as adapters for Widgets and can
simplify and extend the capabilities of their underlying components. Therefore,
you can think of a GEF editor as a GraphicalViewer on top of a Canvas object. It
handles events, keeps track of the user’s selections, and creates the basis for the
editor’s EditPart hierarchy.
Our editor’s Viewer extends GraphicalViewerImpl, a concrete class that imple-
ments the GraphicalViewer interface. The best way to see how this object works is
to examine its methods, shown in table D.7.
The first two methods create the structure underlying the GEF editor. First, the
createControl() method builds the SWT Canvas object. Afterward, it creates a
LightWeightSystem to hold the editor’s Draw2D Figures. These objects also pro-
vide a channel through which the Viewer can receive Events.
Table D.7 Important methods of the GraphicalViewerImpl class
Method Function
createControl() Constructs the Canvas beneath the graphical editor
createLightweightSystem() Builds the Draw2D object to handle events and Figures
setRootEditPart() Creates the EditPart that activates all its children
setRootFigure() Specifies the top-level Figure for this editor
setContents() Specifies the top-level Model class for the editor (Chart)
getEditPartFactory() Finds the class to create an EditPart based on its Model
setRouteEventsToEditDomain() Transfers Events from the LightweightSystem to the
EditDomain
addDragSourceListener() Keeps track of components being moved
addDropTargetListener() Keeps track of components being dropped
setKeyHandler() Keeps track of the user’s keystrokes
addSelectionChangedListener() Listens for changes in the user’s selection
findObjectAtExcluding() Determines which EditPart was selected by the user
getSelectedEditParts() Obtains a list of the EditParts in the selection
Introducing the EditorPart 453
The next two methods provide a basis for the editor’s MVC structure. First, the
setRootEditPart() creates a new top-level parent for the EditPart hierarchy. It’s
important to understand that this is not a part that we’ve created previously. It
doesn’t perform event handling or specify EditPolicys; it does interact with the
editor’s Layers, but its main purpose is to manage child EditParts.
Another purpose of the RootEditPart is to specify a Figure to create when set-
RootFigure() is invoked. Again, this isn’t a Figure that we’ve coded. The nature of
this Figure depends on the RootEditPart. In our case, because we’re using a Scal-
ableRootEditPart, the Viewer creates a new Viewport with a LayeredPane.
The next two methods continue this MVC development. The getContents()
method initializes the Viewer by providing the top-level Model class of the Viewer.
In our case, this is a Chart. The class returned by getEditFactory() uses this
Model to create a new EditPart, or a ChartPart for our editor. This EditPart is
then added as a child of the Viewer’s RootEditPart.
The next four methods handle events in the Viewer. The first method directs
Events from the LightWeightSystem to the editor’s EditDomain. The Viewer creates
Listeners for DragEvents and DropTargetEvents and also provides a KeyHandler to
respond to keyboard actions. It’s important to note that the Viewer doesn’t
respond to Events itself, but sends them to the object best suited to handle them.
The last three methods in the table deal with the Viewer’s management of selec-
tions. The Viewer listens for the user’s selections and calls the findObjectAtEx-
cluding() method to see if a selection location matches that of an EditPart. If so,
the EditPart is added to the List of EditParts returned by getSelectedEdit-
Parts(). Even though the SelectionTool responds to the user’s selection, it gets its
information from the Viewer.
D.10.3 The FlowchartEditor
Now that you understand how GraphicalEditors and GraphicalViewers operate,
we can present the complete code for the FlowchartEditor. This class extends the
GraphicalViewerWithPalette class, which is just a GraphicalEditor with the Com-
posite split into two sections. The code is shown in listing D.28.
package com.swtjface.flowchart;
import java.io.*;
import java.util.EventObject;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
Listing D.28 FlowchartEditor.java
454 APPENDIX D
The Graphical Editing Framework (GEF)
import org.eclipse.swt.SWT;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.gef.*;
import org.eclipse.gef.dnd.TemplateTransferDragSourceListener;
import org.eclipse.gef.editparts.ScalableRootEditPart;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.ui.parts.*;
import com.swtjface.flowchart.actions.FlowchartContextMenuProvider;
import com.swtjface.flowchart.dnd.FlowchartDropTargetListener;
import com.swtjface.flowchart.editpart.*;
import com.swtjface.flowchart.model.*;
import com.swtjface.flowchart.palette.*;
public class FlowchartEditor extends GraphicalEditorWithPalette
{
public FlowchartEditor()
{
DefaultEditDomain defaultEditDomain =
new DefaultEditDomain(this);
setEditDomain(defaultEditDomain);
}
Chart Flowchart;
protected void setInput(IEditorInput input)
{
super.setInput(input);
IFile file = ((IFileEditorInput)input).getFile();
try
{
InputStream is = file.getContents(false);
if(is.available()!=0)
{
ObjectInputStream ois = new ObjectInputStream(is);
Flowchart = (Chart)ois.readObject();
ois.close();
setTitle(file.getName());
} else
Flowchart = new Chart();
}
catch (Exception e)
{
e.printStackTrace();
Flowchart = new Chart();
}
}
protected Chart getChart()
{
return Flowchart;
Setting editor’s
initial chart
If file contains
chart, use it
If file is empty,
create new chart
Introducing the EditorPart 455
}
public void setChart(Chart chart)
{
Flowchart = chart;
}
protected void createOutputStream(OutputStream os)
throws IOException
{
ObjectOutputStream outStream = new ObjectOutputStream(os);
outStream.writeObject(getChart());
outStream.close();
}
public void doSaveAs()
{}
public void doSave(IProgressMonitor monitor)
{
try
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
createOutputStream(out);
IFile file = ((IFileEditorInput)getEditorInput()).getFile();
file.setContents(new ByteArrayInputStream(out.toByteArray()),
true, false, monitor);
out.close();
getCommandStack().markSaveLocation();
}
catch (Exception e)
{
e.printStackTrace();
}
}
private boolean savePreviouslyNeeded = false;
public boolean isDirty()
{
return isSaveOnCloseNeeded();
}
public boolean isSaveAsAllowed()
{
return true;
}
public boolean isSaveOnCloseNeeded()
{
return getCommandStack().isDirty();
}
Convert existing chart
to output stream
Set file contents with
output stream
456 APPENDIX D
The Graphical Editing Framework (GEF)
private boolean savePreviouslyNeeded()
{
return savePreviouslyNeeded;
}
private void setSavePreviouslyNeeded(boolean value)
{
savePreviouslyNeeded = value;
}
protected void configureGraphicalViewer()
{
super.configureGraphicalViewer();
getGraphicalViewer().setRootEditPart
(new ScalableRootEditPart());
getGraphicalViewer().setEditPartFactory(new PartFactory());
ContextMenuProvider provider =
new FlowchartContextMenuProvider(getGraphicalViewer(),
getActionRegistry());
getGraphicalViewer().setContextMenu(provider);
getSite().registerContextMenu
(provider, getGraphicalViewer());
getGraphicalViewer().setKeyHandler(new
GraphicalViewerKeyHandler(getGraphicalViewer())
.setParent(getCommonKeyHandler()));
}
protected void initializeGraphicalViewer()
{
getGraphicalViewer().setContents(Flowchart);
getGraphicalViewer().addDropTargetListener(
new FlowchartDropTargetListener(getGraphicalViewer()));
}
private PaletteRoot root;
protected PaletteRoot getPaletteRoot()
{
if (root == null)
root = FlowchartPalette.getPaletteRoot();
return root;
}
protected void initializePaletteViewer()
{
super.initializePaletteViewer();
getPaletteViewer().addDragSourceListener(
new TemplateTransferDragSourceListener(getPaletteViewer()));
}
// Part 4: Allow the user to interact with the environment
private KeyHandler sharedKeyHandler;
protected KeyHandler getCommonKeyHandler()
Create initial objects
for Graphical Viewer
Set top-level Model for
Graphical Viewer
Tell Graphical
Viewer where
to create new
Models
Introducing the EditorPart 457
{
if (sharedKeyHandler == null)
{
sharedKeyHandler = new KeyHandler();
sharedKeyHandler.put(KeyStroke.getPressed(SWT.DEL, 127, 0),
getActionRegistry().getAction
(ActionFactory.DELETE.getId()));
}
return sharedKeyHandler;
}
public void commandStackChanged(EventObject event)
{
if (isDirty())
{
if (!savePreviouslyNeeded())
{
setSavePreviouslyNeeded(true);
firePropertyChange(IEditorPart.PROP_DIRTY);
}
}
else
{
setSavePreviouslyNeeded(false);
firePropertyChange(IEditorPart.PROP_DIRTY);
}
super.commandStackChanged(event);
}
public void gotoMarker(IMarker marker)
{ }
}
Whew! As shown by the annotations, this class performs three tasks. The first
involves file operations. Once the user starts the editor by selecting a *.fcf file, the
editor converts it into an ObjectInputStream and attempts to convert this into a
Chart object. If the conversion succeeds, then this Chart is used to initialize the
GraphicalViewer. Otherwise, if the file is empty, the editor constructs a new Chart
object. Similarly, when the user wants to save the Chart to a file, the editor con-
verts it into an ObjectOutputStream and then to a file. Notice that the editor con-
stantly monitors the CommandStack to see if the contents are dirty, which means
they’ve been changed since the last save.
The next task involves configuring and initializing the GraphicalViewer and
PaletteViewer. The editor provides the GraphicalViewer with its RootEditPart, its
EditPartFactory, ContextMenu, and KeyHandler, and initializes it with the Chart.
Associate Delete key
with Delete Action
458 APPENDIX D
The Graphical Editing Framework (GEF)
To enable the user to drag template objects from the palette, the editor provides a
TemplateTransferDragSourceListener for the PaletteViewer and a Flowchart-
DropTargetListener for the GraphicalViewer. It also initializes the PaletteViewer
with the PaletteRoot created in the FlowchartPalette class.
Finally, the editor manages user input. This means creating a KeyHandler and
making sure the Delete keystroke creates a DeleteAction. The editor also
responds to Command execution by firing a PropertyChangeEvent whenever the
CommandStack changes.
And that finishes our flowchart editor. With luck, your application should
resemble figure D.15.
D.11 Other GEF aspects
Despite the lengthy presentation, the GEF provides a number of important fea-
tures that we failed to mention. We’ll talk about these subjects in this final section.
Figure D.15
The flowchart editor in full
Other GEF aspects 459
D.11.1 Accessibility
We’re ashamed that we failed to make the flowchart editor accessible, especially
since the GEF makes accessibility so easy. GEF EditParts interact with accessibility
tools by creating an AccessibilityEditPart() method and making it available.
This new EditPart responds to AccessibilityEvents and AccessibilityCon-
trolEvents by providing information concerning the part’s name, description,
state, and children. AccessibleAnchors make it possible to create and remove Con-
nections through the keyboard.
D.11.2 Grid layout
One of the most interesting features of a GEF editor is the possibility of adding rul-
ers and a grid to the GraphicalViewer. This lets the user force the editor’s Figures
to position themselves according to the grid’s points, a process also called SnapTo-
Grid. Once the GridLayout is specified, Actions such as the ToggleSnapToGeometry-
Action cause EditParts to change their location in response to SnapMoveRequests
and SnapResizeRequests.
D.11.3 Zooming in and out
Another interesting capability lets the user increase or decrease the size of a
selected portion of the editor through zooming. This is accomplished by a Zoom-
Manager, which is associated with the GraphicalViewer and fires a ZoomEvent when
the user changes the zoom level. This Event results in a ZoomInAction or Zoom-
OutAction, which causes the Viewer to enlarge or reduce the component’s graph-
ics. These Actions can also be performed through the Workbench by adding their
RetargetActions.
D.11.4 Kudos to Randy Hudson
The inspiration for our flowchart editor was the Logic Editor created by Randy
Hudson, technical lead for IBM’s GEF development and the driving force behind
its improvement. Like a latter-day Prometheus, he took this powerful tool out of
IBM’s cloistered research group and made it freely available for us commoners.
We’d like to doff our hats to Mr. Hudson for his hard work in both developing
and supporting this toolkit, and to you, gentle reader, for your patience in learn-
ing how it works.
461
index
A
AbstractConnectionAnchor 380
AbstractConnectionRouter 383
AbstractGraphicalEditPart 390
AbstractHintLayout 372
AbstractTextEditor 286
AbstractTreeViewer 172
accelerator keys 72, 201, 203
accessibility 459
accessor 408
ActionBarContributor 394,
444–446
ActionContributionItem 62, 64,
66, 68, 70
ActionRegistry 441–444, 446,
451
Actions 20, 49, 62, 66, 70, 77,
102, 154, 204, 261, 285, 389
and Menus 204–205, 209
GEF and Draw2D Actions
397–399, 402, 441–442,
444–445, 447, 459
ActiveX 10
adapters 20, 54
add() 368
addAncestorListener() 368
addChild() 411
addEditorAreaTransfer() 293
addFigureListener() 368
addFocusListener() 367
addKeyListener() 367
addListener() 368
addMenuBar() 24
addMouseListener() 53, 367
addMouseMotionListener() 368
addPoint 375
addPropertyChangeListener()
73, 368
addStatusLine() 24
addToolBar() 24
addView() 295–296
AlignmentRetargetAction 445
animation 160
Ant 321–322
Apple 322
application class 290
application directory 307
Application Programming Inter-
face 17
ApplicationWindow 20, 22–23,
42, 63, 68
ArmEvents 63
array 37
AS_CHECK_BOX 66
AS_PUSH_BUTTON 66
AS_RADIO_BUTTON 66
AutomaticRouter 383
B
BANNER_FONT 152
Bendpoint 403
BendpointConnectionRouter
383
BendpointRequest 403
BookmarkNavigator 287
Browser 280–281
browser
dependencies 281
supported platforms 280
Button 34, 299, 304
ButtonGroup 370, 372
ButtonModel 370
Buttons 370
C
C programming language 17
Canvas 135–137, 139–140,
164–165, 364, 400, 451–452
CDLC 10
CellEditor 197, 199–200
CellModifier 210
CFBundleExecutable 322
check button 36
child widgets 15
ClassPath 322
Classpath Variables 314, 318, 365
Clickable 369–370
client area 39
Clipboard 254, 261–262
clipping 139
Color 141
ColorDialog 144, 213
colors 140, 145, 164
choosing 214
depth 157
RGB 213
system 140
ColorSelector 144–145
ColumnLayout 301–302
ColumnWeightData 193–194
CombinedTemplateCreation-
Entry 402
Combo 100
462 INDEX
drop-down 100
read-only 100
simple 100
styles 100
styles demonstrated 100
ComboBoxCellEditor 197, 200
Command 391–394, 404,
418–420, 422–426, 434–435,
437–441, 445–450, 458
CommandStack 394, 419,
441–442, 452, 457–458
Common Public License 9
compilation 318
ComponentEditPolicy 436, 438
ComponentPolicy 439
Composite 22–23, 38, 40, 42–44,
164–165, 293–295, 299–301,
364, 368, 372, 451, 453
Computer Aided Design 363
computeSize() 31
computeTrim() 40
Configure Variables 318
configureEditorAreaDropLis-
tener() 293
Connection 373, 377, 380, 382,
387, 401, 403, 414, 416, 418,
420, 422, 426, 434, 439, 448,
450
ConnectionAnchor 377,
380–381, 393, 426, 430,
432, 440, 449–450
ConnectionBendpointTracker
403
ConnectionCreationTool
403–404, 448–450
ConnectionCreationToolEntry
401, 448
ConnectionEditPart 427, 432,
434, 448
ConnectionEndpointLocator
382
ConnectionLayer 383
ConnectionRouter.NullConnec-
tionRouter 383
Connections 366
Connector 363
containers 15, 38, 41, 372–373,
389, 393
containsPoint() 373
content providers 172, 177, 196
advantages of 179
ContentAssistant 92, 96–97, 99
ContentProvider 173, 181,
184, 194
ContentViewer 168–170, 172
Context menu 444
ContextMenuProvider 394,
443, 456
ContributionItem 64–66, 70
ContributionManager 64, 66, 68,
70
contributions 20, 49, 63, 67, 285
contributors 77
Control 28, 30, 32, 134–135,
138–139, 286, 363–364, 367
ControlAdapter 55
ControlContribution 102
Controller 390–392
control-relative coordinates 32
convertAccelerator() 72
CoolBar 103–104
vs. ToolBar 103
CoolItem 103–104
copy 255
CopyRetargetAction 445
CPL See Common Public License
createAndRunWorkbench() 291
CreateCommand 419–420, 422,
437–438
CreateConnectionRequest 404,
439–440, 448–449
createContents() 22–23, 68, 165
createEditPart() 427
createEditPolicies() 426,
429–431, 434, 447
createFigure() 433
createMenuManager() 68
createPartControl() 301, 304
CreateRequest 403
createToolBarManager() 68
CreationEntryTool 405
CreationFactory 402, 405
CreationTool 403
custom components 363
custom dialogs 213
custom layouts 124–125, 128
calculating size 125
positioning widgets 126
when to use 124
D
data formats 255
data persistence 294
DecoratingLabelProvider 277,
279
decorators 277
DEFAULT_FONT 152
DelegatingLayout 372
DeleteAction 442, 447, 458
DeleteCommand 422–423,
438–439, 448
DeleteRequest 447–448
DeleteRetargetAction 445
DIALOG_FONT 152
DIALOG_TRIM 19
DialogPage 269
dialogs 19–21, 213, 228, 230
custom 218, 228–230
error 220
input 222
JFace 218, 228
JFace compared to Swing 218
JFace hieararchy 218
message 219
modal 219
multipage 236
parent window 219
preferences 268
progress 224
SWT 213
validating input 223
DialogSettings 245
direct palette 156
DirectedGraphLayout 380
DirectEditRequest 435
directory
choosing 214
DirectoryDialog 214
Display 14–16, 18, 23, 52, 63,
135, 153, 290–291, 364
display-relative coordinates 32
dispose() 8, 22, 29, 144, 150, 158
disposeColors() 144
Document 89, 99
drag and drop 254–257, 383, 393
implementing 257, 259
types 256
DragEvent 403, 426, 453
DragSource 259, 383
DragSourceEvent 260
INDEX 463
DragSourceListener 259–260
DragTracker 403, 426
DRAW_DELIMITER 147
DRAW_MNEMONIC 147
DRAW_TAB 147
DRAW_TRANSPARENT 147
Draw2D 362–365, 367, 370–374,
380, 382–383, 389, 393, 400
Drawable 135, 138
drawArc() 137
drawFocus() 137
drawing 374
drawLine() 137
drawOval() 137
drawPolygon() 137, 375
drawPolyline() 137
drawRectangle() 137–138
drawRoundRectangle() 138
drawString() 147
drawText() 147, 150
DropTarget 257, 383
DropTargetEvent 257–258, 453
DropTargetListener 257
E
Eclipse 312
Eclipse Forms 285, 294, 297,
299–303, 308
Eclipse IDE 317
Eclipse in Action 312
Eclipse SDK 312, 316
Eclipse Workbench 285,
287–288, 306
Eclipse.app 321
Eclipse.org 312
Edge 380
EditDomain 404, 447, 452–453
editing text
SWT vs. JFace 108
with JFace 91
EditorPart 286, 393, 399, 441,
447, 450–451
EditorPartAction 441
editors 285–288, 291, 293–295,
308
EditPart 391–394, 399, 403, 408,
422, 426–428, 430, 446
EditPartFactory 427–428, 457
EditPolicy 394
Environmental Variables 316,
320
error dialogs 216
detailed messages 220
error handling 196, 200
ErrorDialog 220, 222
dependencies 222
event handling 49, 63, 367
event model 49, 77
event responses 363
EventObject 52
events 4, 15, 49, 58, 62, 368
typed 50, 60
execute() 404
ExpandableComposite 301
Export 306
ExtendedModifyListener 84–85,
87, 97
F
factory 384, 394
FieldEditor 270–271
provided by JFace 271
FieldEditorPreferencePage 270
Figure 364–368, 370–374, 377,
380–384, 387, 390, 392–393,
399, 434
FigureListener 368
file extensions
filtering 216
file handling 294
FileDialog 215
styles 215
files
choosing 215
fill layout 110
styles 112
fill() 69
fillArc() 137
fillGradientRectangle() 138
fillOval() 137
fillPolygon() 137
fillRectangle() 138
Filters 174
filters 173
findFigureAt() 369, 373
findKeyCode() 72
findKeyString() 72
findModifier() 72
FindMouseEventAt() 369
fireChangeEvent() 370
firePropertyChange() 73, 368,
409
firePropertyChangeEvent() 370
FlowFigureLayout 372
focus behavior 140
FocusAdapter 55
Font 145, 150
FontData 146
FontDialog 150, 216
FontMetrics 148
FontRegistry 4, 150–151, 163
fonts 20, 134, 145–146, 148,
150–152, 164, 166
choosing 216
management 145
Form 300–302
form layout 119, 122
FormAttachment 120–121, 123
constructors 121
FormData 120, 123
FormEditor 286
FormLayout 120
FormPage 286
FormText 300–302
FormToolkit 299–301, 303–304
FreeformLayer 373
FreeformLayeredPane 372–373
FreeformViewport 374
G
GC 364–365, 369, 374
GC See graphic context
GCJ 308
GEF 363, 365, 387, 389–391,
393–394, 400, 403
getAccelerator() 72
getActionDefinitionID() 73
getAlignment() 34
getAscent() 148
getAverageCharWidth() 148
getBannerBackground() 144
getBounds() 31
getChildren() 39, 368–369, 411
getClientArea() 40
getColorValue() 144
getCurrent() 18
getData() 29
getDescent() 148
getDescription() 71
464 INDEX
getDisabledImageDescriptor()
73–74
getDisplay() 29, 143
getErrorBorder() 144
getFontMetrics() 148
getHeight() 148
getHelpListener() 73
getHorizontalBar() 40
getHoverImageDescriptor() 74
getImage() 34
getImageDescriptor() 71
getInitialWindowPerspec-
tiveId() 292
getItemCount() 45
getLayout() 39
getLeading() 148
getLocale() 146
getLocation() 31, 381
getMaximizedControl() 43
getMenuCreator() 73–74
getNewObject() 406
getOwner() 381
getPaletteRoot() 401
getParent() 369
getPropertyDescriptors()
414–415
getResourceAsStream() 153
getRGBs() 158
getSelection() 36, 45
getSeparator() 24
getSize() 31
getStyle() 29
getSystemColor() 141, 143
getTabList() 39
getText() 34
getTextBounds() 369
getTextLocation() 369
getToolTipText() 71
getTransparencyMask() 159
getVerticalBar() 40
GIF 160, 163
graphic context 134–137,
139–140, 143, 147–148,
150, 154–155, 165
Graphical Editing Framework
363
graphical editors 363, 389
GraphicalEditor 286, 441–442,
451, 453
GraphicalEditPolicy 436
GraphicalNodeEditPolicy 436,
439, 449
GraphicalViewer 393–394, 400,
428, 450, 452–453, 457, 459
GraphicalViewerWithPalette 453
Graphics 365, 369, 374–375
graphics 134, 136
graphs 380
grid layout 116
GridData 117, 119
size attributes 117
styles 117
GridLayout 116, 231
Group 38, 40
GTK 16, 308, 316
GUIs 3, 7, 285
H
handleEvent() 59
handleFocusGained() 367
handleFocusLost() 367
handleKeyPressed() 367
handleKeyReleased() 367
handleMouseDoubleClicked()
367
handleMouseDragged() 368
handleMouseEntered() 368
handleMouseExited() 368
handleMouseHovered() 368
handleMouseMoved() 368
handleMousePressed() 367
handleMouseReleased() 367
Hashtable 382
HEADER_FONT 152
heavyweight 364
heavyweight components 7
HelloSWT 14
HelloSWTJFace 14, 21
helper classes 20
HREF 303
HTML 300–303
Hyperlink 299, 302–305
HyperlinkAdapter 303
HyperlinkEvent 303
HyperlinkGroup 304–305
HyperlinkListener 303
I
IAutoIndentStrategy 90
IBaseLabelProvider
170–171, 278
ICellModifier 197–198
ICompletionProposal 92
IContentAssistProcessor
91–92, 99
getCompletionProposalAuto-
ActivationCharacters 92
IContributionManager 204
IDialogPage 236–237, 248, 269
IDocument 89, 99
regions 89
IDocumentPartitioner 89
IInputValidator 223
ILabelDecorator 276, 278
ILabelProvider 171, 179, 276
default implementation See
LabelProvider
Image 152, 154, 158, 390
ImageData 153–155, 157–159,
161, 166
ImageDescriptor 163, 166
ImageLoader 159–160, 163, 166
ImageRegistry 4, 163, 277, 279
images 20, 152, 164
indexed palette 156–157
InputDialog 222–223
InputStream 153
InterruptedException 226
IPageLayout 295–296
IPerspectiveFactory 295–296
IPlatformRunnable 290–291
IPreferencePage 268
IPreferencePageContainer 268,
273–274
IPreferencePageNode 273
IPreferenceStore 274, 291
IProgressMonitor 225–226
IPropertyChangeListener 72
IPropertySource 412, 415
IRunnableContext 224–226
IRunnableWithProgress 224
isDirect() 156
isDisposed() 29
IStatus 220–222
severity 221
IStructuredContentProvider
172, 177, 181, 187, 196
IStructuredSelection 181
retrieving items 181
ITableLabelProvider 171, 198
INDEX 465
ITextDoubleClickStrategy 90
ITextHover 90
ITextListener 97
ITextViewer 89–90
plug-ins 90
ITreeContentProvider
177–178, 185
ITypedRegion 89
IUndoManager 90
IWizard 235, 239, 242
IWizardContainer 241
IWizardNode 244
IWizardPage 235, 237
IWorkbench 291
IWorkbenchWindowConfigurer
291–293
J
J2EE 309
J2ME 10
Java Build Path 314–315, 318
Java compiler 314
Java Native Interface 17
Java SDK 287, 312
Java Web Start 308
java.library.path 316, 320, 322
JavaBeans 197, 389, 408
JFace 144, 150, 163, 285, 312,
314–316, 318, 389, 405
ApplicationWindows 23
event model 63
origin 3
JFace text packages
obtaining 88
JFaceColors 144
JFaceResources 151
JNI 7, 17
JOptionPane 218–219, 222
JVM 5
K
KDE 10
key code 56
KeyAdapter 55
keyCode 57
KeyEvent 56–57, 60, 447
KeyHandler 394, 447, 453,
456–458
KeyListener 50, 59, 84, 87
L
Label 32, 299–300, 369, 382
label decorators in Eclipse 280
Label providers 170–171, 198,
210, 277
Layer 373–374
LayeredPane 373, 453
LayerPanes 372
Layers 366
Layout 302, 372
LayoutData 115
LayoutManager 364, 372–373
LayoutPolicy 394
layouts
overview 110
SWT compared to Swing 110
LEFT_TO_RIGHT 135
libraries 14, 314
lightweight components 5
LightweightSystem 364–365,
371, 387, 400
LineStyleListener 83
Linux 3, 16, 316
List 180, 369, 392
on Motif 180
styles 180
listeners 18, 49, 52, 54, 364, 367
typed 52, 58–59
typed listeners 50
untyped 58–59
lists
JFace 181
SWT 180
ListViewer 20, 181
styles 181
LocationRequest 403–404
long-running tasks 224
cancelling 226
M
Macintosh 3, 321
MainClass 322
ManhattanConnectionRouter
383
marquee selection 393
MarqueeSelectionTool 402–403
MenuAdapter 55
MenuItem 103, 201–203
styles 202
MenuListener 201
MenuManager 65–66, 101,
204–205, 210
menus 23, 191, 200–202
events 201
JFace 204
styles 201
SWT 201
message dialogs
types 220
MessageBox 216
styles 217
MessageDialog 219–220
Model 389, 391–392, 394, 400,
406–407, 409, 426
Model-Delegate See Swing
Model-View-Controller 168,
170, 172
ModifyListener
vs. ExtendedModifyListener
85
modular 389
MouseAdapter 55
mouseDoubleClick() 53
mouseDown() 53
MouseEvent 52, 62, 150,
204, 403
MouseListener 50, 53, 59,
203, 384
MouseMotionListener 384
MouseMotionListener.Stub 384
MOUSEOVER_PROPERTY 370
MouseTrackAdapter 55
mouseUp() 53
MultiEditor 286
MultiPageEditorPart 286
MultiStatus 222
mutator 408, 411–412,
418–419, 424
MVC 6, 8, 389, 391, 416
N
native 17
native graphics 316, 320, 322
native graphics library 17, 316
native methods 16
NO_MERGE_PAINTS 139
Node 380
NodeEditPart 426, 430
466 INDEX
O
Object 390
ObjectInputStream 457
offset 156
Open file dialog 215
open() 150
OpenGL 309
OS class 16
OS X 321
OSGi 67
OutputStream 160
P
pack() 15, 31
packages 398
paint() 369
paintBorder() 369
paintChildren() 369
paintClientArea() 369
PaintEvent 138–140, 142,
149–150, 154–155, 164, 374
paintFigure() 369, 375
painting 138
PaintListener 138–139, 142, 149,
154, 164
palette 393, 399, 402
PaletteData 156–157
PaletteGroup 401–402
PaletteRoot 400, 402, 404
PaletteViewer 393–394, 400, 404,
457–458
Pareto Rule 77
paste 255
PATH variable 316
PathFigure 382
perspective 285, 288, 290, 292,
294–296, 298
Platform 196
PlatformUI 290–291
plug-in 285–286, 288–289, 296,
306–308, 393, 396–397
Plug-in Manifest Editor 289,
299, 396
plugin.xml 289–290, 295–296,
298, 307, 393, 396
Pocket PC 10
Point 376, 380–381
PointList 375
Polygon 376
PolylineConnection 382, 393,
439, 450
PolylineDecoration 382
Position 89
PrecisionDimension 380
PrecisionPoint 380
PrecisionRectangle 380
PreferenceConverter 275
PreferenceManager 274
PreferencePage 269
PreferencePageDialog 273–274
Preferences 318
PreferenceStore 275
preferred size 30
PRESSED_PROPERTY 370
preStartup() 292
preWindowOpen() 292–293
Printer 135
ProgressBar 106, 227–228
when to use 107
ProgressIndicator 106–107,
227–228
animated mode 108
ProgressMonitor 226
ProgressMonitorDialog 224–228
project 312–313, 395
Property View 415
propertyChange() 409, 426,
430, 448
PropertyChangeEvent 72,
391–392, 394, 408–409,
411, 416, 418, 427–430, 448,
450, 458
PropertyChangeListener 271,
368
PropertyChangeSupport
409–410
providers 170
R
RadialLayout 128
radio buttons 37–38
RadioGroupFieldEditors 37
Ray 380
RCP 284–285, 287–288, 291,
294, 296–299, 306
readAndDispatch() 16, 18, 49
Rectangle 153, 375–376,
380, 382
Redo stack 419
RedoRetargetAction 445
redraw 139, 149–150
refID 296
refresh() 392
refreshChildren() 430
registries 21
removeChild() 411
removePropertyChange-
Listener() 73
repaint() 369
repeatCount 161
Request 391–393, 403–404, 419,
434–435, 441
ResizableEditPolicy 436, 438
ResizeTracker 403
ResourceNavigator 287, 294
RetargetAction 394, 444–445
RGB 140, 142, 144, 146, 156, 159
Rich Client Platform 284–285,
293, 306, 308
RIGHT_TO_LEFT 135
RootEditPart 428, 453, 457
router 383
row layout 112
RowData 115
RowLayout 114
properties 114
RTF 255
S
Sash 43–44
SashForms 43–44
Save dialog 215
ScalableFreeformLayeredPane
373
ScalableLayeredPane 373
ScalableRootEditPart 453
scaleTo() 155
scanline 156
ScrollBar 374
ScrollBarLayout 372
ScrollPane 372, 374
SDK 316
SelectionAction 442
SelectionAdapter 55
SelectionListener 102
SelectionRequest 403–404, 447
SelectionTool 402–404, 447, 453
separation of concerns 389–390
separator 33
INDEX 467
Serializable 409–410
setAccelerator() 72
setActionDefinitionID() 73
setAlignment(int) 34
setBackground() 143
setBlockOnOpen() 22
setBounds() 31
setChild() 420
setChildrenEnabled() 369
setClient() 301
setClipping() 139
setColors() 144
setColorValue() 144
setConstraint() 369, 420
setControl() 44
setData() 29
setDefaultImage(Image) 24
setDescription() 71
setDisabledImageDescriptor()
73–74
setExceptionHandler() 24
SetFocus() 17
setFocus() 294–295
setFont() 146
setForeground() 143, 304
setHelpListener() 73
setHoverImageDescriptor() 74
setImage(Image) 34
setImageDescriptor() 71
setLayout() 39, 111
setLocale() 146
setLocation() 31
setMenuCreator() 73–74
setOrientation() 43
setParent() 420
setPixel() 158
setSelection() 36, 45
setSize() 31
setSourceDecoration() 382
setStatus(String) 24
setTabList() 39
setTargetDecoration() 382
setText() 146
setText(String) 34
setToolTipText() 71
setUDistance() 382
setVDistance() 382
setWeights() 43
Shape 374
Shell 14–15, 18, 23, 52, 364, 371
modality 19
secondary 19
top-level 19
ShellAdapter 55
ShellEvent 52
sleep() 18
Slider 105
on different operating systems
105
styles 106
SnapMoveRequest 459
SnapResizeRequest 459
sorters 173–174
ST 82
StackAction 441–442
standalone 285, 288, 296, 306,
308, 395
standalone applications 285
stateMask 57
Status 221–222
status line 23
StatusLineManager 65, 68
String 382
StructuredViewer 168–169,
172–175
style 19, 33
StyledText 82, 85, 97
actions 82
binding actions
to keystrokes 82
events 85
invoking actions
programmatically 82
setStyleRange 85
vs. Text 79
StyleRange 83–84
modifying 83
persisting 83
Swing
automatic garbage
collection 5
Model-Delegate 6
origin 4
rendering 5
SWT 16, 144, 154, 160, 163, 285,
312, 314, 316, 318, 321,
364–365, 371, 374, 383, 387
graphics 3
origin 6
platforms supported 9
resource management 7
SWT initialization 243
SWT.ARROW 35
SWT.BORDER 19
SWT.CENTER 33, 35
SWT.CHECK 36
SWT.CLOSE 19
SWT.FLAT 35
SWT.HORIZONTAL 33
SWT.KeyDown 59
SWT.LEFT 33, 35
SWT.MAX 19
SWT.MIN 19
SWT.MouseDoubleClick 59
SWT.PUSH 34
SWT.RADIO 37
SWT.RESIZE 19
SWT.RIGHT 33, 35
SWT.SEPARATOR 33
SWT.SHADOW_ETCHED_IN 41
SWT.SHADOW_ETCHED_OUT
41
SWT.SHADOW_IN 33, 40
SWT.SHADOW_NONE 33, 40
SWT.SHADOW_OUT 33, 40
SWT.TITLE 19
SWT.TOGGLE 35
SWT.VERTICAL 33
SWT/JFace 2, 6, 16, 134, 145,
312, 316, 366
system colors 141–142
T
tab 44
TabFolders 44, 46
TabItem 44
Table 191, 293, 295, 299–300,
303–304
columns 193
TableColumn 193
TableItem 192, 199
TableLayout 193–194
Tables 191
editing 197
JFace 194
SWT 191
TableViewer 20, 194
TableWrapLayout 302
TaskList 287
template 394, 402, 404–406
TemplateEntry 400, 405
468 INDEX
TemplateTransferDrag-
SourceListener 454,
456, 458
TemplateTransferDrop-
TargetListener 405, 407
Text 15, 79, 81–82, 300
events 79
Method summary 81
text editing
in JFace 88
in SWT 88
Validation 81
with StyledText 82
TEXT_FONT 152
TextViewer 90, 96, 99
toControl() 31
toDisplay() 31
Toggle 370
toggle button 36
ToggleModel 370
Tool 391–392, 402–403, 434,
441, 446
ToolBarManager 65–66, 101
ToolBars 23, 102–103
and Actions 102
creating 102
creating by hand 103
styles 102
ToolEntry 400, 402
ToolItem 103
toString() 29
Transfer 255, 261–262
Transform 380
translate 374
transparency 159
transparentPixel 159
TRAVERSE_TAB_NEXT 58
TraverseEvents 56, 58, 63
Tree 176
styles 177
vs. TreeViewer 179
TreeAdapter 55
TreeItem 176–177
Trees 176
JFace 177
SWT 176
TreeViewer 20, 177, 184
vs. Tree 179
trim 39
TypedEvent 50, 52
TypedListener 50
U
UI thread 196
UML 363
UndoRetargetAction 445
Unified Modeling Language 363
untypedListener 61
user preferences 268, 270
persistent 274
user-interface thread 18
V
VerifyEvent 56, 81
VerifyListener 80
View 389–392, 433
Viewer 168, 285, 389, 400, 459
Viewer framework 168
events 172
mixing with standard widgets
169
ViewerFilter 187
viewers 20
ViewerSorter 174, 187
implementing 174
viewID 296
ViewPart 287–288, 294
Viewport 374, 453
Visual Studio 363
W
widgets 28, 364
Overview 79
WidgetWindow example 11
windowing system 316
Windows 17
wizard containers 241
WizardDialog 235, 242
WizardPage 237–238
building custom 237, 239
wizards 20–21, 235, 240–241, 397
classes vs. interfaces 235
hierarchy 235
page display order 241, 250
persistent settings 244–246
WizardSelectionPage 243
workbench 285–298, 306–308,
323, 397
WorkbenchAdvisor 291–293, 298
WorkbenchPartAction 441
wrapper program 321
X
XYLayout 372–373
Z
ZoomInAction 459
ZoomInRetargetAction 445
ZoomManager 459
ZoomOutAction 459
ZoomOutRetargetAction 445