Java 1.1 Unleashed
- 39 -
The JavaBeans API
by Michael Morrison
IN THIS CHAPTER
- Property Management
- Introspection
- Event Handling
- Persistence
- Application Builder Support
With all the neat things JavaBeans accomplishes, you might imagine that there is
some highly complex system pulling all kinds of magical tricks under the hood. The
truth is, there is no magic behind JavaBeans and surprisingly little complexity considering
how advanced it is as a software component technology. The lack of complexity in
JavaBeans is because of the well-designed JavaBeans API, which is completely responsible
for carrying out all the interesting ideas you learned about in the previous chapter.
In this chapter, you take a quick tour through the JavaBeans API to familiarize
yourself with all emergency locations <grin>. Actually, the tour is
meant to help you get the big picture of how the API is divided and what type of
functionality each part of it addresses. Although there are a decent number of classes
and interfaces defined in the API, you don't have to worry about them just yet. Being
faced with a large amount of new information to process and digest is always somewhat
overwhelming, so this chapter hits just the high points. This way, you'll have some
perspective when you dig into more details in the next couple of chapters.
In this chapter, keep in mind that JavaBeans is ultimately a programming interface,
which means that all its features are implemented in the java.beans package.
The java.beans package is also referred to as the JavaBeans API and is provided
as part of the standard Java 1.1 class library. The JavaBeans API itself is merely
a suite of smaller APIs devoted to specific functions, or services. Following is
a list of the main component services in the JavaBeans API that are necessary to
facilitate all the features that make JavaBeans such an exciting technology:
- Property management
- Introspection
- Event handling
- Persistence
- Application builder support
By understanding these services and how they work, you'll have much more insight
into exactly what type of technology JavaBeans is. This entire chapter is devoted
to helping you understand the basics of these APIs and why they are necessary elements
of the JavaBeans architecture.
Property Management
The property management facilities in the JavaBeans API are responsible for handling
all interactions relating to bean properties. Properties reflect the internal state
of a bean and constitute the data part of a bean's structure (remember that beans
have two basic parts: a data part and a method part). More specifically, properties
are discrete, named attributes of a bean that determine its appearance and behavior.
Properties are important in any component technology because they isolate component
state information into discrete pieces that can be easily modified.
To help you get a better idea of the importance of properties, consider some different
scenarios that deal with properties. Following are some examples of how bean properties
are accessed and used:
- As object fields in scripting environments such as JavaScript or VBScript
- Programmatically, using public accessor methods
- Visually, using property sheets in application builder tools
- Through the persistent storage and retrieval of a bean
As this list shows, properties come into play in a variety of ways when it comes
to bean access and manipulation. Notice the flexibility properties provide: You can
access them through scripting languages such as JavaScript, through full-blown programming
languages such as Java, and through visual builder tools. This freedom to access
and manipulate beans in a variety of ways is one of the critical design goals of
the JavaBeans technology. And it is fulfilled by the property management facilities
in the JavaBeans API. The next few sections discuss some of the major issues addressed
by the JavaBeans API property management facilities.
Accessor Methods
The primary way properties are exposed in the JavaBeans API is through accessor
methods. An accessor method is a public method defined in a bean that directly reads
or writes the value of a particular property. Each property in a bean must have a
corresponding pair of accessor methods: one for reading the property and one for
writing. The accessor methods responsible for reading are known as getter methods
because they get the value of a property. Likewise, accessor methods responsible
for writing are known as setter methods because they set the value of a property.
Indexed Properties
So far, the discussion of properties has been limited to single-value properties,
which are the most common properties used in JavaBeans. However, the JavaBeans API
also supports indexed properties, which are properties that represent an array of
values. Indexed properties work in a way very similar to arrays in traditional Java
programming: You access a particular value using an integer index. Indexed properties
are very useful in situations in which a bean must maintain a group of properties
of the same type. For example, a container bean that keeps track of the physical
layout of other beans might store references to them in an indexed property.
Bound and Constrained Properties
The JavaBeans API supports two mechanisms for working with properties at a more
advanced level: bound and constrained properties. Bound properties are properties
that provide notifications to an interested party based on changes in the property
value. An interested party is an applet, application, or bean that wants to know
about changes in the property. These properties are called bound properties because
they are bound to some type of external behavior based on their own changes. Bound
properties are defined at the component level, which means that a bean is responsible
for specifying which components are bound. An example of a bound property is a visibility
property; a bean's container might be interested in knowing the status of this property
because the container has to graphically reorganize other beans based on a bean's
visibility.
The other interesting property feature provided by the JavaBeans API is support
for constrained properties, which are properties that enable an interested party
to perform a validation on a new property value before accepting the modification.
Constrained properties are useful in providing interested parties with control over
how a bean is altered. An example of a constrained property is a date property for
which the application containing the bean wants to limit the valid date property
values to a certain range.
Introspection
The introspection facilities in the JavaBeans API define the mechanism by which
components make their internal structure readily available to the outside world.
These facilities consist of the functional overhead necessary to enable development
tools to query a bean for its internal structure, including the interfaces, methods,
and member variables that comprise the bean. Although the introspection services
are primarily designed for use by application builder tools, they are grouped separately
from the application builder services in the API because their role in making a bean's
internal structure available externally is technically independent of builder tools.
In other words, you may have other reasons for querying a bean about its internal
structure beyond the obvious reasons used in builder tools.
The introspection services provided by the JavaBeans API are divided into two
parts: low-level services and high-level services. These two types of services are
distinguished by the level of access they provide to bean internals. The low-level
API services are responsible for enabling wide access to the structural internals
of a bean. These services are very important for application builder tools that heavily
use bean internals to provide advanced development features. However, this level
of access isn't appropriate for developers who are using beans to build applications
because it exposes private parts of a bean that aren't meant to be used by developers
at the application level. For these purposes, the high-level API services are more
appropriate.
The high-level services use the low-level services behind the scenes to provide
access to limited portions of a bean's internals (typically, the bean's public properties
and methods). The difference between the two levels of services is that the high-level
services don't enable access to internal aspects of a bean that aren't specifically
designed for external use. The end result is two distinct services that offer bean
introspection capabilities based on the level of access required by the interested
party, be it an application builder tool or a user. The next few sections cover several
of the major functions supported in the JavaBeans API introspection facilities.
Reflection and Design Patterns
The JavaBeans API has a very interesting technique for assessing the public properties,
methods, and events for a bean. To determine information about a bean's public features,
the bean's methods are analyzed using a set of low-level reflection services. These
services gather information about a bean and determine its public properties, methods,
and events by applying simple design patterns. You learned about the standard Java
1.1 reflection services in Chapter 18, "The Reflection Package." Design
patterns are rules applied to a bean's method definitions that determine information
about the bean. For example, when a pair of accessor methods are encountered in the
analysis of a bean, the JavaBeans introspection facilities match them based on a
design pattern and automatically determine the property they access.
The whole premise of design patterns is that method names and signatures conform
to a standard convention. There are a variety of different design patterns for determining
everything from simple properties to event sources. All these design patterns rely
on some type of consistent naming convention for methods and their arguments. This
approach to introspection is not only convenient from the perspective of JavaBeans,
it also has the intended side effect of encouraging bean developers to use a consistent
set of naming conventions.
Explicit Bean Information
Even though the design-pattern approach to introspection is very useful and encourages
a consistent approach to naming, you may be wondering what happens if bean developers
don't follow the convention. Fortunately, design patterns aren't the only option
for introspection, meaning that obstinate developers are free to ignore the suggested
naming conventions if they so choose. The developers who opt to cast convention to
the wind must use another introspection facility in the JavaBeans API: They must
explicitly list the public information about their beans. They must "spill the
beans," to inject a painfully bad pun.
The explicit introspection facility in the JavaBeans API to which I'm referring
involves creating a bean information class that specifies various pieces of information
about a bean, including a property list, method list, and event list. This approach
isn't automatic like the design-pattern approach, but it does provide a way to explicitly
describe your bean to the world, which might be advantageous in some situations.
The Introspector
Just in case you're wondering how two different introspection approaches can possibly
coexist to describe a single bean, you should know about another service that consolidates
the whole introspection process. The introspection facilities provide an introspector
used to obtain explicit bean information for a bean. The introspector is responsible
for traversing the inheritance tree of a bean to determine the explicit bean information
for all parent beans. If, at any point, explicit information is not defined, the
introspector falls back on the reflection services and uses design patterns to automatically
determine external bean information.
This two-tiered solution to assessing bean functionality is very nice because
it first attempts to use information explicitly provided by a bean's developer and
relies on automatic design patterns only if the explicit information isn't there.
The other nice thing is that it supports a mixture of the two approaches, which means
that methods for a bean can be explicitly defined in a provided bean information
class, but the properties and events can be determined automatically using design
patterns. This gives bean developers a lot of flexibility in deciding how they want
their beans exposed.
Event Handling
The event-handling facilities in the JavaBeans API specify an event-driven architecture
that defines interactions among beans and applications. If you're familiar with the
Java AWT, you know that it provides a comprehensive event-handling model. This existing
AWT event model forms the basis of the event-handling facilities in the JavaBeans
API. These event-handling facilities are critical in that they determine how beans
respond to changes in their state, as well as how these changes are propagated to
applications and other beans.
The event-handling facilities hinge on the concepts of event sources and listeners.
A bean capable of generating events is considered an event source; an application
or bean capable of responding to an event is considered an event listener. Event
sources and listeners are connected by an event registration mechanism that is part
of the event-handling facilities. This registration mechanism basically boils down
to an event listener being registered with an event source through a simple method
call. When the source generates an event, a specified method is called on the event
listener with an event state object being sent along as its argument. Event state
objects are responsible for storing information associated with a particular event.
In other words, event state objects carry with them any information related to the
event being sent. The next few sections cover some of the major issues dealt with
by the JavaBeans API event-handling facilities.
Unicast and Multicast Event Sources
Although most practical event sources support multiple listeners, the event-handling
facilities provide for event sources that choose to limit their audience to a single
listener. These sources are called unicast event sources; their more liberal counterparts
are called multicast event sources. The primary functional difference between the
two is that unicast event sources throw an exception if an attempt is made to register
more than one listener.
Even though the JavaBeans API supports both unicast and multicast event sources,
keep in mind that multicast event sources are much less limiting in terms of practical
use. In other words, developers should avoid designing beans as unicast event sources
whenever possible.
Event Adapters
Even though many bean events follow the standard source/listener model about which
you just learned, the JavaBeans API provides a mechanism for dealing with more complex
situations for which this model doesn't quite fit the bill. This mechanism is based
on event adapters, which act as intermediaries between event sources and listeners.
Event adapters sit between sources and listeners and provide a way of inserting specialized
event-delivery behavior into the standard source/listener event model. Event adapters
are important to the event-handling facilities because they open the door for the
implementation of a highly specialized event-handling mechanism tailored to the unique
challenges sometimes encountered in applications or application builder tools.
Persistence
The persistence facilities in the JavaBeans API specify the mechanism by which
beans are stored and retrieved within the context of a container. The information
stored through persistence consists of all the parts of a bean necessary to restore
the bean to a similar internal state and appearance. This generally involves the
storage of all public properties and, potentially, some internal properties, although
the specifics are determined by each particular bean. Information not stored for
a bean through persistence are references to external beans, including event registrations.
These references are expected to be stored somehow by an application builder tool
or through some programmatic means.
By default, beans are persistently stored and retrieved using the automatic serialization
mechanism provided by Java, which is sufficient for most beans. However, bean developers
are also free to create more elaborate persistence solutions based on the specific
needs of their beans. Like the introspection facilities, the JavaBeans persistence
facilities provide for both an explicit approach and an automatic approach to carrying
out its functions.
Application Builder Support
The final area of the JavaBeans API deals with application builder support. The
application builder support facilities provide the overhead necessary to edit and
manipulate beans using visual application builder tools. Application builder tools
rely heavily on these facilities to enable a developer to visually lay out and edit
beans while constructing an application. These facilities fulfill a major design
goal of the JavaBeans API: They enable beans to be used constructively with little
or no programming effort.
One issue with which the JavaBeans architects wrestled is that application builder
support for a specific bean is required only at design time. Consequently, it is
somewhat wasteful to bundle this support code into a runtime bean. Because of this
situation, the application builder facilities require that builder-specific overhead
for a bean must be physically separate from the bean itself. This separation enables
beans to be distributed by themselves for runtime use or in conjunction with the
application builder support for design-time use. The next two sections cover some
of the major issues dealt with by the JavaBeans API application builder support facilities.
Property Editors and Sheets
One of the ways in which the JavaBeans API supports the editing and manipulation
of beans with application builder tools is through property sheets. A property sheet
is a visual interface that provides editors for each public property defined for
a bean. The individual editors used in a property sheet are called property editors.
Each type of exported property in a bean must have a corresponding property editor
if it is to be edited visually by a builder tool. Some standard property editors
are provided by the JavaBeans API for built-in Java types, but user- defined properties
require their own custom editors. The property editors for all the exported properties
of a bean are presented together on a property sheet that enables users to edit the
properties visually.
Customizers
The other way in which the JavaBeans API enables beans to be visually edited in
an application builder tool is through customizers. Customizers are user interfaces
that provide a specialized way of visually editing bean properties. Because customizers
are implemented entirely by bean developers, there are no firm guidelines about how
they present visual property information to the user. However, most customizers probably
will be similar in function to "wizards," those popular user interfaces
on the Windows platform that use multiple-step questionnaires to gather information
from the user.
Summary
This chapter took you inside the JavaBeans technology by exploring the JavaBeans
API. This API is ultimately responsible for delivering all the functionality of JavaBeans.
You learned that the API has several major functional areas, each of which is devoted
to a particular JavaBeans service. You covered the basics of each of these areas
and looked at the kinds of problems they address and the different solutions they
provide.
Although the discussions throughout this chapter were fairly general and avoided
much technical detail, they still painted a pretty complete picture of the JavaBeans
API--at least from a conceptual level. Armed with this knowledge, you're ready to
press on and learn how to use the JavaBeans API in the next chapter, "Creating
Your Own Beans." Roll up your sleeves and get ready for more thrills!
|