75
JavaBeans Concepts Using the NetBeans GUI Builder Writing a Simple Bean Properties Simple Properties Bound Properties Constrained Properties Indexed Properties Manipulating Events Bean Persistence Long Term Persistence Introspection Bean Customization Using the BeanContext API Overview of the BeanContext API Bean Context #1: Containment Only Bean Context #2: Containment and Services AWT Containers and the BeanContextProxy Interface

Notes on JavaBeans

Embed Size (px)

DESCRIPTION

lecture notes on java beans

Citation preview

Page 1: Notes on JavaBeans

JavaBeans Concepts

Using the NetBeans GUI Builder

Writing a Simple Bean

Properties

Simple Properties

Bound Properties

Constrained Properties

Indexed Properties

Manipulating Events

Bean Persistence

Long Term Persistence

Introspection

Bean Customization

Using the BeanContext API

Overview of the BeanContext API

Bean Context 1 Containment Only

Bean Context 2 Containment and Services

AWT Containers and the BeanContextProxy Interface

The JavaBeanstrade architecture is based on a component model which enables developers to create software units called components Components are self-contained reusable software units that can be visually assembled into composite components applets applications and servlets using visual application builder tools JavaBean components are known as beans

A set of APIs describes a component model for a particular language The JavaBeans API specificationdescribes the core detailed elaboration for the JavaBeans component architecture

Beans are dynamic in that they can be changed or customized Through the design mode of a builder tool you can use the Properties window of the bean to customize the bean and then save (persist) your beans using visual manipulation You can select a bean from the toolbox drop it into a form modify its appearance and behavior define its interaction with other beans and combine it and other beans into an applet application or a new bean

The following list briefly describes key bean concepts

Builder tools discover a beans features (that is its properties methods and events) by a process known as introspection Beans support introspection in two ways

o By adhering to specific rules known as design patterns when naming bean features The Introspector class examines beans for these design patterns to discover bean features The Introspector class relies on the core reflection API The trail The Reflection API is an excellent place to learn about reflection

o By explicitly providing property method and event information with a related bean information class A bean information class implements the BeanInfo interface A BeanInfo class explicitly lists those bean features that are to be exposed to application builder tools

Properties are the appearance and behavior characteristics of a bean that can be changed at design time Builder tools introspect on a bean to discover its properties and expose those properties for manipulation

Beans expose properties so they can be customized at design time Customization is supported in two ways by using property editors or by using more sophisticated bean customizers

Beans use events to communicate with other beans A bean that is to receive events (a listener bean) registers with the bean that fires the event (a source bean) Builder tools can examine a bean and determine which events that bean can fire (send) and which it can handle (receive)

Persistence enables beans to save and restore their state After changing a beans properties you can save the state of the bean and restore that bean at a later time

with the property changes intact The JavaBeans architecture uses Java Object Serialization to support persistence

A beans methods are no different from Java methods and can be called from other beans or a scripting environment By default all public methods are exported

Beans vary in functionality and purpose You have probably met some of the following beans in your programming practice

GUI (graphical user interface) Non-visual beans such as a spelling checker Animation applet Spreadsheet application

Lesson Using the NetBeans GUI Builderhis lesson explains how to use the NetBeans IDE GUI Builder to work with beans In preparation for working with the GUI Builder you should be first familiar with the key NetBeans concepts which are explained in the NetBeans IDE Java Quick Start Tutorial

This lesson guides you through the process of creating a bean pattern in the NetBeans projects introduces the user interface of the GUI Builder and explains how to add your bean object to the palette

Creating a New Project

In the NetBeans IDE you always work in a project where you store sources and files To create a new project perform the following steps

1 Select New Project from the File menu You can also click the New Project button in the IDE toolbar

2 In the Categories pane select the General node In the Projects pane choose the Java Application type Click the Next button

3 Enter MyBean in the Project Name field and specify the project location Do not create a Main class here because later you will create a new Java class in this project

4 Click the Finish button

This figure represents the expanded MyBean node in the Projects list

Creating a New Form

After creating a new project the next step is to create a form within which the JavaBeans components and other required GUI components will be placed

To create a new form perform the following sequence of actions

1 In the Projects list expand the MyBean node right-click on the ltdefault packagegt node and choose New|JFrame Form from the pop-up menu

2 Enter MyForm as the Class Name3 Click the Finish button

The IDE creates the MyForm form and the MyForm class within the MyBean application and opens the MyForm form in the GUI Builder

This figure represents the Projects list where the MyForm class is located

The GUI Builder Interface

When the JFrame form is added to your application the IDE opens the newly-created form in an Editor tab with a toolbar containing the following buttons

ndash Selection Mode enables you to select one or more objects in the Design Area

ndash Connection Mode enables you to set a connection between objects by specifying an event

ndash Preview Design enables you to preview the form layout

ndash Align commands enable you to align selected objects

ndash Change Resizability enables you to set up vertical and horizontal resizing

When the MyForm form opens in the GUI Builders Design view three additional windows appear enabling you to navigate organize and edit GUI forms These windows include the following

Design Area The primary window for creating and editing Java GUI forms Source and Design toggle buttons enable you to switch between view a classs source code and a graphical view of the GUI components Click on an object to select it in the Design Area For a multiple selection hold down the Ctrl key while clicking on objects

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 2: Notes on JavaBeans

The JavaBeanstrade architecture is based on a component model which enables developers to create software units called components Components are self-contained reusable software units that can be visually assembled into composite components applets applications and servlets using visual application builder tools JavaBean components are known as beans

A set of APIs describes a component model for a particular language The JavaBeans API specificationdescribes the core detailed elaboration for the JavaBeans component architecture

Beans are dynamic in that they can be changed or customized Through the design mode of a builder tool you can use the Properties window of the bean to customize the bean and then save (persist) your beans using visual manipulation You can select a bean from the toolbox drop it into a form modify its appearance and behavior define its interaction with other beans and combine it and other beans into an applet application or a new bean

The following list briefly describes key bean concepts

Builder tools discover a beans features (that is its properties methods and events) by a process known as introspection Beans support introspection in two ways

o By adhering to specific rules known as design patterns when naming bean features The Introspector class examines beans for these design patterns to discover bean features The Introspector class relies on the core reflection API The trail The Reflection API is an excellent place to learn about reflection

o By explicitly providing property method and event information with a related bean information class A bean information class implements the BeanInfo interface A BeanInfo class explicitly lists those bean features that are to be exposed to application builder tools

Properties are the appearance and behavior characteristics of a bean that can be changed at design time Builder tools introspect on a bean to discover its properties and expose those properties for manipulation

Beans expose properties so they can be customized at design time Customization is supported in two ways by using property editors or by using more sophisticated bean customizers

Beans use events to communicate with other beans A bean that is to receive events (a listener bean) registers with the bean that fires the event (a source bean) Builder tools can examine a bean and determine which events that bean can fire (send) and which it can handle (receive)

Persistence enables beans to save and restore their state After changing a beans properties you can save the state of the bean and restore that bean at a later time

with the property changes intact The JavaBeans architecture uses Java Object Serialization to support persistence

A beans methods are no different from Java methods and can be called from other beans or a scripting environment By default all public methods are exported

Beans vary in functionality and purpose You have probably met some of the following beans in your programming practice

GUI (graphical user interface) Non-visual beans such as a spelling checker Animation applet Spreadsheet application

Lesson Using the NetBeans GUI Builderhis lesson explains how to use the NetBeans IDE GUI Builder to work with beans In preparation for working with the GUI Builder you should be first familiar with the key NetBeans concepts which are explained in the NetBeans IDE Java Quick Start Tutorial

This lesson guides you through the process of creating a bean pattern in the NetBeans projects introduces the user interface of the GUI Builder and explains how to add your bean object to the palette

Creating a New Project

In the NetBeans IDE you always work in a project where you store sources and files To create a new project perform the following steps

1 Select New Project from the File menu You can also click the New Project button in the IDE toolbar

2 In the Categories pane select the General node In the Projects pane choose the Java Application type Click the Next button

3 Enter MyBean in the Project Name field and specify the project location Do not create a Main class here because later you will create a new Java class in this project

4 Click the Finish button

This figure represents the expanded MyBean node in the Projects list

Creating a New Form

After creating a new project the next step is to create a form within which the JavaBeans components and other required GUI components will be placed

To create a new form perform the following sequence of actions

1 In the Projects list expand the MyBean node right-click on the ltdefault packagegt node and choose New|JFrame Form from the pop-up menu

2 Enter MyForm as the Class Name3 Click the Finish button

The IDE creates the MyForm form and the MyForm class within the MyBean application and opens the MyForm form in the GUI Builder

This figure represents the Projects list where the MyForm class is located

The GUI Builder Interface

When the JFrame form is added to your application the IDE opens the newly-created form in an Editor tab with a toolbar containing the following buttons

ndash Selection Mode enables you to select one or more objects in the Design Area

ndash Connection Mode enables you to set a connection between objects by specifying an event

ndash Preview Design enables you to preview the form layout

ndash Align commands enable you to align selected objects

ndash Change Resizability enables you to set up vertical and horizontal resizing

When the MyForm form opens in the GUI Builders Design view three additional windows appear enabling you to navigate organize and edit GUI forms These windows include the following

Design Area The primary window for creating and editing Java GUI forms Source and Design toggle buttons enable you to switch between view a classs source code and a graphical view of the GUI components Click on an object to select it in the Design Area For a multiple selection hold down the Ctrl key while clicking on objects

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 3: Notes on JavaBeans

with the property changes intact The JavaBeans architecture uses Java Object Serialization to support persistence

A beans methods are no different from Java methods and can be called from other beans or a scripting environment By default all public methods are exported

Beans vary in functionality and purpose You have probably met some of the following beans in your programming practice

GUI (graphical user interface) Non-visual beans such as a spelling checker Animation applet Spreadsheet application

Lesson Using the NetBeans GUI Builderhis lesson explains how to use the NetBeans IDE GUI Builder to work with beans In preparation for working with the GUI Builder you should be first familiar with the key NetBeans concepts which are explained in the NetBeans IDE Java Quick Start Tutorial

This lesson guides you through the process of creating a bean pattern in the NetBeans projects introduces the user interface of the GUI Builder and explains how to add your bean object to the palette

Creating a New Project

In the NetBeans IDE you always work in a project where you store sources and files To create a new project perform the following steps

1 Select New Project from the File menu You can also click the New Project button in the IDE toolbar

2 In the Categories pane select the General node In the Projects pane choose the Java Application type Click the Next button

3 Enter MyBean in the Project Name field and specify the project location Do not create a Main class here because later you will create a new Java class in this project

4 Click the Finish button

This figure represents the expanded MyBean node in the Projects list

Creating a New Form

After creating a new project the next step is to create a form within which the JavaBeans components and other required GUI components will be placed

To create a new form perform the following sequence of actions

1 In the Projects list expand the MyBean node right-click on the ltdefault packagegt node and choose New|JFrame Form from the pop-up menu

2 Enter MyForm as the Class Name3 Click the Finish button

The IDE creates the MyForm form and the MyForm class within the MyBean application and opens the MyForm form in the GUI Builder

This figure represents the Projects list where the MyForm class is located

The GUI Builder Interface

When the JFrame form is added to your application the IDE opens the newly-created form in an Editor tab with a toolbar containing the following buttons

ndash Selection Mode enables you to select one or more objects in the Design Area

ndash Connection Mode enables you to set a connection between objects by specifying an event

ndash Preview Design enables you to preview the form layout

ndash Align commands enable you to align selected objects

ndash Change Resizability enables you to set up vertical and horizontal resizing

When the MyForm form opens in the GUI Builders Design view three additional windows appear enabling you to navigate organize and edit GUI forms These windows include the following

Design Area The primary window for creating and editing Java GUI forms Source and Design toggle buttons enable you to switch between view a classs source code and a graphical view of the GUI components Click on an object to select it in the Design Area For a multiple selection hold down the Ctrl key while clicking on objects

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 4: Notes on JavaBeans

Creating a New Form

After creating a new project the next step is to create a form within which the JavaBeans components and other required GUI components will be placed

To create a new form perform the following sequence of actions

1 In the Projects list expand the MyBean node right-click on the ltdefault packagegt node and choose New|JFrame Form from the pop-up menu

2 Enter MyForm as the Class Name3 Click the Finish button

The IDE creates the MyForm form and the MyForm class within the MyBean application and opens the MyForm form in the GUI Builder

This figure represents the Projects list where the MyForm class is located

The GUI Builder Interface

When the JFrame form is added to your application the IDE opens the newly-created form in an Editor tab with a toolbar containing the following buttons

ndash Selection Mode enables you to select one or more objects in the Design Area

ndash Connection Mode enables you to set a connection between objects by specifying an event

ndash Preview Design enables you to preview the form layout

ndash Align commands enable you to align selected objects

ndash Change Resizability enables you to set up vertical and horizontal resizing

When the MyForm form opens in the GUI Builders Design view three additional windows appear enabling you to navigate organize and edit GUI forms These windows include the following

Design Area The primary window for creating and editing Java GUI forms Source and Design toggle buttons enable you to switch between view a classs source code and a graphical view of the GUI components Click on an object to select it in the Design Area For a multiple selection hold down the Ctrl key while clicking on objects

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 5: Notes on JavaBeans

The GUI Builder Interface

When the JFrame form is added to your application the IDE opens the newly-created form in an Editor tab with a toolbar containing the following buttons

ndash Selection Mode enables you to select one or more objects in the Design Area

ndash Connection Mode enables you to set a connection between objects by specifying an event

ndash Preview Design enables you to preview the form layout

ndash Align commands enable you to align selected objects

ndash Change Resizability enables you to set up vertical and horizontal resizing

When the MyForm form opens in the GUI Builders Design view three additional windows appear enabling you to navigate organize and edit GUI forms These windows include the following

Design Area The primary window for creating and editing Java GUI forms Source and Design toggle buttons enable you to switch between view a classs source code and a graphical view of the GUI components Click on an object to select it in the Design Area For a multiple selection hold down the Ctrl key while clicking on objects

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 6: Notes on JavaBeans

Inspector Representation of a tree hierarchy of all the components in your application The Inspector highlights the component in the tree that is currently being edited

Palette A customizable list of available components containing groups for Swing AWT Borders and Beans components This window enables you to create remove and rearrange the categories displayed in the palette using the customizer

Properties Window A display of the properties of the component currently selected in the GUI Builder Inspector window Projects window or Files window

If you click the Source button the IDE displays the applications Java source code in the editor Sections of code that are automatically generated by the GUI Builder are indicated by blue areas These blue areas are protected from editing in the Source view You can only edit code appearing in the white areas of the editor when in Source view When you make your changes in the Design View the IDE updates the files sources

Creating a Bean

To create your own bean object and add it to the palette for the bean group execute the following procedure

1 Select the ltdefault packagegt node in the MyBean project2 Choose New|Java Class from the pop-up menu3 Specify the name for the new class for example MyBean then press the Finish

button4 Open the MyBeanjava file 5 In the editor window select inside the class Right-click and choose Insert Code

Then select Add Property 6 In the Name field of the Add Property dialog box type YourName and press OK

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 7: Notes on JavaBeans

7 Now you can analyze the automatically generated code Notice that set and get methods were included

public class MyBean Creates a new instance of MyBean public MyBean()

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 8: Notes on JavaBeans

Holds value of property yourName private String yourName

Getter for property yourName return Value of property yourName public String getYourName() return thisyourName

Setter for property yourName param yourName New value of property yourName public void setYourName(String yourName) thisyourName = yourName

8 Right-click the MyBean node in the MyBean project tree and choose Tools |Add to Palette from the pop-up menu

9 Select the Beans group in the Palette tree to add your bean

Now you can switch to the Palette window by choosing Palette from the Windows menu and make sure that the MyBean component was added to the Beans group

So far you have created a bean set the YourName property and added this bean as a component to the palette

Adding Components to the Form

Now you can use the Free Design of the GUI Builder and add the MyBean component and other standard Swing components to MyForm

1 Select the MyForm node in the project tree2 Drag the JLabel Swing component from the Palette window to the Design Area

Double-click the component and change the text property to Enter your name3 Drag the JTextField component from the Palette window to the Design Area

Double-click the component and empty the text field4 Drag the JButton component from the Palette window to the Design Area

Double-click the component and enter OK as the text property5 Add another button and enter Cancel as its text property6 Align components by using the appropriate align commands 7 Before you drag the MyBean component from the Pallete you must compile your

project because the MyBean component is non-visual and cannot be operated as a visual component When you Drag and Drop the MyBean component it will not appear in the Design Area However you can view it in the Inspector window by expanding the Other Components node as shown in the following figure

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 9: Notes on JavaBeans

8

To summarize in the previous steps you created a project developed a JFrame form added a bean object and included it in your project as a non-visual component Later in this trail you will learn how to change properties for the bean component and handle events by using the NetBeans GUI Builder

In this section you will learn more about beans by performing the following actions

Creating a simple bean Compiling the bean Generating a Java Archive (JAR) file Loading the bean into the GUI Builder of the NetBeans IDE Inspecting the beans properties and events

Your bean will be named SimpleBean Here are the steps to create it

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 10: Notes on JavaBeans

1 Write the SimpleBean code Put it in a file named SimpleBeanjava in the directory of your choice Heres the code

2 import javaawtColor3 import javabeansXMLDecoder4 import javaxswingJLabel5 import javaioSerializable67 public class SimpleBean extends JLabel 8 implements Serializable 9 public SimpleBean() 10 setText( Hello world )11 setOpaque( true )12 setBackground( ColorRED )13 setForeground( ColorYELLOW )14 setVerticalAlignment( CENTER )15 setHorizontalAlignment( CENTER )16 17

SimpleBean extends the javaxswingJLabel graphic component and inherits its properties which makes the SimpleBean a visual component SimpleBean also implements the javaioSerializable interface Your bean may implement either the Serializable or the Externalizable interface

18 Create a manifest the JAR file and the class file SimpleBeanclass Use the Apache Ant tool to create these files Apache Ant is a Java-based build tool that enables you to generate XML-based configurations files as follows

19 ltxml version=10 encoding=ISO-8859-1gt2021 ltproject default=buildgt2223 ltdirname property=basedir file=$antfilegt2425 ltproperty name=beanname value=SimpleBeangt26 ltproperty name=jarfile value=$basedir$beannamejargt2728 lttarget name=build depends=compilegt29 ltjar destfile=$jarfile basedir=$basedir

includes=classgt30 ltmanifestgt31 ltsection name=$beannameclassgt32 ltattribute name=Java-Bean value=truegt33 ltsectiongt34 ltmanifestgt35 ltjargt36 lttargetgt3738 lttarget name=compilegt39 ltjavac destdir=$basedirgt40 ltsrc location=$basedirgt41 ltjavacgt42 lttargetgt4344 lttarget name=cleangt

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 11: Notes on JavaBeans

45 ltdelete file=$jarfilegt46 ltfileset dir=$basedir includes=classgt47 ltdeletegt48 lttargetgt4950 ltprojectgt

It is recommended to save an XML script in the buildxml file because Ant recognizes this file name automatically

51 Load the JAR file Use the NetBeans IDE GUI Builder to load the jar file as follows

1 Start NetBeans 2 From the File menu select New Project to create a new application for

your bean You can use Open Project to add your bean to an existing application

3 Create a new application using the New Project Wizard 4 Select a newly created project in the List of Projects expand the Source

Packages node and select the Default Package element 5 Click the right mouse button and select New|JFrameForm from the pop-up

menu 6 Select the newly created Form node in the Project Tree A blank form

opens in the GUI Builder view of an Editor tab 7 Open the Palette Manager for SwingAWT components by selecting

Palette Manager in the Tools menu 8 In the Palette Manager window select the beans components in the Palette

tree and press the Add from JAR button 9 Specify a location for your SimpleBean JAR file and follow the Add from

JAR Wizard instructions 10 Select the Palette and Properties options from the Windows menu 11 Expand the beans group in the Palette window The SimpleBean object

appears Drag the SimpleBean object to the GUI Builder panel

The following figure represents the SimpleBean object loaded in the GUI Builder panel

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 12: Notes on JavaBeans

52 Inspect Properties and Events The SimpleBean properties will appear in the Properties window For example you can change a background property by selecting another color To preview your form use the Preview Design button of the GUI Builder toolbar To inspect events associated with the SimpleBean object switch to the Events tab of the Properties window You will learn more about bean properties and events in the lessons that follow

Lesson Properties

In the following sections you will learn how to implement bean properties A bean property is a named attribute of a bean that can affect its behavior or appearance Examples of bean properties include color label font font size and display size

The JavaBeanstrade specification defines the following types of bean properties

Simple ndash A bean property with a single value whose changes are independent of changes in any other property

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 13: Notes on JavaBeans

Indexed ndash A bean property that supports a range of values instead of a single value

Bound ndash A bean property for which a change to the property results in a notification being sent to some other bean

Constrained ndash A bean property for which a change to the property results in validation by another bean The other bean may reject the change if it is not appropriate

Bean properties can also be classified as follows

Writable ndash A bean property that can be changed o Standard o Expert o Preferred

Read Only ndash A bean property that cannot be changed Hidden ndash A bean property that can be changed However these properties are not

disclosed with the BeanInfo class

BeanBuilder uses this schema to group and represent properties in the Properties window

Simple Properties

To add simple properties to a bean add appropriate getXXX and setXXX methods (or isXXX and setXXX methods for a boolean property)

The names of these methods follow specific rules called design patterns These design pattern-based method names allow builder tools such as the NetBeans GUI Builder to provide the following features

Discover a beans properties Determine the properties readwrite attributes Determine the properties types Locate the appropriate property editor for each property type Display the properties (usually in the Properties window) Alter the properties (at design time)

Adding a Title Property

In previous lessons you learned how to create a simple property by using the NetBeans GUI Builder The following procedure shows how to create a simple property in detail

1 Right-click on the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill out the New Property Pattern form as shown in the following figure and click

OK

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 14: Notes on JavaBeans

4 The following code is automatically generated 5 public class MyBean 6 7 Creates a new instance of MyBean 8 public MyBean() 9 1011 12 Holds value of property title13 14 private String title1516 17 Getter for property title18 return Value of property title19 20 public String getTitle() 21 return thistitle22 2324 25 Setter for property title26 param title New value of property title27 28 public void setTitle(String title) 29 thistitle = title30 31 32

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 15: Notes on JavaBeans

33 Now make your bean visual by extending the JComponent class and implement the Serializable interface Then add the paintComponent method to represent your bean

34 import javaawtGraphics35 import javaioSerializable36 import javaxswingJComponent3738 39 Bean with a simple property title40 41 public class MyBean42 extends JComponent43 implements Serializable44 45 private String title4647 public String getTitle()48 49 return thistitle50 5152 public void setTitle( String title )53 54 thistitle = title55 5657 protected void paintComponent( Graphics g )58 59 gsetColor( getForeground() )6061 int height = ggetFontMetrics()getHeight()62 if ( thistitle = null )63 gdrawString(thistitle 0 height )64 65

Inspecting Properties

Select the MyBean component in the Other Components node in the Inspector window Now you can analyze the title property in the Properties window and change it To change the title property press the button and enter any string you wish

The following figure represents the title property set to the The title value

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 16: Notes on JavaBeans

The NetBeans GUI Builder enables you to restrict the changing of a property value To restrict the changing of the title property right-click the title property in the Bean Patterns node of the MyBean project Select Properties from the pop-up menu and the Properties window appears Choose one of the following property access types from the Mode combo box

ReadWrite Read only Write only

The Read only property has only the get method only while the Write only property has only the set method only The ReadWrite type property has both of these methods

Bound Properties

Bound properties support the PropertyChangeListener (in the API reference documentation) class

Sometimes when a Bean property changes another object might need to be notified of the change and react to the change

Whenever a bound property changes notification of the change is sent to interested listeners

The accessor methods for a bound property are defined in the same way as those for simple properties However you also need to provide the event listener registration methods forPropertyChangeListener classes and fire a PropertyChangeEvent (in the

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 17: Notes on JavaBeans

API reference documentation) event to the PropertyChangeListener objects by calling their propertyChange methods

The convenience PropertyChangeSupport (in the API reference documentation) class enables your bean to implement these methods Your bean can inherit changes from the PropertyChangeSupportclass or use it as an inner class

In order to listen for property changes an object must be able to add and remove itself from the listener list on the bean containing the bound property It must also be able to respond to the event notification method that signals a property change

The PropertyChangeEvent class encapsulates property change information and is sent from the property change event source to each object in the property change listener list with the propertyChange method

Implementing Bound Property Support Within a Bean

To implement a bound property in your application follow these steps 1 Import the javabeans package This gives you access to the

PropertyChangeSupport class2 Instantiate a PropertyChangeSupport object This object maintains the property

change listener list and fires property change events You can also make your class a PropertyChangeSupport subclass

3 Implement methods to maintain the property change listener list Since a PropertyChangeSupport subclass implements these methods you merely wrap calls to the property-change support objects methods

4 Modify a propertys set method to fire a property change event when the property is changed

Creating a Bound Property

To create the title property as a bound property for the MyBean component in the NetBeans GUI Builder perform the following sequence of operations

1 Right-click the Bean Patterns node in the MyBean class hierarchy 2 Select Add|Property from the pop-up menu 3 Fill the New Property Pattern form as shown on the following figure and click

OK

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 18: Notes on JavaBeans

4 Note that the title property and the multicast event source pattern PropertyChangeListener were added to the Bean Patterns structure

You can also modify existing code generated in the previous lesson to convert the title and lines properties to the bound type as follows (where newly added code is shown in bold)

import javaawtGraphicsimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javaioSerializableimport javaxswingJComponent

Bean with bound properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this )

public String getTitle() return thistitle

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 19: Notes on JavaBeans

public void setTitle( String title ) String old = thistitle thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) String[] old = thislines thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) String old = thislines[index] thislines[index] = line thispcsfireIndexedPropertyChange( lines index old lines )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines )

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 20: Notes on JavaBeans

paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Constrained PropertiesA bean property is constrained if the bean supports the VetoableChangeListener(in the API reference documentation) and PropertyChangeEvent(in the API reference documentation) classes and if the set method for this property throws a PropertyVetoException(in the API reference documentation)

Constrained properties are more complicated than bound properties because they also support property change listeners which happen to be vetoers

The following operations in the setXXX method for the constrained property must be implemented in this order

1 Save the old value in case the change is vetoed2 Notify listeners of the new proposed value allowing them to veto the change3 If no listener vetoes the change (no exception is thrown) set the property to the

new value

The accessor methods for a constrained property are defined in the same way as those for simple properties with the addition that the setXXX method throws a PropertyVetoException exception The syntax is as follows

public void setPropertyName(PropertyType pt)throws PropertyVetoException code

Handling Vetoes

If a registered listener vetoes a proposed property change by throwing a PropertyVetoException exception the source bean with the constrained property is responsible for the following actions

Catching exceptions Reverting to the old value for the property

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 21: Notes on JavaBeans

Issuing a new VetoableChangeListenervetoableChange call to all listeners to report the reversion

The VetoableChangeListener class throws a PropertyVetoException and handles the PropertyChangeEvent event fired by the bean with the constrained property

The VetoableChangeSupport provides the following operations

Keeping track of VetoableChangeListener objects Issuing the vetoableChange method on all registered listeners Catching any vetoes (exceptions) thrown by listeners Informing all listeners of a veto by calling vetoableChange again but with the

old property value as the proposed new value

Creating a Constrained Property

To create a constrained property set the appropriate option in the New Property Pattern form as shown on the following figure

Note that the Multicast Source Event Pattern - vetoableChangeListener was added to the Bean Patterns hierarchy

You can also modify the existing code generated in the previous lesson to make the title and lines properties constrained as follows (where newly added code is shown in bold)

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 22: Notes on JavaBeans

import javaioSerializableimport javabeansPropertyChangeListenerimport javabeansPropertyChangeSupportimport javabeansPropertyVetoExceptionimport javabeansVetoableChangeListenerimport javabeansVetoableChangeSupportimport javaawtGraphicsimport javaxswingJComponent

Bean with constrained properties public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

private final PropertyChangeSupport pcs = new PropertyChangeSupport( this ) private final VetoableChangeSupport vcs = new VetoableChangeSupport( this )

public String getTitle() return thistitle This method was modified to throw the PropertyVetoException if some vetoable listeners reject the new title value public void setTitle( String title ) throws PropertyVetoException String old = thistitle thisvcsfireVetoableChange( title old title ) thistitle = title thispcsfirePropertyChange( title old title )

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index] This method throws the PropertyVetoException if some vetoable listeners reject the new lines value public void setLines( String[] lines ) throws PropertyVetoException

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 23: Notes on JavaBeans

String[] old = thislines thisvcsfireVetoableChange( lines old lines ) thislines = lines thispcsfirePropertyChange( lines old lines )

public void setLines( int index String line ) throws PropertyVetoException String old = thislines[index] thisvcsfireVetoableChange( lines old line ) thislines[index] = line thispcsfireIndexedPropertyChange( lines index old line )

public void addPropertyChangeListener( PropertyChangeListener listener ) thispcsaddPropertyChangeListener( listener )

public void removePropertyChangeListener( PropertyChangeListener listener ) thispcsremovePropertyChangeListener( listener ) Registration of the VetoableChangeListener public void addVetoableChangeListener( VetoableChangeListener listener ) thisvcsaddVetoableChangeListener( listener )

public void removeVetoableChangeListener( VetoableChangeListener listener ) thisvcsremoveVetoableChangeListener( listener )

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 24: Notes on JavaBeans

private void paintString( Graphics g String str int height ) if ( str = null ) gdrawString( str 0 height )

Indexed Properties

An indexed property is an array of properties or objects that supports a range of values and enables the accessor to specify an element of a property to read or write

Indexed properties are specified by the following methods

Methods to access individual values public PropertyElement getPropertyName(int index)

public void setPropertyName(int index PropertyElement element)

and Methods to access the entire indexed property array

public PropertyElement[] getPropertyName()public void setPropertyName(PropertyElement element[])

Note that the distinction between the get and set methods for indexed properties is subtle The get method either has an argument that is the array index of the property or returns an array The set method either has two arguments namely an integer array index and the property element object that is being set or has the entire array as an argument

Creating an Indexed Property

To create an indexed property for your MyBean component right-click the Bean Patterns node and select Add|Indexed Property from the pop-up menu Set up Non-Index Options as shown in the following figure

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 25: Notes on JavaBeans

The code in the Source window will be changed automatically as follows

import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with simple property title public class MyBean extends JComponent implements Serializable private String title

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 26: Notes on JavaBeans

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() if ( thistitle = null ) gdrawString(thistitle 0 height )

Holds value of property lines private String[] lines

Indexed getter for property lines param index Index of the property return Value of the property at index public String getLines(int index) return thislines[index]

Getter for property lines return Value of property lines public String[] getLines() return thislines

Indexed setter for property lines param index Index of the property param lines New value of the property at index public void setLines(int index String lines) thislines[index] = lines

Setter for property lines param lines New value of property lines public void setLines(String[] lines) thislines = lines

Add the following code to the MyBeanjava component to present the user with a list of choices You can provide and change these choices at design time (Newly added code is shown in bold) import javaawtGraphicsimport javaioSerializableimport javaxswingJComponent

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 27: Notes on JavaBeans

Bean with a simple property title and an indexed property lines public class MyBean extends JComponent implements Serializable private String title private String[] lines = new String[10]

public String getTitle() return thistitle

public void setTitle( String title ) thistitle = title

public String[] getLines() return thislinesclone()

public String getLines( int index ) return thislines[index]

public void setLines( String[] lines ) thislines = lines

public void setLines( int index String line ) thislines[index] = line

protected void paintComponent( Graphics g ) gsetColor( getForeground() )

int height = ggetFontMetrics()getHeight() paintString( g thistitle height )

if ( thislines = null ) int step = height for ( String line thislines ) paintString( g line height += step )

private void paintString( Graphics g String str int height )

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 28: Notes on JavaBeans

if ( str = null ) gdrawString( str 0 height )

The following figure represents the lines property in the Properties window

Notice that this property has a null value To set up an alternative value press the button The form shown in the following figure enables you to add ten items for the lines property list First remove the default null items Then add custom items to the list by entering each item value into the Item field and pressing the Add button each time

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 29: Notes on JavaBeans

Lesson Manipulating Events

Event passing is the means by which components communicate with each other Components broadcast events and the underlying framework delivers the events to the components that are to be notified The notified components usually perform some action based on the event that took place

The event model was designed to accommodate the JavaBeanstrade architecture To understand how events and event handling work in the JavaBeans component model you must understand the concepts of events listeners and sources To refresh your knowledge in these areas read the Writing Event Listeners lesson of the Swing tutorial

The event model that is used by the JavaBeans architecture is a delegation model This model is composed of three main parts sources events and listeners

The source of an event is the object that originates or fires the event The source must define the events it will fire as well as the methods for registering listeners of those events A listener is an object that indicates that it is to be notified of events of a

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 30: Notes on JavaBeans

particular type Listeners register for events using the methods defined by the sources of those events

From the Properties lesson you discovered two event listeners The PropertyChangeListener(in the API reference documentation) interface provides a notification whenever a bound property value is changed and the VetoableChangeListener(in the API reference documentation) creates a notification whenever a bean changes a constrained property value

Simple Event Example

This example represents an application that performs an action when a button is clicked Button components are defined as sources of an event type called ActionEvent(in the API reference documentation) Listeners of events of this type must register for these events using the addActionListener method

Therefore the addActionListener method is used to register the ButtonHandler object as a listener of the ActionEvent event that is fired by the button

In addition according to the requirements of the ActionListener class you must define an actionPerformed method which is the method that is called when the button is clicked

import javaawteventActionEventimport javaawteventActionListenerimport javaxswingJTextAreaimport javaawtBorderLayoutimport javaxswingJButtonimport javaxswingJFrameimport javaxswingWindowConstants

public class ButtonHandler implements ActionListener Component that will contain messages about events generated private JTextArea output Creates an ActionListener that will put messages in JTextArea everytime event received public ButtonHandler( JTextArea output ) thisoutput = output

When receives action event notification appends message to the JTextArea passed into the constructor public void actionPerformed( ActionEvent event )

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 31: Notes on JavaBeans

thisoutputappend( Action occurred + event + n )

class ActionTester public static void main(String args[]) JFrame frame = new JFrame( Button Handler ) JTextArea area = new JTextArea( 6 80 ) JButton button = new JButton( Fire Event ) buttonaddActionListener( new ButtonHandler( area ) ) frameadd( button BorderLayoutNORTH ) frameadd( area BorderLayoutCENTER ) framepack() framesetDefaultCloseOperation( WindowConstantsDISPOSE_ON_CLOSE ) framesetLocationRelativeTo( null ) framesetVisible( true )

Using Introspection to Discover the Events A Bean Fires

The JavaBeans API provides event-oriented design patterns to give introspecting tools the ability to discover what events a bean can fire For a bean to be the source of an event it must implement methods that add and remove listener objects for that type of event The design patterns for these methods are the following

public void addltEventListenerTypegt(ltEventListenerTypegt a)public void removeltEventListenerTypegt(ltEventListenerTypegt a)

These methods let a source bean know where to fire events The source bean then fires events at those listener beans using the methods for those particular interfaces For example if a source bean registers ActionListener objects it will fire events at those objects by calling the actionPerformed method on those listeners package javaawteventimport javautilEventListener

public interface ActionListener extends EventListener

public void actionPerformed(ActionEvent e)

Using the NetBeans GUI Builder to Set Events

In the lesson Using the NetBeans GUI Builder you learned how to create a MyBean component add the yourName property and design a simple form Now you will set an event by which a value entered in the JTextField component is stored in the yourName property Use the GUI Builder as follows to set such an event

1 Left click the MyForm node

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 32: Notes on JavaBeans

2 Switch to the Connection Mode by clicking the appropriate button on the GUI Builder toolbar

3 In the Design Area or Inspector window select the OK button (jButton1) Notice that the button is highlighted in red when it is selected

4 In the Inspector window select the myBean1 component 5 In the Connection wizards Select Source Event page select the action|

actionPerformed[jButton1ActionPerformed1] event by expanding the event type directory nodes as represented in the following figure

6 Click the Next button 7 In the Specify Target Operation page specify the yourName property in the

MyBean component and click the Next button 8 In the Enter Parameters page specify the target property by selecting the Property

radio button 9 Press the ellipsis () button to display the Select Property dialog box 10 In the Select Property dialog box select the jTextField component from the

Component combobox and choose the text property from the list that is presented as shown on the following figure

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 33: Notes on JavaBeans

11 Click the Finish button

The Source Editor window is now displayed Since the GUI Builder automatically generates the code to connect the forms components the following code will be added to the MyForm class

private void jButton1ActionPerformed(javaawteventActionEvent evt) myBean1setYourName(jTextField1getText())

Lesson Bean Persistence

A bean has the property of persistence when its properties fields and state information are saved to and retrieved from storage Component models provide a mechanism for persistence that enables the state of components to be stored in a non-volatile place for later retrieval

The mechanism that makes persistence possible is called serialization Object serialization means converting an object into a data stream and writing it to storage Any applet application or tool that uses that bean can then reconstitute it by deserialization The object is then restored to its original state

For example a Java application can serialize a Frame window on a Microsoft Windows machine the serialized file can be sent with e-mail to a Solaris machine and then a Java application can restore the Frame window to the exact state which existed on the Microsoft Windows machine

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 34: Notes on JavaBeans

Any applet application or tool that uses that bean can then reconstitute it by deserialization

All beans must persist To persist your beans must support serialization by implementing either the javaioSerializable(in the API reference documentation) interface or the javaioExternalizable(in the API reference documentation) interface These interfaces offer you the choices of automatic serialization and customized serialization If any class in a classs inheritance hierarchy implements Serializable or Externalizable then that class is serializable

Classes That Are Serializable

Any class is serializable as long as that class or a parent class implements the javaioSerializable interface Examples of serializable classes include Component String Date Vector and Hashtable Thus any subclass of the Component class including Applet can be serialized Notable classes not supporting serialization include Image Thread Socket and InputStream Attempting to serialize objects of these types will result in an NotSerializableException

The Java Object Serialization API automatically serializes most fields of a Serializable object to the storage stream This includes primitive types arraysand strings The API does not serialize or deserialize fields that are marked transient or static

Controlling Serialization

You can control the level of serialization that your beans undergo Three ways to control serilization are

Automatic serialization implemented by the Serializable interface The Java serialization software serializes the entire object except transient and static fields

Customized serialization Selectively exclude fields you do not want serialized by marking with the transient (or static) modifier

Customized file format implemented by the Externalizable interface and its two methods Beans are written in a specific file format

Default Serialization The Serializable Interface

The Serializable interface provides automatic serialization by using the Java Object Serialization tools Serializable declares no methods it acts as a marker telling the Object Serialization tools that your bean class is serializable Marking your class Serializable means you are telling the Java Virtual Machine (JVM) that you have made sure your class will work with default serialization Here are some important points about working with the Serializable interface

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 35: Notes on JavaBeans

Classes that implement Serializable must have an access to a no-argument constructor of supertype This constructor will be called when an object is reconstituted from a ser file

You dont need to implement Serializable in your class if it is already implemented in a superclass

All fields except static and transient fields are serialized Use the transient modifier to specify fields you do not want serialized and to specify classes that are not serializable

Selective Serialization Using the transient Keyword

To exclude fields from serialization in a Serializable object mark the fields with the transient modifier

transient int status

Default serialization will not serialize transient and static fields

Selective Serialization writeObject and readObject

If your serializable class contains either of the following two methods (the signatures must be exact) then the default serialization will not take place

private void writeObject(javaioObjectOutputStream out) throws IOExceptionprivate void readObject(javaioObjectInputStream in) throws IOException ClassNotFoundException

You can control how more complex objects are serialized by writing your own implementations of the writeObject and readObject methods Implement writeObject when you need to exercise greater control over what gets serialized when you need to serialize objects that default serialization cannot handle or when you need to add data to the serialization stream that is not an object data member Implement readObject to reconstruct the data stream you wrote with writeObject

The Externalizable Interface

Use the Externalizable interface when you need complete control over your beans serialization (for example when writing and reading a specific file format) To use the Externalizable interface you need to implement two methods readExternal and writeExternal Classes that implement Externalizable must have a no-argument constructor

Lesson Long Term Persistence

Long-term persistence is a model that enables beans to be saved in XML format

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 36: Notes on JavaBeans

Information on the XML format and on how to implement long-term persistence for non-beans can be found in XML Schema and Using XMLEncoder

Encoder and Decoder

The XMLEncoder class is assigned to write output files for textual representation of Serializable objects The following code fragment is an example of writing a Java bean and its properties in XML format

XMLEncoder encoder = new XMLEncoder( new BufferedOutputStream( new FileOutputStream( Beanarchivexml ) ) )

encoderwriteObject( object ) encoderclose()

The XMLDecoder class reads an XML document that was created with XMLEncoder

XMLDecoder decoder = new XMLDecoder( new BufferedInputStream( new FileInputStream( Beanarchivexml ) ) )

Object object = decoderreadObject() decoderclose()

Whats in XML

An XML bean archive has its own specific syntax which includes the following tags to represent each bean element

an XML preamble to describe a version of XML and type of encoding a ltjavagt tag to embody all object elements of the bean an ltobjectgt tag to represent a set of method calls needed to reconstruct an object

from its serialized form ltobject class=javaxswingJButton method=newgt ltstringgtOkltstringgt ltobjectgt

or statements

ltobject class=javaxswingJButtongt ltvoid method=setTextgt ltstringgtCancelltstringgt ltvoidgt ltobjectgt

tags to define appropriate primitive types o ltbooleangt o ltbytegt

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 37: Notes on JavaBeans

o ltchargt o ltshortgt o ltintgt o ltlonggt o ltfloatgt o ltdoublegt

ltintgt5555ltintgt

a ltclassgt tag to represent an instance of Class ltclassgtjavaswingJFrameltclassgt

an ltarraygt tag to define an array ltarray class=javalangString length=5gt ltarraygt

The following code represents an XML archive that will be generated for the SimpleBean component

ltxml version=10 encoding=UTF-8 gtltjavagt ltobject class=javaxswingJFramegt ltvoid method=addgt ltobject class=javaawtBorderLayout field=CENTERgt ltobject class=SimpleBeangt ltvoidgt ltvoid property=defaultCloseOperationgt ltobject class=javaxswingWindowConstants field=DISPOSE_ON_CLOSEgt ltvoidgt ltvoid method=packgt ltvoid property=visiblegt ltbooleangttrueltbooleangt ltvoidgt ltobjectgtltjavagt

Lesson Introspection

Introspection is the automatic process of analyzing a beans design patterns to reveal the beans properties events and methods This process controls the publishing and discovery of bean operations and properties This lesson explains the purpose of introspection introduces the Introspection API and gives an example of introspection code

Purpose of Introspection

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 38: Notes on JavaBeans

A growing number of Java object repository sites exist on the Internet in answer to the demand for centralized deployment of applets classes and source code in general Any developer who has spent time hunting through these sites for licensable Java code to incorporate into a program has undoubtedly struggled with issues of how to quickly and cleanly integrate code from one particular source into an application

The way in which introspection is implemented provides great advantages including

1 Portability - Everything is done in the Java platform so you can write components once reuse them everywhere There are no extra specification files that need to be maintained independently from your component code There are no platform-specific issues to contend with Your component is not tied to one component model or one proprietary platform You get all the advantages of the evolving Java APIs while maintaining the portability of your components

2 Reuse - By following the JavaBeans design conventions implementing the appropriate interfaces and extending the appropriate classes you provide your component with reuse potential that possibly exceeds your expectations

Introspection API

The JavaBeans API architecture supplies a set of classes and interfaces to provide introspection

The BeanInfo (in the API reference documentation) interface of the javabeans package defines a set of methods that allow bean implementors to provide explicit information about their beans By specifying BeanInfo for a bean component a developer can hide methods specify an icon for the toolbox provide descriptive names for properties define which properties are bound properties and much more

The getBeanInfo(beanName) (in the API reference documentation) of the Introspector (in the API reference documentation) class can be used by builder tools and other automated environments to provide detailed information about a bean The getBeanInfo method relies on the naming conventions for the beans properties events and methods A call to getBeanInfo results in the introspection process analyzing the beanrsquos classes and superclasses

The Introspector class provides descriptor classes with information about properties events and methods of a bean Methods of this class locate any descriptor information that has been explicitly supplied by the developer through BeanInfo classes Then the Introspector class applies the naming conventions to determine what properties the bean has the events to which it can listen and those which it can send

The following figure represents a hierarchy of the FeatureDescriptor classes

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 39: Notes on JavaBeans

Each class represented in this group describes a particular attribute of the bean For example the isBound method of the PropertyDescriptor class indicates whether a PropertyChangeEvent event is fired when the value of this property changes

Editing Bean Info with the NetBeans BeanInfo Editor

To open the BeanInfo dialog box expand the appropriate class hierarchy to the bean Patterns node Right-click the bean Patterns node and choose BeanInfo Editor from the pop-up menu All elements of the selected class that match bean-naming conventions will be displayed at the left in the BeanInfo Editor dialog box as shown in the following figure

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 40: Notes on JavaBeans

Select one of the following nodes to view and edit its properties at the right of the dialog box

BeanInfo Bean Properties Methods Event Sources

Special symbols (green and red) appear next to the subnode to indicate whether an element will be included or excluded from the BeanInfo class

If the Get From Introspection option is not selected the nodes subnodes are available for inclusion in the BeanInfo class To include all subnodes right-click a node and choose Include All You can also include each element individually by selecting its subnode and setting the Include in BeanInfo property If the Get From Introspection option is selected the setting the properties of subnodes has no effect in the generated BeanInfo code

The following attributes are available for the nodes for each bean property event sources and method

Name - A name of the selected element as it appears in code Preferred - An attribute to specify where this property appears in the Inspector

window under the Properties node Expert - An attribute to specify where this property appears in the Inspector

window under the Other Properties node Hidden - An attribute to mark an element for tool use only Display Name Code - A display name of the property Short Description Code - A short description of the property Include in BeanInfo - An attribute to include the selected element in the BeanInfo

class Bound - An attribute to make the bean property bound Constrained - An attribute to make the bean property constrained Mode - An attribute to set the propertys mode and generate getter and setter

methods Property Editor Class - An attribute to specify a custom class to act as a property

editor for the property

For Event Source nodes the following Expert properties are available

Unicast (read-only) In Default Event Set

Introspection Sample

The following example represents code to perform introspection

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 41: Notes on JavaBeans

import javabeansBeanInfoimport javabeansIntrospectorimport javabeansIntrospectionExceptionimport javabeansPropertyDescriptor

public class SimpleBean private final String name = SimpleBean private int size

public String getName() return thisname

public int getSize() return thissize

public void setSize( int size ) thissize = size

public static void main( String[] args ) throws IntrospectionException BeanInfo info = IntrospectorgetBeanInfo( SimpleBeanclass ) for ( PropertyDescriptor pd infogetPropertyDescriptors() ) Systemoutprintln( pdgetName() )

This example creates a non-visual bean and displays the following properties derived from the BeanInfo object

class name size

Note that a class property was not defined in the SimpleBean class This property was inherited from the Object class To get properties defined only in the SimpleBean class use the following form of the getBeanInfo method

IntrospectorgetBeanInfo( SimpleBeanclass Objectclass )

Lesson Bean Customization

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 42: Notes on JavaBeans

Customization provides a means for modifying the appearance and behavior of a bean within an application builder so it meets your specific needs There are several levels of customization available for a bean developer to allow other developers to get maximum benefit from a beanrsquos potential functionality

The following links are useful for learning about property editors and customizers PropertyEditor (in the API reference documentation) interface PropertyEditorSupport (in the API reference documentation) class PropertyEditorManager (in the API reference documentation) class Customizer (in the API reference documentation) interface BeanInfo (in the API reference documentation) interface

A beans appearance and behavior can be customized at design time within beans-compliant builder tools There are two ways to customize a bean

By using a property editor Each bean property has its own property editor The NetBeans GUI Builder usually displays a beans property editors in the Properties window The property editor that is associated with a particular property type edits that property type

By using customizers Customizers give you complete GUI control over bean customization Customizers are used where property editors are not practical or applicable Unlike a property editor which is associated with a property a customizer is associated with a bean

Property Editors

A property editor is a tool for customizing a particular property type Property editors are activated in the Properties window This window determines a propertys type searches for a relevant property editor and displays the propertys current value in a relevant way

Property editors must implement the PropertyEditor interface which provides methods to specify how a property should be displayed in a property sheet The following figure represents the Properties window containing myBean1 properties

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 43: Notes on JavaBeans

You begin the process of editing these properties by clicking the property entry Clicking most of these entries will bring up separate panels For example to set up the foreground or background use selection boxes with choices of colors or press the button to work with a standard ColorEditor window Clicking on the toolTipText property opens a StringEditor window

The support class PropertyEditorSupport provides a default implementation of the PropertyEditor interface By subclassing your property editor from PropertyEditorSupport you can simply override the methods you need

To display the current property value sample within the Properties window you need to override isPaintable to return true You then must override paintValue to paint the current property value in a rectangle in the property sheet Heres how ColorEditor implements paintValue

public void paintValue(javaawtGraphics gfx javaawtRectangle box) Color oldColor = gfxgetColor() gfxsetColor(Colorblack) gfxdrawRect(boxx boxy boxwidth-3 boxheight-3) gfxsetColor(color) gfxfillRect(boxx+1 boxy+1 boxwidth-4 boxheight-4) gfxsetColor(oldColor)

To support the custom property editor override two more methods Override supportsCustomEditor to return true and then override getCustomEditor to return a custom editor instance ColorEditorgetCustomEditor returns this

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 44: Notes on JavaBeans

In addition the PropertyEditorSupport class maintains a PropertyChangeListener list and fires property change event notifications to those listeners when a bound property is changed

How Property Editors are Associated with Properties

Property editors are discovered and associated with a given property in the following ways

Explicit association by way of a BeanInfo object The editor of the titles property is set with the following line of code

pdsetPropertyEditorClass(TitleEditorclass)

Explicit registration by way of the javabeansPropertyEditorManagerregisterEditor method This method takes two arguments the bean class type and the editor class to be associated with that type

Name search If a class has no explicitly associated property editor then the PropertyEditorManager searchs for that classs property editor in the following ways

o Appending Editor to the fully qualified class name For example for the mypackageComplexNumber class the property editor manager would search for the mypackageComplexNumberEditor class

o Appending Editor to the class name and searching a class path

Customizers

You have learned that builder tools provide support for you to create your own property editors What other needs should visual builders meet for complex industrial-strength beans Often it is undesirable to have all the properties of a bean revealed on a single (sometimes huge) property sheet What if one single root choice about the type of the bean rendered half the properties irrelevant The JavaBeans specification provides for user-defined customizers through which you can define a higher level of customization for bean properties than is available with property editors

When you use a bean Customizer you have complete control over how to configure or edit a bean A Customizer is an application that specifically targets a beans customization Sometimes properties are insufficient for representing a beans configurable attributes Customizers are used where sophisticated instructions would be needed to change a bean and where property editors are too primitive to achieve bean customization

All customizers must

Extend javaawtComponent or one of its subclasses

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 45: Notes on JavaBeans

Implement the javabeansCustomizer interface This means implementing methods to register PropertyChangeListener objects and firing property change events at those listeners when a change to the target bean has occurred

Implement a default constructor Associate the customizer with its target class via BeanInfogetBeanDescriptor

Lesson Using the BeanContext API

As stated in the specification the purpose of the Extensible Runtime Containment and Services Protocol is to introduce the concept of a relationship between a Component and its environment or Container wherein a newly instantiated Component is provided with a reference to its Container or Embedding Context The Container or Embedding Context not only establishes the hierarchy or logical structure but it also acts as a service provider that Components may interrogate in order to determine and subsequently employ the services provided by their Context

Overview of the BeanContext API

This section introduces extensible mechanisms and represents inheritance diagram of the BeanContext API

Bean Context 1 Containment Only

This section teaches how to use the BeanContextSupport class to provide the basic BeanContext functionality

Bean Context 2 Containment and Services

This section teaches how to use service capability defined by the BeanContextServices interface

AWT Containers and the BeanContextProxy Interface

This section describes how an AWT Container can act as a BeanContext

Additional Resources

The Extensible Runtime Containment and Services Protocol Specification The javabeansbeancontext API documentation

Overview of the BeanContext API

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 46: Notes on JavaBeans

The Extensible Runtime Containment and Services Protocol supports extensible mechanisms that

Introduce an abstraction for the environment or context in which a JavaBean logically functions during its life-cycle that is a hierarchy of JavaBeans

Enable the dynamic addition of arbitrary services to a JavaBeans environment Provide a single service discovery mechanism through which JavaBeans may

interrogate their environment in order both to ascertain the availability of particular services and to subsequently employ those services

Provide better support for JavaBeans that are also Applets

In English this means that there now exists a standard mechanism through which Java developers can logically group a set of related JavaBeans into a context that the beans can become aware of andor interact with This context or containing environment is known as the BeanContext

There are two distinct types of BeanContext included in this protocol one which supports membership only (interface javabeansbeancontextBeanContext) and one which supports membership and offers services (interface javabeansbeancontextBeanContextServices) to its JavaBeans nested within

To orient yourself with the classes and interfaces of javabeansbeancontext take a minute to look over the following hierarchy diagram You will notice that the majority of the package is defined as interfaces which allow for multiple inheritance

Inheritance Diagram of the BeanContext API

The classes and interfaces relevant to the BeanContext API are listed in the following diagrams As you study the diagrams take note of the BeanContext and BeanContextServices interfaces and that each has its own concrete implementation that you can subclass or instantiate directly (classes javabeansbeancontextBeanContextSupport and javabeansbeancontextBeanContextServicesSupport respectively) Also take note of the location of the javabeansbeancontextBeanContextChild interface This is the interface that allows nested JavaBeans to become aware of their enclosing BeanContext

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 47: Notes on JavaBeans

Bean Context 1 Containment Only

The containment portion of the Extensible Runtime Containment and Services Protocol is defined by the BeanContext interface In its most basic form a BeanContext is used to logically group a set of related java beans bean contexts or arbitrary objects JavaBeans nested into a BeanContext are known as child beans Once nested a child bean can query its BeanContext for various membership information as illustrated in the following examples

Here are some possible BeanContext containment scenarios

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 48: Notes on JavaBeans

The sample code presented in this chapter uses instances of the BeanContextSupport helper class to provide the basic BeanContext functionality A BeanContextSupport object is simply a concrete implementation of the BeanContext interface

With a BeanContextSupport instance it is possible to

Add an object bean or BeanContext boolean add(Object o) Remove an object bean or BeanContext boolean remove(Object o) Add a BeanContextMembershipListener void

addBeanContextMembershipListener(BeanContextMembershipListener

bcml) Remove a BeanContextMembershipListener void

removeBeanContextMembershipListener(BeanContextMembershipListener

bcml) Get all JavaBean or BeanContext instances currently nested in this BeanContext

as an array or as an Iterator Object[] toArray() Object[] toArray(Object[] a) and Iterator iterator()

Determine whether or not a specified object is currently a child of the BeanContext boolean contains(Object o)

Get the number of children currently nested in this BeanContext int size() Determine whether or not the BeanContext currently has zero children boolean

isEmpty() Instantiate a new JavaBean instance as a child of the target BeanContext Object

instantiateChild(String beanName)

The following test programs which are run from the command line illustrate the use of these methods

The comments in the source code explain the purpose of each

File Example1java

import javabeansbeancontext

public class Example1 private static BeanContextSupport context = new BeanContextSupport() The BeanContext

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 49: Notes on JavaBeans

private static BeanContextChildSupport bean = new BeanContextChildSupport() The JavaBean public static void main(String[] args) report()

Add the bean to the context Systemoutprintln(Adding bean to context) contextadd(bean)

report()

private static void report() Print out a report of the contexts membership state Systemoutprintln(=============================================)

Is the context empty Systemoutprintln(Is the context empty + contextisEmpty())

Has the context been set for the child bean boolean result = (beangetBeanContext()=null) Systemoutprintln(Does the bean have a context yet + result)

Number of children in the context Systemoutprintln(Number of children in the context + contextsize())

Is the specific bean a member of the context Systemoutprintln(Is the bean a member of the context + contextcontains(bean))

Equality test if (beangetBeanContext() = null) boolean isEqual = (beangetBeanContext()==context) true means both references point to the same object Systemoutprintln(Contexts are the same + isEqual) Systemoutprintln(=============================================)

Output =============================================Is the context empty trueDoes the bean have a context yet falseNumber of children in the context 0Is the bean a member of the context false=============================================Adding bean to context=============================================Is the context empty falseDoes the bean have a context yet true

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 50: Notes on JavaBeans

Number of children in the context 1Is the bean a member of the context trueContexts are the same true=============================================

File Example2java

import javabeansbeancontext

public class Example2 public static void main(String[] args)

A BeanContext BeanContextSupport context = new BeanContextSupport()

Many JavaBeans BeanContextChildSupport[] beans = new BeanContextChildSupport[100]

Systemoutprintln(Number of children in the context + contextsize())

Create the beans and add them to the context for (int i = 0 i lt beanslength i++) beans[i] = new BeanContextSupport() contextadd(beans[i]) Systemoutprintln(Number of children in the context + contextsize())

Context now has 100 beans in it get references to them all Object[] children = contexttoArray() Systemoutprintln(Number of objects retrieved from the context + childrenlength)

Output Number of children in the context 0Number of children in the context 100Number of objects retrieved from the context 100

File Example3java

import javabeansbeancontextimport javaio

public class Example3 public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() Systemoutprintln(Number of children nested into the context + contextsize())

BeanContextChildSupport child = null try child = (BeanContextChildSupport)contextinstantiateChild(javabeansbeancontextBeanContextChildSupport)

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 51: Notes on JavaBeans

catch(IOException e) Systemoutprintln(IOException occurred + egetMessage()) catch(ClassNotFoundException e) Systemoutprintln(Class not found + egetMessage()) Systemoutprintln(Number of children nested into the context + contextsize())

Output Number of children nested into the context 0Number of children nested into the context 1

BeanContextMembershipEvent Notification

The BeanContext API uses the standard Java event model to register listeners and deliver events For an overview of this standard event model refer to Writing Event Listeners For details about handling specific events see Writing Event Listeners

In a basic BeanContext the event classes and interfaces involved are

javabeansbeancontextBeanContextMembershipEvent Encapsulates the list of children added to or removed from the membership of a particular BeanContext An instance of this event is fired whenever a successful add() remove() retainAll() removeAll() or clear() is invoked on a given BeanContext instance

javabeansBeanContextMembershipListener Objects wishing to receive BeanContextMembershipEvents implement this interface It defines methods void childrenAdded(BeanContextMembershipEvent bcme) and void childrenRemoved(BeanContextMembershipEvent bcme) which are called when a child is added to or removed from a given BeanContext instance

BeanContextMembershipEvent Notification Sample Code

File MembershipTestjava

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() the context MyMembershipListener listener = new MyMembershipListener() BeanContextChildSupport bean = new BeanContextChildSupport() a JavaBean contextaddBeanContextMembershipListener(listener) now listening contextadd(bean) contextremove(bean)

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 52: Notes on JavaBeans

class MyMembershipListener implements BeanContextMembershipListener public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context)

Output Another bean has been added to the contextA bean has been removed from the context

The same example implemented using an anonymous inner class

import javabeansbeancontext

public class MembershipTest public static void main(String[] args) BeanContextSupport context = new BeanContextSupport() contextaddBeanContextMembershipListener(new BeanContextMembershipListener() public void childrenAdded(BeanContextMembershipEvent bcme) Systemoutprintln(Another bean has been added to the context)

public void childrenRemoved(BeanContextMembershipEvent bcme) Systemoutprintln(A bean has been removed from the context) ) BeanContextChildSupport bean = new BeanContextChildSupport() contextadd(bean) contextremove(bean)

Output Another bean has been added to the contextA bean has been removed from the context

laquo Previous bull Trail bull Next raquo

Bean Context 2 Containment and Services

As mentioned in the introduction the BeanContext API also provides a standard mechanism through which JavaBeans can discover and utilize the services offered by

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 53: Notes on JavaBeans

their enclosing BeanContext Service capability is defined by the BeanContextServices interface Because this interface is a BeanContext extension it inherits all BeanContext membership capabilities The discovery and requesting of services can be summarized in the following steps

1 A JavaBean that implements the javabeansbeancontextBeanContextServicesListener interface joins the bean context (the context itself is a BeanContextServices implementation) and registers its intent to be notified of new services via the contexts addBeanContextServicesListener(BeanContextServicesListener bcsl) method

2 A javabeansbeancontextBeanContextServiceProvider registers a new service with the context via the contexts addService() method The context notifies all currently registered listeners that this new service has been added

3 After being notified of the newly available service the listening JavaBean requests an instance of the service from the context

4 The context tells the service provider to deliver the service to the requesting JavaBean

BeanContextServices Service Related Methods

Using a javabeansbeancontextBeanContextServicesSupport object as the bean context it is possible to

Add a service to this BeanContext boolean addService(javalangClass serviceClass BeanContextServiceProvider serviceProvider)

Add a service to this BeanContext boolean addService(Class serviceClass BeanContextServiceProvider bcsp boolean fireEvent)

Revoke a service void revokeService(javalangClass serviceClass BeanContextServiceProvider serviceProvider boolean

revokeCurrentServicesNow) Release a BeanContextChilds (or any arbitrary object associated with a

BeanContextChild) reference to the specified service void releaseService(BeanContextChild child javalangObject requestor

javalangObject service) Add a BeanContextServicesListener void

addBeanContextServicesListener(BeanContextServicesListener bcsl) Remove a BeanContextServicesListener void

removeBeanContextServicesListener(BeanContextServicesListener

bcsl) Get the currently available services for this context Iterator

getCurrentServiceClasses() Determine whether or not a given service is currently available from this context

boolean hasService(javalangClass serviceClass) Get a service from the context Object getService(BeanContextChild

child javalangObject requestor javalangClass serviceClass javalangObject serviceSelector

BeanContextServiceRevokedListener bcsrl)

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 54: Notes on JavaBeans

Get the list of service dependent service parameters (Service Selectors) for the specified service Iterator getCurrentServiceSelectors(javalangClass serviceClass)

Service Event Notification

JavaBeans nested into a BeanContextServices implement BeanContextServicesListener to listen for new services being added andor BeanContextServiceRevokedListener to listen for services being revoked

There are two event types that may be intercepted by such listeners

BeanContextServiceAvailableEvent received by the BeanContextServicesListener in order to identify the service being registered

BeanContextServiceRevokedEvent received by the BeanContextServiceRevokedListener in order to identify the service being revoked

The Service Provider

JavaBeans can query their enclosing bean context for a list of available services or ask for a specific service by name The service itself however is actually delivered by a BeanContextServiceProvider The provider can be any object that implements the javabeansbeancontextBeanContextServiceProvider interface Services become available in a context via the bean contexts addService() registration method

BeanContextServiceProvider offers the following three methods which will be automatically called when a bean requests (or releases) a service from its context

Object getService(BeanContextServices bcs javalangObject requestor javalangClass serviceClass javalangObject

serviceSelector) Iterator getCurrentServiceSelectors(BeanContextServices bcs

javalangClass serviceClass) public void releaseService(BeanContextServices bcs

javalangObject requestor javalangObject service) Release a service from any object that currently has a reference to it

The Service

The service itself is best described by this paragraph from the specification

A service represented by a Class object is typically a reference to either an interface or to an implementation that is not publicly instantiable This Class defines an interface protocol or contract between a BeanContextServiceProvider the factory of the service and an arbitrary object associated with a BeanContextChild that is currently nested within the BeanContext the service is registered with

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 55: Notes on JavaBeans

The following section presents a sample application that uses a word counting service to count the number of words in a given text file

A Word Counting Service Example

The classes defined in this sample application are DocumentBeanjava A JavaBean that encapsulates a File object Create an

instance of this bean by passing it a String indicating the name of the text file to represent This bean extends BeanContextChildSupport which allows it to listen for additionrevocation of services in its context When the bean detects that a WordCount service has been added to the context it requests the service to count the number of words it contains

WordCountServiceProviderjava A class that acts as the factory for delivering the WordCount service This class implements the BeanContextServiceProvider interface

WordCountjava This interface defines the service itself DocumentTesterjava The main test program

File DocumentBeanjava

import javabeansbeancontextimport javaioimport javautil

public final class DocumentBean extends BeanContextChildSupport

private File document private BeanContextServices context

public DocumentBean(String fileName) document = new File(fileName)

public void serviceAvailable(BeanContextServiceAvailableEvent bcsae) Systemoutprintln([Detected a service being added to the context])

Get a reference to the context BeanContextServices context = bcsaegetSourceAsBeanContextServices() Systemoutprintln(Is the context offering a WordCount service + contexthasService(WordCountclass))

Use the service if its available if (contexthasService(WordCountclass)) Systemoutprintln(Attempting to use the service) try WordCount service = (WordCount)contextgetService(this this

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 56: Notes on JavaBeans

WordCountclass document this) Systemoutprintln(Got the service) servicecountWords() catch(Exception e)

public void serviceRevoked(BeanContextServiceRevokedEvent bcsre) Systemoutprintln([Detected a service being revoked from the context])

File WordCountServiceProviderjava

import javabeansbeancontextimport javautilimport javaio

public final class WordCountServiceProvider implements BeanContextServiceProvider

public Object getService(BeanContextServices bcs Object requestor Class serviceClass Object serviceSelector)

For this demo we know that the cast from serviceSelector to File will always work final File document = (File)serviceSelector

return new WordCount() public void countWords() try Create a Reader to the DocumentBeans File BufferedReader br = new BufferedReader(new FileReader(document)) String line = null int wordCount = 0 while ((line = brreadLine()) = null) StringTokenizer st = new StringTokenizer(line) while (sthasMoreTokens()) Systemoutprintln(Word + (++wordCount) + is + stnextToken()) Systemoutprintln(Total number of words in the document + wordCount) Systemoutprintln([WordCount service brought to you by WordCountServiceProvider]) brclose() catch(Exception e)

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 57: Notes on JavaBeans

public void releaseService(BeanContextServices bcs Object requestor Object service) do nothing

public Iterator getCurrentServiceSelectors(BeanContextServices bcs Class serviceClass) return null do nothing

File WordCountjava

public interface WordCount

public abstract void countWords()

File DocumentTesterjava

import javabeansbeancontextimport javautil

public class DocumentTester

public static void main(String[] args) BeanContextServicesSupport context = new BeanContextServicesSupport() a bean context DocumentBean doc1 = new DocumentBean(Testtxt) contextadd(doc1) contextaddBeanContextServicesListener(doc1) listen for new services WordCountServiceProvider provider = new WordCountServiceProvider() contextaddService(WordCountclass provider) add the service to the context

File Testtxt

This text will be analyzed by the WordCount

service

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface
Page 58: Notes on JavaBeans

Output

[Detected a service being added to the context]Is the context offering a WordCount service trueAttempting to use the serviceGot the serviceWord 1 is ThisWord 2 is textWord 3 is willWord 4 is beWord 5 is analyzedWord 6 is byWord 7 is theWord 8 is WordCountWord 9 is serviceTotal number of words in the document 9[WordCount service brought to you by WordCountServiceProvider]

AWT Containers and the BeanContextProxy Interface

Sometimes it is desirable for an AWT Container to act as a BeanContext However AWT Containers cannot implement the BeanContext interface directly because of a method name collision between Component and Collection If some AWT Component needs to act as a BeanContext it must internally create a BeanContext instance and delegate work to it Third parties such as visual builder tools can discover this BeanContext instance if the Component implements the BeanContextProxy interface

The BeanContextProxy Interface

public BeanContextChild getBeanContextProxy() - Gets the BeanContextChild (or subinterface) associated with this object

  • Creating a New Project
  • Creating a New Form
  • The GUI Builder Interface
  • Creating a Bean
  • Adding Components to the Form
  • Adding a Title Property
  • Inspecting Properties
  • Implementing Bound Property Support Within a Bean
  • Creating a Bound Property
  • Handling Vetoes
  • Creating a Constrained Property
  • Creating an Indexed Property
  • Simple Event Example
  • Using Introspection to Discover the Events A Bean Fires
  • Using the NetBeans GUI Builder to Set Events
  • Classes That Are Serializable
  • Controlling Serialization
  • Default Serialization The Serializable Interface
  • Selective Serialization Using the transient Keyword
  • Selective Serialization writeObject and readObject
  • The Externalizable Interface
  • Encoder and Decoder
  • Whats in XML
  • Purpose of Introspection
  • Introspection API
  • Editing Bean Info with the NetBeans BeanInfo Editor
  • Introspection Sample
  • Property Editors
  • How Property Editors are Associated with Properties
  • Customizers
  • Overview of the BeanContext API
  • Bean Context 1 Containment Only
  • Bean Context 2 Containment and Services
  • AWT Containers and the BeanContextProxy Interface
  • Additional Resources
  • Inheritance Diagram of the BeanContext API
  • BeanContextMembershipEvent Notification
  • BeanContextMembershipEvent Notification Sample Code
  • The same example implemented using an anonymous inner class
  • A Word Counting Service Example
  • The BeanContextProxy Interface