JavaBeans

JavaBeans is a "software component model" for Java that has generated quite a lot of interest from many quarters. The JavaBeans API specification defines "beans" as follows:
A Java Bean is a reusable software component that can be manipulated visually in a builder tool.
Components expose their features (for example, public methods and events) to builder tools for visual manipulation. This "exposure" happens as a result of the component engineer following a few basic naming and programming conventions. A "JavaBeans-enabled" builder tool can then examine the Bean's "meta-data", discern its features, and make those features accessible for visual manipulation. A builder tool maintains Beans in a palette or toolbox. You can select a Bean from the toolbox, drop it into a form, modify it's appearance and behavior, define its interaction with other Beans, and compose it and other Beans into an applet, application, or new Bean. All this can be done without writing a line of code. [source: http://java.sun.com/docs/books/tutorial/javabeans/whatis/beanDefinition.html]


Three kinds of users

The java.beans package defines classes and interfaces designed for programmers who are working with beans at three distinct levels:
  1. those that are writing interface builder tools that manipulate beans
  2. those that are creating beans for others to use
  3. those that are assembling an application using beans
The first level supported by JavaBeans are those few people who are writing interface builder tools that manipulate beans. Much of the JavaBeans API is intended for use only by this constituency. The main thing that a builder tool needs to be able to do with beans is "introspect" on them. It needs to be able to determine at run-time: A property is a piece of the bean's internal state that can be programmatically set and queried (usually through a standard pair of "get" and "set" accessor methods). In addition to simple "primitive" properties, there are three "constructed" property types. An indexed property defines an array of legal elements. A bound property sends out notification events when it changes. A constrained property sends out notification events when it is about to change, but it allows the change to be vetoed by any "listener" before the change is consumated.

An event is exactly like the AWT model for broadcast notification. A bean defines an event if it provides methods for adding and removing event "listener" objects. Finally, a method is any public method defined by the bean, excluding those methods used to get and set properties, and register and remove event listeners.

These are all "features" that a builder tool must be able to display to the programmer who is using the tool. The JavaBeans API defines a set of naming conventions for the methods that a bean defines. If a bean follows these conventions, a builder tool can use the Java Reflection API (metadata) to determine what properties, methods, and events the bean supports. The Introspector class uses "reflection" to obtain information about a bean and presents it to the builder tool in the form of a BeanInfo object, which itself contains various FeatureDescriptor objects describing the properties, methods, and events of the bean.

At the second level, the JavaBeans API contains classes and interfaces intended for use by programmers who are creating beans for others to use. One of the surprising features of the JavaBeans API is that there is no Bean class that all beans must extend. A bean can be of any class; however, beans should follow certain naming conventions. The java.beans classes that a bean creator uses are generally auxiliary classes, used not by the bean, but by the builder tool that manipulates the bean. These auxiliary classes are shipped with a bean, and provide additional information or methods that a builder tool may use with the bean. These classes are not included in finished software built with the bean.

For example, one of the auxiliary classes a bean may define is a custom BeanInfo class to provide information to the builder tool that is not available through the Reflection API. This information might include a human-readable description of the bean's properties, methods, and events, for example. Or, if a bean does not follow the standard naming conventions, this custom BeanInfo class must provide more basic information about the bean's properties, methods, and events.

Besides a BeanInfo class, complex beans may also provide a Customizer class and one or more PropertyEditor classes. A Customizer class is a kind of configuration tool or "wizard" for a bean. It is instantiated by the builder tool in order to guide the user through bean customization. A PropertyEditor class allows the user to edit the value of non-primitive bean properties. Builder tools have built-in property editors for common types such as strings, colors, and fonts; but a bean that has properties of some unusual or custom type may want to provide a PropertyEditor subclass to allow the user to easily specify values for those properties.

The third level at which the JavaBeans API can be used is by programmers who are assembling an application using beans. Some programmers may do this through a builder tool, while others may do it "by hand". Programmers using beans do not typically have to use the java.beans package. At this level, it is more a matter of reading the documentation for the particular beans being used and following those instructions. Nevertheless, a programmer using beans does need to be familiar with the Java 1.1 AWT event model used by beans. Also, programmers using beans "by hand" should be familiar with the naming conventions for bean properties, methods, and events, in order to more easily understand how a given bean can be used. In Java 1.1, all AWT components are beans and follow these naming conventions.

[Source: Flanagan97a, pp98-99]


Technical requirements

The surprisingly small list of requirements for a simple JavaBean component are: The "naming signature conventions" can be summarized as follows (where Xxx is the name of the specific property or type). Why are the technical requirements so undemanding? The first reason is that most of each component's interface information is found through the Java Reflection API. The second reason is that Java's "serialization" architecture is so versatile.


JavaBeans introspection

For a component to be easily reusable, there needs to be a way to identify at run-time what methods it supports and the types of events it raises and/or listens for. In JavaBeans, this mechanism is "introspection", and it is an extension to the core Java Reflection API.

The standard reflection capability allows queries to be made to find the class of an object and its public methods and attributes. The JavaBeans introspection mechanism extends this by looking for the use of the implicit "naming signature conventions" summarized above, or, an explicit auxiliary BeanInfo object.

The use of the BeanInfo class allows the author of the bean to expose only a selection of the public methods and attributes. It is also useful when reusing legacy code as a component. Old code may not abide by JavaBean's "naming signature conventions", and BeanInfo provides the indirection necessary to map the old implementation to the required interface.


Java serialization

Serialization allows an object (or an entire hierarchy of objects) to be "flattened" and subsequently: transported across a network, piped to another "process", saved inside some persistence abstraction, and/or recreated from some persistence abstraction. When bean-built applications are executed, the serialized state of each bean is restored identically to its state at the time the bean tool saved it. This strategy differs from that of other component technologies that generate and add dozens of lines of code to the normal application code.


Implementation examples

The class below is a bean. All AWT components are beans, and this class is a slight embellishment of the Button component. It has a default constructor. It implements java.io.Serializable, and it "exposes" properties by using the correct "get/set" naming convention. It does not need to support addActionListener() and removeActionListener() because the base class Button does that. It is interesting to note that even though the property is physically implemented by the attribute named "attrABC", it is logically represented in an interface builder tool by the name "theAbcAttr".
    1  import java.awt.*;

    2  public class MyButtonBean extends Button implements java.io.Serializable {
    3     private int attrABC = 24;

    4     public MyButtonBean() {
    5        super( "press me" );
    6        setActionCommand( "pressMeData" );
    7     }
    8     public void setTheAbcAttr( int in ) {
    9        attrABC = in;
   10     }
   11     public int getTheAbcAttr() {
   12        return attrABC;
   13  }  }
The class below follows all the rules described above, and, it exports its interest in listening for events with the implements ActionListener declaration. It is capable of interfacing with both MyButtonBean beans and beans that derive from TextComponent (lines 22 and 27).
    1  import java.awt.*;
    2  import java.awt.event.*;

    3  public class MyListenerBean extends Panel
    4                              implements ActionListener,
    5                                         java.io.Serializable {
    6     private int attrXYZ = 42;
    7     private TextArea ta;
       
    8     public MyListenerBean() {
    9       setLayout(null);
   10       ta = new TextArea();
   11       ta.setBounds( 0, 0, 100, 200 );
   12       add( ta );
   13       setSize( 100, 200 );
   14     }
   15     public void setTheXyzAttr( int in ) {
   16        attrXYZ = in;
   17     }
   18     public int getTheXyzAttr() {
   19        return attrXYZ;
   20     }
   21     public void actionPerformed( ActionEvent ae ) {
   22        if (ae.getSource() instanceof MyButtonBean) {
   23           MyButtonBean btn = (MyButtonBean) ae.getSource();
   24           ta.append( btn.getLabel() + "\n");
   25           ta.append( "  " + ae.getActionCommand() + "\n");
   26           ta.append( "  " + btn.getTheAbcAttr() + "\n");
   27        } else if (ae.getSource() instanceof TextComponent) {
   28           TextComponent tf = (TextComponent) ae.getSource();
   29           ta.append( tf.getText() + "\n");
   30  }  }  }
Beans are packaged in Java ARchive files (.jar). A .jar archive can contain any number of .class files and other support files. BDK's beanbox tool requires the archive to have a "manifest" file, and the name of that file appears to be limited to "manifest.mf". The manifest file must have entries like the following for all beans contained in the archive.
   Name: MyListenerBean.class
   Java-Bean: True

   Name: MyButtonBean.class
   Java-Bean: True
To create the .jar file, the command is very similar to "tar" on Unix. After the command name, flags, .jar name, and .mf name; all other files can be listed in any order. To show up in the beanbox's ToolBox window, the .jar file must reside in the "jars" subdirectory. To execute the beanbox, you invoke the run.bat file referenced below.
   jar cfm mylistenerbean.jar manifest.mf MyListenerBean.class
                                          MyButtonBean.class
   copy mylistenerbean.jar q:\cpp\java2\bdk\jars
   q:\cpp\java2\bdk\beanbox\run

Technical overview

The more interesting interfaces and classes in the java.beans package include:

EJB   (Enterprise JavaBeans)

The vision/scope of the JavaBeans component model is visually-oriented components that run in desktop-bound, client-side applications. Enterprise JavaBeans extends that vision to larger, transaction-oriented components that run on the server, or anywhere on the network. EJBs run inside of "containers" and "application servers". These architectural frameworks are not new. Early versions of application servers were vendor-specific and defined proprietary interfaces. As a result, services and components had to be developed with advance knowledge of which application server would be used, and then couldn't integrate with components written for a different vendor server.

Sun decided to address this cacophany of competing standards by creating the Enterprise JavaBeans specification. It formally defined the capabilities an EJB application server must support, and standardized the programming interface to access them. An application "system" is composed of Enterprise JavaBeans, that are plugged into EJB containers, which in turn are plugged into EJB-compliant application servers.

The current version of the EJB specification standardizes support for things like managing transactions, multithreading, synchronization, object activation and passivation (persistence), object locating (naming services), security, and component interoperability. It also partitions a number of tasks as being application server implementation details and shields EJB developers from having to know how they are implemented. A couple of these "details" are pooling of resources (like database connections) and load balancing.

Another significant feature of EJB is the capability for developers to define and customize runtime attributes (such as transaction, security, and state management) declaratively via environment properties using visual tools.

The EJB model defines the roles and relationships between: components, containers, and servers. Components are encapsulated, engineered, and packaged pieces of functionality that can be assembled into working application systems. Components execute within a construct called a container.

A container provides an application context for one or more components. In practical terms, a container provides an operating system process or thread in which to execute the component. The container manages all resources on behalf of its components and manages all interactions between the components and any external systems. Client components normally execute within some type of visual container, such as a form, a compound document, or a Web page. Server components are non-visual and execute within a container that is provided by an application server, such as a TP monitor, a Web server, or a database system.

The EJB container

An application server provides an optimized execution environment for server-side containers. It combines traditional OLTP technologies with new distributed object technologies. Servers automate some of the more complex features of multitier computing. They manage and recycle scarce system resources, such as processes, threads, memory, database connections, and network sessions on behalf of the applications. Some of the more sophisticated application servers offer load-balancing services that can distribute application processing across multiple systems. An application server also provides access to infrastructure services, such as naming, directory, transactions, persistence, and security.