Java Beans                               revision Aug 21 / 2001      Peter Komisar

references:
'Java 1.2 Developer's Handbook', Heller & Roberts,  'Java 1.1 The Complete Reference'
Naughton & Schildt, JDK 1.2.2 API documentation,  The Jar Guide', & 'The Manifest File Format',
The Sun web site 'Introduction the the JavaBeans API, John Zukowski


What is a Java Bean?

A JavaBean is a reusable component. JavaBeans are all built to a specification that
allows them to work together. A simple example of a reusable, interconnectable
component is a lego block. We take for granted they can be connected together to
build large and complex structures. What allows them to be interconnected is the fact
that they are built to an exact specification. There are a specific number of protrusions
and depressions that are positioned in exactly the right places so they can interlock.
The legos also have exact overall dimensions that allow them to fit together. Making
software interconnect like lego blocks is a considerably more complicated business
especially considering that javabeans, beyond fitting together, can provide extra
functionality to a program and are able to communicate with each other. Still the
fundamental idea remains the same in that a blueprint allows different objects to
interconnect by virtue of them adhering to a a uniform standard.
 

The javabean architecture also allows the beans to be pieced together using a java bean
compliant visual development environment The bean design provides the development
environment the means to find out what properties the bean has and what the bean can
do. As might be anticipated, developing javabeans is more complicated than developing
regular java programs because of the added need to conform to the java bean blueprint.
Fortunately, the extra restraints on the code are not that hard to learn and implement.
The advantage gained  is that your code will automatically be interconnectable with other
javabeans.
 

An example of java beans are java's visual components, the AWT widgets and the
newer swing components. They are all javabeans and conform to the javabean architecture.
This may lead you to think that java beans are all about visual components and GUIs.
While the the design has been very successfully applied to producing visual components,
the architecture can be equally well applied to non-visual functions. The only thing hitch is
that to run a java bean that provides non-visually oriented functionality in a visual development
environment, you will need to supply a visual component to act as a host for your java bean
functionality.

Patterns and Reusability

The desire to make code reusable is not really a new idea. Computer programmers
for a long time recognized they were often reinventing the wheel with each new project
they undertook. In 1968 M.D.McIlroy's published a request that a catalog of software
components be created that could be plugged together to build applications. For a long
time this was sort of a search for the holy grail that had been pursued with more or less
success. Javabeans provides a decidedly successful answer to McIlroy's request. The
javabean architecture has provided a large collection of interoperable components that
can interconnected by hand-coded java or with the aid of a java beans development
environment.
 

"Each pattern describes a problem which occurs over and over again in our environment,
and describes the core of the solution to that problem, in such a way that you can use this
solution a million times over, without ever doing it the same way twice"

                                                                                                                    Christopher Alexander

The designers of the javabeans architecture were influenced by the study of patterns
that has been carried out in many academic fields of study. The study of patterns began
with the release of Christopher Alexander's book 'The Timeless Way of Building'
printed by Oxford Press in 1978. Alexander was an architect who observed different
problems would arise in buildings that the builders would solve in the same way over
and over again. He cataloged these patterns in his book. Academics in other disciplines
were soon looking for patterns in their fields of study.

Four computer scientists, Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides
wrote the highly influential  book, 'Design Patterns-Elements of Reusable Object Oriented
Software' which was published in 1995. The researchers document 23 well used software
patterns in this book.

The advantage to recognizing patterns is that they provide a prescription for a tried and
tested solution to a problem that can be refined and perfected and doesn't need to be
rediscovered every time a problem arises. The javabean architecture benefits from the
use of classic patterns in it's design, and also supply the java programmer with a design
pattern that can be followed in order to create reusable and interoperable java
components.
 

Practical Aspects of Using JavaBeans

The Bean Box

JavaBeans are designed to be used in combinations to create applets and applications.
The architecture allows builder tools to be used to execute this task. The builder tools
allows beans to be put together visually without the need for the builder to do provide
and code. To assist the developer, a reference builder is supplied called the BeanBox.
The BeanBox is to javabeans what appletviewer is to applets. It provides a quick way
for a developer to find out how his or her bean will behave in a visual environment.
Commercial IDE such as IBM's Visual Age for Java will supply a sophisticated version
of the bean box to put together javabeans.

Get & Run the BDK

The Bean Development Kit is a 5 megabyte download. The self-extracting archive
can be downloaded from sun at http://java.sun.com/beans/software/bdk_download.html
To start the application you have to change to the  \bdk\ beanbox directory and
execute the batch file, run.bat. John Zukowski one of the early authors of Java texts
has a useful article written at the sun site if you wish to visit it. Introduction to the
JavaBeans API

Bean Box Operations

The BeanBox produces three windows. The windows allow a user to modify a
bean's state using property sheets. The bean box allows beans to message each
other using property changes and events. The bean box also allows saving a bean
with all it's property states via the serialization process. The bean box expects the
java bean will be packaged in a jar file when it loads it into it's work area. The
bean box environment provide these controls along with other point and click
operations to create programs built from java beans.

What the BeanBox does alludes to what a JavaBeans is. Beans are stateful objects
that can be persisted in memory. Beans are normally packaged in jar files. JavaBeans
can communicate with each other through events and property changes. Beans are
inconnectable components that can be assembled in a builder's tool.

Jar Files

Java tools such as the BeanBox expect beans to be packaged in JAR files. The
jar utility is another variant on the zip file invented by Phil Katz who donated his
compression scheme for public use. Jar files like their Zip equivalents, provide
an efficient means for packaging and accessing a set of java classes. Jar files
serve to reduce download time. They also allow digital signatures to be associated
with the jar allowing for authentication and security. When a jar file is used to house
a java bean it's manifest file must be used to indicate which components are Java
beans.

Example  Name: frame1.gif           // a manifest may have several .class files
             Name: Frames.class        // when they are beans they must be followed
             Java-Bean: True            // by the tag line 'Java-Bean' True
 

JAR Utility

To create a jar file type jar at the command line followed by options and names, first,
what you wish to call the jar file, then the name of the manifest file, followed by the
names of the files you wish to enter in the archive. (If you are not creating a bean than
you may not need the manifest and your command becomes jar cf and the name
following will be the name of the jar followed by the classes or pattern for the classes
you want entered into the archive.)

example   jar  cfm  Globe.jar  Places.mf   *.gif   *.class

//  places all .class and .gif in current directory into a JAR  file named Globe.jar
//  with  an externally prepared manifest file Places.mf

Here is a second example straight from the jar utility. // type jar by itself at the command line

example  jar  cvfm  classes.jar   myM   -C foo/ .

Use an existing manifest file 'myM' and archive all the files in the foo/ directory into 'classes.jar':

Following is a list of jar options. Notice two of the capital letters describe negative
actions and the third C doesn't follow the rule.

jar options
 
  c   a new archive is created
  f   makes the first file name listed that of the archive
 m   makes the next name that of the manifest file
 M   no manifest file is created 
 t   tabulate archive contents
 x   extract archive files
 v   provide verbose output as utility executes
 C   change to the given directory and include the following file
 O  do not compress
 i  generate index info for the named manifest file
 u  update existing archive

Creating a Bean

Assuming we have the code that defines a bean prepared and we will get to that, there
are a number of mechanical steps that have to be followed in creating a java bean. First
a directory for the bean needs to be created. Once created switch into that directory.
The java source file is copied into the directory. The source code's packaging scheme
must match the hierarchy of the directory structure. A manifest file needs to be prepared
as a straight text file and saved with the .mf or .mft extension. Inside the manifest any
classes that represent java beans must be tagged with script indicating they are
javabeans.

example      Manifest-Version: 1.0 
                      Name: SimpleBean.class
                      Java-Bean: true

A jar file is created using a statement such as the following.

example   jar cfm    jar_name    manifest.mft    *.class

Finally the BeanBox can be started and the newly created bean can be loaded into it to
see if it works as expected.
 

Summary of Steps involved in packaging a javabean.
 
 1.Create a directory for the bean ( and switch to it ).
 2.Create the java source file matching package hierarchy to that of the directory structure.
 3.Compile the source file* // see box below
 4.Write the manifest file, saving with the .mf /.mft extension to the directory, tagging 
    the bean as below

 example 1     Name: new_directory / the_bean.class
                        Java-Bean: true

 example 2   Manifest-Version: 1.0     //  this is the contents of a tested manifest file 
                      Name: SimpleBean.class 
                      Java-Bean: true 
 

 The manifest file consists of a list of files present within the archive itself. Not all files 
 in the archive need to be listed in the manifest, but all files which are to be signed must 
 be listed. The manifest file itself must not be listed. A preliminary section appears at the
 top of the file containing, at minimum, this standard's version number.

 Manifest-Version: 1.0*
 

 5. Generate a jar file using  jar cfm    jar_name    manifest.mft    *.class
 6. Start the BDK by changing to c:\bdk\beanbox and type run
     // The new bean should be in the toolbox window
 7. Test by loading excercising the beans parameters in the BeanBox 

Bean developers can automate some of these processes using Makefile utilities. For more
on this topic see JavaBeans Makefiles
 
 Makefile utilities  // for reference


 Makefile utilities have been developed to simplify the bean building process serving 
 to eliminate the needs for steps 3, 4 and 5 above (compiling the bean, writing the 
 manifest and creating the jar file)

 For Unix, run  gnumake yourBean.gmk 

 For Windows, run nmake -f yourBean.mk

 This will compile SimpleBean, and create a JAR file in the beans/jars directory. 
The BeanBox looks in that directory for JAR files
..

Beans Support

Java Bean support comes in the following packages. The beans package provides
the general support for visual tools to build beans. The beancontext package provides
a way to structure beans in hierarchies. The reflect package is java's generic package
for accessing internal information about java objects. A typical java bean will include
these packages as imports.

Reflection and Class Class

At runtime a Java Virtual Machine knows how to build an object based on information
it has obtained from class bytecode.This same information regarding the field(s), method(s)
and constructor(s) of a class can be accessed using the Reflection API in java.lang.reflect.
Though only the JVM can create an instance of these classes from the bytecode info, you can
get a representative instance of them using the class Class.

RTTI or Run Time Type Information for any object is stored in an object of class Class,
which is full of informational method types like isPrimitiveArray( ), or getConstuctor( ).
One the main functions of Class is to provide auxiliary support for the loading of classes at
runtime. Programs written in other languages will often load everything before running. (This
is static loading. Java uses dynamic loading. (Classes are loaded when they are first
referenced).

When source code is compiled to a .class file, in addition to translating source code to
bytecode, a Class object, is written into the bytecode describing the files contents. The
runtime checks any casts that have been made using this object, before allowing the class
to be loaded into the program.

Three ways of getting a Class object:

              1) Class c = lemon.getClass( );                       // off an instance
              2) Class q = Class.forName("className");     // via a  static method call
              3) className.class                                         // a class literal
 

Introspection   //  a specialized form of reflection for getting information about a bean.

Introspection is a specialized use of the reflection process. Introspection is the process
of finding what properties, methods and events a Bean support. This capability is a
specialized use of the reflection process. The Introspector class uses reflection (the
more general tool for decomposing any object) and applies it to Bean instances. The
Introspector class provides a standard way for vendor tools to acquire the bean info.

Additional information is derived from the way beans conform to design patterns resulting
in the further exposure of bean information. Introspector provides access to the BeanInfo
class via it's getBeanInfo( ) method.

// the method takes an instance of class Class for a given component

From the BeanInfo class returned by getBeanInfo( ), you can call  getXXXDescriptor( )
methods, where XXX can be EventSet, Property or Method  providing info for all the
events the bean fires, all the properties and all the methods the Bean supports.
 
 
 public class Introspector extends Object // from jdk1.3 documentation, for reference

 The Introspector class provides a standard way for tools to learn about the properties, 
 events, and methods supported by a target Java Bean. 

 For each of those three kinds of information, the Introspector will separately analyze the 
 bean's class and superclasses looking for either explicit or implicit information and use that 
 information to build a BeanInfo object that comprehensively describes the target bean. 

 If a class provides explicit BeanInfo about itself then we add that to the BeanInfo information 
 we obtained from analyzing any derived classes, but we regard the explicit information as 
 being definitive for the current class and its base classes, and do not proceed any further
 up the superclass chain. 

 If we don't find explicit BeanInfo on a class, we use low-level reflection to study the 
 methods of the class and apply standard design patterns to identify property accessors, 
 event sources, or public methods. We then proceed to analyze the class's superclass
 and add in the information from it (and possibly on up the superclass chain). 
 

BeanInfo

The information gathered in Introspection is poured into an instance of the BeanInfo class. This
interface has methods which can be used to control what information is returned to the user,
allowing more or less detail than is provided by reflection alone. Normally BeanInfo is used to
provide the bean tool user with less information so the Bean is easier to work with. The
bean info class must be named after the bean it is associated with. For example, a Bean named
Jumping need a bean info class called JumpingBeanInfo. SimpleBeanInfo is a convenience
class which allows you to override methods selectively.

Persistence

The ability to save the state of a java bean is achieved through serialization. Serialization
uses the reflection process to store information about the state of an object.When
you Save a bean to a .ser file via the menu in BDK's BeanBox, persistence is achieved
by writing the java bean to file through ObjectOutputStream. It is retrieved through
ObjectInputStream. As a result, the bean must be tagged with the Serializable
interface. The Serializable interface is one of Java interfaces that defines no methods.
The Serialiizable interface is just used to mark an object as being serializable.
 

Customization

A builder tool uses reflection to present a default property sheet for use by the bean
integrator. If the BeanBox's standard GUI for property or service presentation is inadequate,
the interface Customizer can be implemented to improve or customize the presentation.

According to the jdk1.3 documentation, "A customizer class provides a complete custom
GUI for customizing a target Java Bean. Each customizer should inherit from the java.awt.
Component class so it can be instantiated inside an AWT dialog or panel. Each customizer
should have a null constructor."

// customizer's should inherit from components so it can come up in a dialog or panel

PropertyEditorSupport

To create an alternate presentation for a single property, PropertyEditorSupport class can
be extended. Both customization and property editor support requires the Bean to provide a
support class which implements the BeanInfo interface.

// PropertyEditorSupport -a support class to help build property editors.
 

Bean Properties

When bean writers adhere to the JavaBean's naming conventions, the Introspector can
recognize and abstract information about the beans properties and events. The Introspector
also scans the class hierarchy and by default fills the beans property sheet with inherited (and
perhaps unwanted properties). As mentioned earlier, this is where BeanInfo interface is used
to filter the information that will be presented by the Bean.

// the BeanInfo interface limits the information entered into the bean's property sheet.

JavaBean properties are classified in four categories.
 

Simple Properties

Simple properties are those that can be described by a get/set method pair as in the
following examples:

public void  setPropertyName( property_type )      property_type   getPropertyName( )

// set takes the simple property, get returns it

For boolean properties the following form is also allowed.

setPropertyName( boolean )        boolean isPropertyName( )

// where  isXXX( )  returns boolean
 

Indexed Properties

Indexed properties are plural versions of the simple form methods where instead
of a simple value an array is taken or returned.

setPropertyName( property_type [] )         property_type []  getPropertyName( )
 // set takes an array  , get returns an array

setPropertyName(property_type[], int )      property_type[]  getPropertyName(int) *

// indexed array in, indexed property returned,  * here int is a specified index value
 

Bound Properties

A control bean can be defined to bind it's property changes to those of other beans.
Firing a change in the source automatically updates properties in other targets. An
intermediary class has been designed to take care of the details of binding properties.

The class, PropertyChangeSupport supports a registration model where target bean
properties are added or removed from a notification list. The binding Bean uses the list to
call listeners through the method firePropertyChange( ). The method is called from the
setXXX( ) method of the binding property.

Summary of property binding

1) Instantiate PropertyChangeSupport on this (usually), the source bean instance
2) Override add /removePropertyChangeListener( ), wrapping in them calls to the
    same method on the PropertyChangeSupport instance.
3) getXXX( ) method returns the property which will be bound in setXXX( )
4) in setXXX( ) method make the property changes then fire them.
 
 
Example demonstrating the above summary of property binding

 1)  PropertyChangeSupport pc_support = new PropertyChangeSupport(this); 

 2) public void addPropertyChangeListener(PropertyChangeListener pc_listener){
         pc_support.addPropertyChangeListener(pc_listener);
         }                              //  do the same for removePropertyChangeListener
 3) public int  getProperty( ){
         return property;
        }
 4) public void setProperty(int newProperty ) { // set takes the new property
         int oldProperty = property;
         property = newProperty;
         pc_support.firePropertyChange( "property", oldProperty, newProperty ) 
        }
.


 
public interface PropertyChangeListener extends EventListener


 A "PropertyChange" event gets fired whenever a bean changes a "bound" property. 
 You can register a PropertyChangeListener with a source bean so as to be notified 
 of any bound property updates. 


 void  propertyChange(PropertyChangeEvent evt) 
 // This, it's only method is called when a bound property is changed.
.

Target Beans

The target bean only real requirement is to support a method that includes the appropriate
EventObject subclass in it's argument. Target beans do not have to implement listener
interfaces. The bean builder tool will provide a hookup or adapter class that achieve the
same end. The hookup acts as a proxy for the target implementing the required interface
on the targets behalf.


public class PropertyChangeSupport extends Object implements Serializable

This is a utility class that can be used by beans that support bound properties. You can use
an instance of this class as a member field of your bean and delegate various work to it.

 Constructor    // from jdk1.2.2 API docs
 
PropertyChangeSupport(Object sourceBean)    Constructs a PropertyChangeSupport object.

 Methods                                                                                                (5 of 9 methods)
 void addPropertyChangeListener
(PropertyChangeListener listener)
 Add a PropertyChangeListener to the listener list. 
 // 1 of 2
 void firePropertyChange
(PropertyChangeEvent evt) 
 Fire an existing PropertyChangeEvent to any registered 
 listeners. Overridden to take (String propertyName, type
 oldValue and type newValue) where type is  int boolean
 or Object in which case the method reports an int boolean
 or Object , bound property update to any registered 
 listeners. // 1of 4
  boolean hasListeners
(String propertyName) 
 Check if there are any listeners for a specific property.
void removePropertyChangeListener
(PropertyChangeListener listener) 
 Remove a PropertyChangeListener from the listener list.
void  removePropertyChangeListener
(String propertyName, 
PropertyChangeListener listener) 
 Remove a PropertyChangeListener for a specific property.


Constrained Properties

Constrained properties are similar to bound properties but also allow the target beans to
reject updates to their properties. Rejecton may occur because a new value is illegal,
invalid or just inappropriate. The Bean normally maintains a VetoableChangeListener(s)
list in addition to a list of PropertyChangeListener(s).

 //  If  the target does not throw exception then the new value is excepted into the target.
// In practice Beans may have both bound and constrained properties being notified in parallel.
 
Example of implementing  a vetoable change // from JavaBean Short course


   private VetoableChangeSupport vetoes = new VetoableChangeSupport (this);

     public void addVetoableChangeListener (VetoableChangeListener v) {
                          vetoes.addVetoableChangeListener (v);
                         }
    public void removeVetoableChangeListener (VetoableChangeListener v) {
                       vetoes.removeVetoableChangeListener (v);
                        }
    // in the bound model the PropertyVetoException is not defined as being thrown

    public void setSalary (float salary) throws PropertyVetoException {
         Float oldSalary = new Float (this.salary);
         vetoes.fireVetoableChange ("salary", oldSalary, new Float (salary));
         this.salary = salary;
         changes.firePropertyChange ("salary", oldSalary, new Float (this.salary));
         }
 // On the receiving end, the VetoableChangeListener needs a vetoableChange method. 

    public void vetoableChange(PropertyChangeEvent e)
           throws PropertyVetoException;

// notice if the vetoableChange method throws it's exception,  it cause it to be raised 
// in setSalary and as a result the firePropertyChange method is not reached. 
 



public class VetoableChangeSupport extends Object implements Serializable

This is a utility class that can be used by beans that support constrained properties. You can
use an instance of this class as a member field of your bean and delegate various work to it.

Constructor     // from the jdk documentation
 
 VetoableChangeSupport(Object sourceBean)     Constructs a VetoableChangeSupport object.

 Methods                                                                                                (5 of 9 methods)
 void addVetoableChangeListener
 (VetoableChangeListener listener) 
 Add a VetoableListener to the listener list.  // 1 of 2
 void fireVetoableChange
 (PropertyChangeEvent evt) 
 Fire an existing VetoableChangeEvent to any registered listeners.
Overridden to take (String propertyName, typeoldValue and typenewValue) where type is int,  boolean or Object in which case the method reports an int boolean or Object , bound property update to any registered listeners. // 1of 4
  boolean hasListeners
 (String propertyName) 
 Check if there are any listeners for a specific property.
 void removeVetoableChangeListener
 (VetoableChangeListener listener) 
 Remove a PropertyChangeListener from the listener list.
 void  removePropertyChangeListener
 (String propertyName, 
 VetoableChangeListener listener) 
 Remove a PropertyChangeListener for a specific property.

 
public interface VetoableChangeListener extends EventListener


 A "VetoableChange" event gets fired whenever a bean changes a "constrained" property. 
 You can register a VetoablerChangeListener with a source bean so as to be notified 
 of any bound property updates. 


 void vetoableChange(PropertyChangeEvent evt) 
 // This, it's only method is called when a constrained property is changed.
.

The following example is excerpted from the custom event modeling shown in the
'Java Beans Short Course' in the tutorial section at the sun site. Here is the url

http://developer.java.sun.com/developer/onlineTraining/
Beans/JBShortCourse/beans.html#beanWriteEvent

Bean Events

When writing a JavaBean you may wish to provide it with it's own customized events. If
you are extending stock beans like awt and swing events you can use the event processing
that have been provided. It is useful to consider a customized event strategy as it shows
clearly the underlying workings of the Delegation Event Model used in Java.

An event allows your Beans to communicate when something interesting happens.
There are three parts to this communication:


EventObject

 The java.util.EventObject class is the basis of all Beans events.

          public class java.util.EventObject
                         extends Object implements java.io.Serializable {
                       public java.util.EventObject (Object source);
                       public Object getSource();
                       public String toString();
                     }

Although you can create EventObject instances directly for your Bean events, design
pattern guidelines require you to subclass EventObject so you have a specific event type.
For example, to define an event for an employee's hire date, you could create a HireEvent
class.

          public class HireEvent extends EventObject {
                       // concrete implementation of EventObject
                       private long hireDate;
                       public HireEvent (Object source) {
                         super (source);
                         hireDate = System.currentTimeMillis();
                       }
                       public HireEvent (Object source, long hired) {
                         super (source);
                         hireDate = hired;
                       }
                       public long getHireDate () {
                         return hireDate;
                       }
                     }

EventListener

The EventListener interface is empty, but serves as a tagging interface that all event
listeners must extend in order for Bean integration tools can work. A listener is something
that desires notification when an event happens. The listener receives the specific EventObject
subclass as a parameter. The name of the new listener interface is EventTypeListener.
For the new HireEvent, the listener name would be HireListener. The actual method names
within the interface have no specific design pattern to follow, but, should describe the event
that is happening. // the name of the method of the method doesn't have to follow a naming pattern

                     public interface HireListener
                         extends java.util.EventListener {
                       public abstract void hired (HireEvent e);
                 // the key is the method has to take the event object
                     }

Event Source

Without an event source, the HireEvent and HireListener are virtually useless. The event
source defines when and where an event will happen. Classes register themselves as
interested in the event, and they receive notification when the event happens. A series
of methods patterns represents the registration process:

                public synchronized void addListenerType(ListenerType l );
                     public synchronized void removeListenerType( ListenerType l );

The event source needs to maintain the list itself, so the entire code to do this is:

                 private Vector hireListeners = new Vector();
                     public synchronized void addHireListener (
                       HireListener l) {
                       hireListeners.addElement (l);
                     }
                 public synchronized void removeHireListener (HireListener l) {
                      hireListeners.removeElement (l);
                     }

If you are using AWT components, AWT events already have this behavior. Maintaining
listeners is only necessary for new event types, or adding listeners where they previously
were not (ActionEvent within a Canvas). If you want to permit only one listener (unicast),
you have the addListenerType method throw the java.util.TooManyListenersException
exception when adding a second listener (and you do not need a Vector). Also, remember
to synchronize the add/remove methods to avoid a race condition.

Once the event happens, it is necessary for the event source to notify all the listeners. For
the hiring example, this would translate into a method like the following:

             protected void notifyHired ( ) {
                       Vector l;
                // create Event
                       HireEvent h = new HireEvent (this);
                       // Copy listener vector so it won't
                       // change while firing
                       synchronized (this) {
                         l = (Vector)hireListeners.clone( );
                       }
                       for (int i=0;i<l.size();i++) {
                         HireListener hl = (HireListener)l.elementAt (i);
                         hl.hired(h);
                        }
                     }