1
What are JavaBeans ? • A Bean is a reusable software component. •
JavaBeans is a set of reusable software components written in java
• JavaBeans is a new technology that is used to construct applications by configuring and connecting components called Beans Why JavaBeans • Beans can be created or can be got in binary format from vendors • • These building blocks need to be designed, coded and tested only once and can be reused in multiple applications. • • Creating a Bean is just like creating any other java program • • JavaBeans led to a new type of programmer called the component assembler who uses well defined components to create more functionality JavaBeans the Self-Contained Component • JavaBeans adds to the Java platform the capability to create a complete application by simply linking together a set of self-contained components • • There is no restriction on the size or complexity of a JavaBeans component • • The philosophy behind JavaBeans is to provide easy to implement functionality for the component • JavaBeans is based on the reuse and interoperability of Bean components JavaBeans and Containers
Container
Container
JavaBean1 JavaBean
JavaBean2
2 Concepts in Component Model JavaBeans provides a platform neutral component architecture The features of JavaBeans are • Component fields or properties • Component methods or functions • Events and intercommunication • State persistence and storage Component fields or properties • A Component will have a set of properties that define its state eg. A component to display text Foreground color Type of font Size of font If the properties of one component match that of another then they are in the same state Properties not only define the appearance but also the behavior of components A component may not have any appearance at all but can have behavior eg. A component in a spreadsheet that calculates the interest earned on some earning column but not capable of displaying the data • •
Properties can range from boolean values, strings, arrays to other components Components can also be independent
Component methods or functions • API of a component is the collection of methods or functions that it contains so that other components and containers can call • • A container can modify a component’s properties and notify it as an event • • Different component models differ in how they make properties and methods of their components available to other components Events and Intercommunication • A component by itself is a lonely component • A component becomes useful when it is used in conjunction with other components • The method by which one component communicate with another component is event transmission • A component undergoes some action causing it to generate an event • An event can also be generated when a button is clicked • When an event happens the component will notify other interested components depending on the model
3 State Persistence and Storage • The components should remember their state and is very important • If an application remembers the size and position of its window when it was last closed it is maintaining a persistent state • The capability to store and retrieve components is called packing • In a distributed environment where the components are served up over a network it is important to store and retrieve components The Basics of Designing a JavaBean • Designing a Bean directly affects the way it behaves in a container • The names chosen for the methods should follow specific design specifications • If the Bean is designed with proper rules then when the Bean participate in Introspection there will be no need for additional programming Designing a Bean consists of the following steps • Specifying the Bean’s properties • Specifying the events the Bean generates or responds to • Defining which properties, methods, and events the Bean exposes to other Beans or to its container • Deciding miscellaneous issues, such as whether the Bean has its own Customization dialog box or whether it requires some prototypical state information • Designing a Bean can be more explained with the help of an example • There are two Beans a Bean to enter text and another Bean to display the text • The two Beans are placed in a container so that one Bean can be used to enter text and the other Bean to display it. • There can be a number of questions about the properties of the Beans • The first thing a Bean needs is a name and they are TextDisplayer and TextReader
Specifying the Bean’s Properties
The TextDisplayer and TextReader Beans should have property defining the text they hold Property Name
Java Type
OutputText
java.lang.String
BGColor
java.awt.Color
TextFont
java.awt.Font
FontColor
java.awt.Color
TextDisplayer Bean Properties
Property Name
Java Type
InputText
java.lang.String
Width
int
TextReader Bean Properties
4 Specifying the Events the Bean Generates or Responds To • The TextDisplayer Bean must respond to an event specifying that its text should change • The TextDisplayer must update its OutputText property and redraw itself • The TextReader Bean doesn’t need to respond to any event but should generate an event when the user changes its InputText property • This type of event is called a PropertyChangeEvent Properties, Methods and Event Exposure • These Beans are simple so there is no need to hide anything from the Bean’s container or other Beans interested in them • Java Beans provides a mechanism that will use methods to extract the names and types of the properties and events Initial Property Values and Bean Customizers
The Beans TextDisplayer and TextReader have a predefined state when they are instantiated and they use standard PropertyEditors for their properties Property Name
Default Value
TextOutput
“TextDisplayer”
BGColor
java.awt.Color.white
TextFont
Courier, normal, 12
FontColor
java.awt.Color.black
Default Property Values for the TextDisplayer Bean
Initial Property Values and Bean Customizers (contd.) Property Name
Default Value
InputText
“ “ (an empty string)
Width
40
Default Property Values for the TextReader Bean
public class TextDisplayer extends Canvas implements PropertyChangeListener { // default constructor for this Bean. This is the constructor that an application // builder would use. public TextDisplayer() { this( "TextDisplayer", Color.white, new Font( "Courier", Font.PLAIN, 12 ),
5 Color.black ); } // custom constructor for this Bean. public TextDisplayer( String OutputText, Color BGColor, Font TextFont, Color FontColor ) { super(); // call the Canvas's constructor. this.OutputText = OutputText; this.BGColor = BGColor; this.TextFont = TextFont; this.FontColor = FontColor; setFont( TextFont ); // set the Canvas's font. setBackground( BGColor ); // set the Canvas's background color. setForeground( FontColor ); // set the Canvas's foreground color. } // this Bean's properties. protected String OutputText; protected Color BGColor, FontColor; protected Font TextFont; } The Bean implement an interface called PropertyChangeListener and is used so that the TextDisplayer Bean can update its OutputText property by receiving an event public class TextReader extends TextField { // default constructor for this Bean. This is the constructor that an application builder // would use. public TextReader() { this( "", 40 ); } // custom constructor for this Bean. public TextReader( String InputText, int Width ) { super( InputText, Width ); this.InputText = InputText; this.Width = Width; setEditable( true ); }
6 // this Bean's properties. protected String InputText; protected int Width; } Creating and Using Properties • • The TextDisplayer Bean display in black fonts in white background as the property is set like that and the FontColor property can be changed according to the users wish. • If the property of a component cannot be changed by other Beans the usefulness and reusability of the Bean is reduced. eg. Bean’s FontColor property to red to indicate a negative value • Four types of properties are associated with a JavaBean • Single value property – is a property for which there is only one value • Indexed property – an indexed property has several values each of which has a unique index • Bound property – a property is bound means that some other Bean is dependent on that property. eg. TextDisplayer and TextReader • Constrained property – a property is constrained if it must check with other components before it can change and constrained properties cannot change arbitrarily Single Value Properties • • • • • • • • • • • •
There are two types of properties Readable properties and Writable properties Readable properties have a getter method used to read the value of the property Writable properties have a setter method used to change the value of the property These methods not only return the value of a property but also can perform calculations and return some other value. The method by which other components and methods learn about a Bean’s properties is called Introspection The class java.beans.Introspector provides introspection information to other components The Introspector class traverses the class hierarchy of a particular Bean and finds explicit information provided by the Bean and uses it. Introspector uses design patterns to extract implicit information from those Beans that do not provide explicit information Specific design rules should be applied when defining accessor methods so that the Introspector class can get the Bean properties easily
7 • •
A BeanInfo class can be supplied to expose a Bean’s properties The design patterns that should be used when defining accessor methods are of the following format
Public void set
( value ); Public get(); Public boolean is(); • The last pattern is an alternative getter method for Boolean properties Only • Setter methods can allowed to throw exceptions if they need •
The accessor methods for the TextDisplayer Bean is as follows
public synchronized String getOutputText() { return( OutputText ); } public synchronized void setOutputText( String text ) { OutputText = text; resizeCanvas(); } public synchronized Color getBGColor() { return( BGColor ); } public synchronized void setBGColor( Color color ) { BGColor = color; setBackground( BGColor ); // set the Canvas's background color. repaint(); } public synchronized Font getTextFont() { return( TextFont ); } public synchronized void setTextFont( Font font ) { TextFont = font; setFont( TextFont );
// set the Canvas's font.
resizeCanvas(); } public synchronized Color getFontColor() { return( FontColor ); }
8 public synchronized void setFontColor( Color color ) { FontColor = color; setForeground( FontColor ); // set the Canvas's foreground color. repaint(); • • • • •
}
All the accessor methods have been declared synchronized assuming that the Beans are running in multithreaded environments Using synchronized accessor methods helps prevent race conditions from forming The following figure shows the property sheet of Sun’s BeanBox for the TextDisplayer Bean
Indexed Properties All indexed properties must be Java integers. • Indexed properties can be read individually or as an entire array. • • The design patterns for indexed properties are as follows public get( int index ); public void set(int index, value); public [ ] get(); Public void set ( [ ] value );
9
Bound Properties • The programmer can decide which all Bean properties other components can bind to • To provide bound properties in a Bean the following methods must be defined public void addPropertyChangeListener( PropertyChangeListener 1 ); public void removePropertyChangeListener( PropertyChangeListener 1 ); To provide this functionality on a per-property basis the following design pattern should be used. public void addListener( PropertyChangeListener 1 ); public void removeListener( PropertyChangeListener 1 ); • • Beans which want to bind to other components properties should implement the PropertyChangeListener interface which consists of the following method public void propertyChange( PropertyChangeEvent evt ); • • Whenever a bound property in a Bean is updated it must call the propertyChange() method in all the components that have registered with it • •
The class java.beans.PropertyChangeSupport helps to call all the components that have registered with the property The following code shows what is required in the TextReader Bean to allow its InputText property to be bound.
// setter method for the InputText property. public synchronized void setInputText( String newText ) { String oldText = InputText; InputText = newText; setText( InputText ); changeAgent.firePropertyChange( "inputText", new String( oldText ), new String( newText ) );
}
// these two methods allow this Bean to have bound properties. public void addPropertyChangeListener( PropertyChangeListener l ) { changeAgent.addPropertyChangeListener( l );
}
public void removePropertyChangeListener( PropertyChangeListener l ) {
10 changeAgent.removePropertyChangeListener( l );
}
protected PropertyChangeSupport changeAgent = new PropertyChangeSupport( this ); Constrained Properties •
The process for providing constrained properties is by defining the following methods in the Bean
public void addVetoableChangeListener( VetoableChangeListener 1 ); public void removeVetoableChangeListener( PropertyChangeListener 1 ); • • To provide this functionality on a per-property basis the following design pattern should be used. public void addListener( VetoableChangeListener 1 ); public void removeListener( VetoableChangeListener 1 ); • • Beans intended to constrain other components properties should implement the VetoableChangeListener interface which consists of the following method public void VetoableChange( PropertyChangeEvent evt ); • • Whenever a constrained property in a Bean is updated it must call the VetoableChange() method in all the components that have registered with it • The class java.beans.VetoableChangeSupport helps to call all the components that have registered with the property • The following code shows what is required in the TextReader Bean to allow its Width property to be constrained // setter method for the Columns property. public synchronized void setWidth( int newWidth ) throws PropertyVetoException { int oldWidth = Width; vetoAgent.fireVetoableChange( "width", new Integer( oldWidth ), new Integer( newWidth ) ); // no one vetoed, so change the property.
11 Width = newWidth; setColumns( Width ); Component p = getParent(); if ( p != null ) { p.invalidate(); p.layout();
}
changeAgent.firePropertyChange( "width", new Integer( oldWidth ), new Integer( newWidth ) );
}
// these two methods allow this Bean to have constrained properties. public void addVetoableChangeListener( VetoableChangeListener l ) { vetoAgent.addVetoableChangeListener( l );
}
public void removeVetoableChangeListener( VetoableChangeListener l ) { vetoAgent.removeVetoableChangeListener( l );
}
protected VetoableChangeSupport vetoAgent = new VetoableChangeSupport( this ); •
In the program the width property is bound and constrained
•
A property does not have to be bound to be constrained
•
To make the Width property constrained but not bound is to remove the line
changeAgent.firePropertyChange( "width", new Integer( oldWidth ), new Integer( newWidth ) ); Using Events to Communicate with Other Components • • The idea behind JavaBeans component model is to provide reusable components • The Beans must be able to communicate with other Beans and their container and this is accomplished by means of Listener interfaces. • Beans use the same event handling scheme as AWT that is if a Bean needs to hear about events coming from another Bean it must register itself with that Bean • A Bean can hear events coming from another Bean by implementing •
the Listener interface for the event of interest. If a Bean is no longer interested in hearing from another Bean then
12 it must unregister itself with that Bean. Any event that a Bean wants to fire must inherit from the class java.util.EventObject. • The event handling method of a Listener interface should follow the design pattern for Introspection as shown Void <EventOccuranceName> (<EventObjectType> evt); •
• • • •
The <EventObjectType> inherits from java.util.EventObject An event handler method can throw exceptions One Listener interface can have any number of related event handlers. There are two types of events that components can listen for and are Multicast events – there can be any number of listeners Unicast events – can have only one listener
Multicast Events • • • • •
Multicast events are the most common types of events The PropertyChangeEvent is a multicast event because there can be any number of listeners The addPropertyChangeListener() and removePropertyChangeListener() methods are used with components to register with a Bean when a bound property change the same is used with multicast events also
public synchronized void add ( < ListenerType> listener ); public synchronized void remove ( < ListenerType> listener ); Unicast Events • • • • •
Unicast events do not occur as often as multicast events Unicast events can have only one listener If more than one component attempt to listen to the unicast event a java.util.TooManyListenersException will be thrown
• • The following design pattern is used when declaring unicast events public synchronized void add ( < ListenerType> listener ) throws java.util. TooManyListenersException; public synchronized void remove ( listener); Introspection : Creating and Using BeanInfo Classes • •
Introspection is the most important aspect of JavaBeans because without it a container cannot do anything with a Bean other than display it The java.beans.Introspector class does all the pattern analysis to expose the properties, methods and events that a component has
13 •
The java.beans.Introspector class looks to see whether a BeanInfo class is defined for the Bean it is inspecting
•
If a BeanInfo class is found then the introspector does not do any pattern analysis on the areas of the Bean for which the BeanInfo
• • •
class supplies information As an example let us design a BeanInfo class for the TextDisplayer Bean The first thing is to define what information to provide and what to leave up to the Introspector class to analyze We provide the properties of the Beans and let the Introspector class use analysis to expose the events and methods
•
The following table shows the names of the TextDisplayer Bean’s properties and the user friendly names to be displayed
Property Name
User-friendly Name
OutputText
“Text String”
BGColor
“Background Color”
TextFont
“Text Font”
FontColor
“Text Color”
The TextDisplayer Bean’s Properties and User-Friendly Names • • • • •
The BeanInfo class is named TextDisplayerBeanInfo.class The Introspector class looks for BeanInfo information by appending BeanInfo to the class name of the Bean it is currently analyzing All BeanInfo classes must implement the java.beans.BeanInfo interface The Introspector class has a set procedure for the way it looks for information and they are 1. The Introspector class looks for a BeanInfo class for the Bean it is analyzing
2. If a BeanInfo class is present each method in the BeanInfo class is whether it can provide any information. The Introspector class will use implicit analysis to expose information for which the BeanInfo class denies any knowledge
called to find out
14 ( returns a null value). If no BeanInfo class is found the Introspector class will use implicit analysis for all the methods in the java.beans.BeanInfo interface 3. The Introspector class then checks to see whether it has obtained explicit information for each of the methods in the BeanInfo interface. If it has not it steps into the parent class ( if one exists) and starts the process over for only those methods that it had to use analysis on. 4.When the Introspector class has gotten information from a BeanInfo class for all the methods in the java.beans.BeanInfo interface or when there are no more parent classes to explore the Introspector class returns its results • • •
The Sun microsystems has provided a prebuilt class called java.beans.SimpleBeanInfo that returns a null value for all the BeanInfo methods The prebuilt class helps to inherit and override only the methods that is required The following is the BeanInfo class for the TextDisplayer Bean
import java.beans.*; public class TextDisplayerBeanInfo extends SimpleBeanInfo { // override the getPropertyDescriptors method to provide that info. public PropertyDescriptor[] getPropertyDescriptors() { PropertyDescriptor[] properties = new PropertyDescriptor[4]; try { properties[0] = new PropertyDescriptor( "Text String", BeanClass, "getOutputText", "setOutputText" ); properties[1] = new PropertyDescriptor(
15 "Text Color", BeanClass, "getFontColor", "setFontColor" ); properties[2] = new PropertyDescriptor( "Text Font", BeanClass, "getTextFont", "setTextFont" ); properties[3] = new PropertyDescriptor( "Background Color", BeanClass, "getBGColor", "setBGColor" ); } catch( IntrospectionException e ) { return( null ); // exit gracefully if we get an exception. } return( properties );
}
private Class BeanClass = TextDisplayer.class; } •
The getPropertyDescriptors() method is overriden in the program
•
The parent class returns null for all the other methods in the java.beans.BeanInfo interface.
•
If a java.beans.IntrospectionException is catch then it means an
incorrect getter or setter method name was given • If an IntrospectionException is catch a null value should be returned so that the Introspector class can still analyze the Bean. • The following figure shows the PropertySheet window of Sun’s BeanBox for the TextDisplayer Bean • The user friendly names have been used instead of the parent classes properties
16
Customization: Providing Custom PropertyEditors and GUI Interfaces • • • • •
• •
•
Properties of a Bean have a Property Editor In the Property window next to the Text String label there is a TextField AWT component already filled with the value of the OutputText property The value is not supplied by the user the BeanBox application asks the java.beans.PropertyEditorManager what the default PropertyEditor was for an object of type java.lang.String and displays it It is not a must that a Bean should have a GUI Environment as the PropertyEditor and Customizer needs eg. a Bean designed to run on a server does not need a GUI Environment The java.beans.Beans class and the java.beans.Visibility interface allows Beans to have different behavior in GUI and non-GUI Environments
PropertyEditors and the PropertyEditor Manager • • • • • • • •
Java.beans.PropertyEditorManager provides default PropertyEditors for majority of Java classes For a custom property type there is no default PropertyEditor so the designer should provide his own PropertyEditor This can be done by providing an additional class by appending Editor to the class name that the PropertyEditorManager can use The requirements of a PropertyEditor are as follows 1. Custom PropertyEditors must inherit from java.awt.Component so that they can be displayed in a property sheet eg. Inheriting from an AWT component like java.awt.TextField
2. Custom PropertyEditors must derive their class name by postfixing Editor to the property class name unless they register themselves with the PropertyEditorManager eg.The PropertyEditor for a custom property type CustomProperty.class must be named CustomPropertyEditor.class 3. The custom PropertyEditors that do not follow the standard naming convention must register itself with the containers PropertyEditorManager by calling the registerEditor() method 4. Custom PropertyEditors must always fire a PropertyChange event
17 to update the custom property otherwise the container has no way of knowing to update the component
Customization Editor •
All application builders have to implement some method of customizing the Beans
. Bean developers can optionally supply customizer classes with their Beans to be used in place of standard property sheets • • To implement a customizer class a Bean must also provide a BeanInfo class • • The class name of a Bean’s customizer class is determined from a call to the getBeanDescriptor() method of the java.beans.BeanInfo interface • • The following is the TextReaderBeanInfo.java program where the BeanInfo class for the TextReader Bean shows how to provide Customizer class information import java.beans.*; public class TextReaderBeanInfo extends SimpleBeanInfo { // override the getBeanDescriptor method to provide a customizer. public BeanDescriptor getBeanDescriptor() { return( new BeanDescriptor( BeanClass, CustomizerClass ) ); } private Class BeanClass = TextReader.class; private Class CustomizerClass = TextReaderCustomizer.class; } The TextReaderBeanInfo inherits from java.beans.SimpleBeanInfo • • The getBeanDescriptor() method is overriden • • The customizer class is postfixed with the keyword Customizer eg. The TextReader customizer is named TextReaderCustomizer.class • • When designing customizer classes there are two restrictions 1. The customizer class must inherit from java.awt.Component so that it can be placed in a Panel or Dialog
18 2. The customizer class must implement the java.beans.Customizer interface •
The customizer class is given a reference to the target component through a call to the setObject() method • The java.beans.Customizer interface includes functionality for PropertyChangeListeners because the Beans container may register itself as a listener with the customizer class • • The property updates should be followed by a call to firePropertyChange() using the java.beans.PropertyChangeSupport class • • The following is the TextReaderCustomizer class public class TextReaderCustomizer extends Panel implements Customizer { public TextReaderCustomizer() { setLayout( new BorderLayout() );
}
public void setObject( Object target ) { component = (TextReader)target; // generate the User Interface } public boolean handleEvent( Event event ) { if ( event.id == Event.KEY_RELEASE && event.target == InputText ) { String old_text = component.getInputText(); String text = InputText.getText(); component.setInputText( text ); changeAgent.firePropertyChange( "inputText", old_text, text ); } else if ( event.id == Event.KEY_RELEASE && event.target == Width ) { int old_width, width; old_width = component.getWidth();
19 try { width = Integer.parseInt( Width.getText() ); try { component.setWidth( width ); changeAgent.firePropertyChange( "width", new Integer ( old_width ), new Integer( width ) } catch( PropertyVetoException e ) { // wait for acceptable data. } } catch( NumberFormatException e ) { // wait for better data. } } return ( super.handleEvent( event ) ); } public void addPropertyChangeListener( PropertyChangeListener l ) { changeAgent.addPropertyChangeListener( l );
}
public void removePropertyChangeListener(PropertyChangeListener l) {
changeAgent.removePropertyChangeListener( l ); } private TextReader component; private TextField InputText, Width; private PropertyChangeSupport changeAgent = new PropertyChangeSupport( this );
}
The handleEvent() method is called by AWT when the user enters data
20 Providing Alternative Behavior in Non-GUI Environments • A GUI interface is not always available to a Bean especially when the Bean is being run in the background or on a server •
Beans that need GUI in non-GUI environments can use the java.beans.Beans class and java.beans.Visibility interface
•
The static method isGuiAvailable() in the java.beans.Beans class can be used to check whether a GUI environment is available
•
The method isGuiAvailable() returns true if a GUI environment is
•
available to the Bean and false A Bean and its container can communicate about the GUI environment by implementing the java.beans.Visibility interface
•
There are four methods in java.beans.Visibility interface and they are 1. public abstract boolean avoidingGui() 2. public abstract void dontUseGui() 3. public abstract boolean needsGui() 4. public abstract void okToUseGui()
public abstract boolean avoidingGui() •
The avoidingGui() method is called by the container to check if a Bean is currently avoiding the GUI environment
•
A Bean will return true for this method if it is actively avoiding the GUI environment
•
Avoiding the GUI is different from needing the GUI
•
The container can use this information to free up resources being used by the GUI environment if a call to this method returns true
public abstract void dontUseGui() •
The method is used by the container to tell the Bean that even though
21 a GUI environment is available the Bean should not use it A container using a Bean on a server can call this method to tell the Bean that there is no point in using the GUI environment public abstract boolean needsGui() •
The method is called by the container to ask whether a bean needs a GUI environment
•
If a Bean can function in a non-GUI environment it will return false
•
It is safe to return true and then never use the GUI environment rather than returning false and using it
public abstract void okToUseGui() •
The method is used by the container to tell a Bean that a GUI environment is available and the Bean can use it
•
This method might also be called after dontUseGui() to indicate that a previously unavailable GUI environment is available again
•
A call to okToUseGui() method do not implies that a Bean should use the GUI environment if it was not planning to