51
slide 13.1 dvanced Programming 2004 Java Beans

Slide 13.1 Advanced Programming 2004 Java Beans. slide 13.2 Advanced Programming 2004 What is a JavaBean?

Embed Size (px)

Citation preview

slide 13.1 Advanced Programming 2004

Java Beans

slide 13.2 Advanced Programming 2004

What is a JavaBean?

slide 13.3 Advanced Programming 2004

This is not a JavaBean!

This is Mr. Bean!

slide 13.4 Advanced Programming 2004

What is a JavaBean?

• A JavaBean is a reusable software component that can be manipulated visually in a builder tool.

• Example of builder tools: NetBeans, IBM's Visual Age, Borland/Inprise's JBuilder

• The JavaBeans API provides a framework for defining reusable, embeddable, modular software components.

• JavaBeans can take a variety of forms, from invisible beans such as a timer to GUI components such as a JComponent.

• Although all beans can be manipulated visually, this does not mean every bean has its own visual representation. For example, javax.sql.RowSet is a JavaBean component that represents the data resulting from a database query.

slide 13.5 Advanced Programming 2004

What is a JavaBean?

• There are no limits on the simplicity or complexity of a JavaBeans component.

• A complex system, such as an embeddable spreadsheet application, can function as individual JavaBean.

• One of the goals of the JavaBeans model is interoperability with similar component frameworks.

• The JavaBeans component model consists of the java.beans and java.beans.beancontext packages and a number of important naming and API conventions to which conforming beans and bean-manipulation tools must adhere.

• See http://java.sun.com/beans/ for the JavaBeans specification.

slide 13.6 Advanced Programming 2004

• JavaBeans– Used for rapid application development

• Assembling predefined software components

– Programming in the large– Used by a component assembler, such as

NetBeans– Promote code reuse

Usage of JavaBeans

slide 13.7 Advanced Programming 2004

• Ideally, we would like to build a substantial application using prefabricated beans, without ever writing a line of code!

• Three characteristics of the JavaBeans architecture make it possible to do that.– Design patterns (coding conventions)– Reflection– Object Serialization

slide 13.8 Advanced Programming 2004

Design patterns

• Design patterns (i.e. coding conventions) let tools and humans recognize the basic features of a bean and manipulate it without knowing how it is implemented.

• By examining a Bean, we can tell what events it can fire and receive; we can learn about its properties (the equivalent of its public variables) and methods.

slide 13.9 Advanced Programming 2004

Reflection

• Reflection makes it possible for Java program to inspect and manipulate new Java objects at runtime.

• Reflection lets a beantool analyze a bean's capabilities, examine the values of its fields, and invoke its methods.

slide 13.10 Advanced Programming 2004

Object Serialization

• The Java Serialization API allows us to "freeze" a live application and revive it later.

• This makes it possible to piece together applications without extensive code generation.

• Rather than customizing and compiling large amounts of Java code to build an application on startup, we can simply paste together beans, configure them, tweak their appearance, and then save them. Later, the beans can be restored with all their state and interconnections intact.

• This opens up a fundamentally different way of thinking about the design process.

slide 13.11 Advanced Programming 2004

NetBeans IDE

• In this course, we use the NetBeans IDE to demonstrate and create beans.

• NetBeans is a popular, pure Java development environment for Java.

• NetBeans offers powerful source-editor capabilities, templates that aid in the creation of various types of Java classes, and the ability to compile, run, and debug applications, all in one tool.

• NetBeans is an open-source project with a modular architecture that allows it to be easily extended with new capabilities.

• See http://www.netbeans.org

slide 13.12 Advanced Programming 2004

Bean Characteristics

• Any object that conforms to certain basic rules can be a bean; there is no Bean class all beans are required to subclass.

• Many beans are AWT components, but it is also quite possible and useful, to write "invisible" beans that do not have an onscreen appearance.

• A bean is characterized by the properties, events, and methods it exports.

• A property is a piece of the bean's internal state that can be programmatically set and/or queried through a standard pair of set and get methods.

slide 13.13 Advanced Programming 2004

Bean Characteristics (cont.)

• A bean communicates with the application in which it is embedded and with other beans by generating events.

• The JavaBeans API uses the same event model AWT and Swing components use. This model is based on the java.util.EventObject class and the java.util.EventListener interface.

• The methods exported by a bean are any public methods defined by the bean, excluding those methods that get and set property values and register and remove event listeners.

slide 13.14 Advanced Programming 2004

Bean Event Model

• A bean defines an event if it provides add and remove methods for registering and deregistering listener objects for that event.

• An application that wants to be notified when an event of that type occurs uses these methods to register an event listener object of the appropriate type.

• When the event occurs, the bean notifies all registered listeners by passing an event object that describes the event to a method defined by the event listener interface.

slide 13.15 Advanced Programming 2004

Specialized Properties

• In addition to the regular properties described earlier, the JavaBeans API also supports: indexed property, bound property, and constrained property.

• An indexed property is a property that has an array value, as well as getter and setter methods that access both individual elements of the array and the entire array.

• A bound property is a property that sends a PropertyChangeEvent to any interested PropertyChangeListener objects whenever the value of the property changes.

slide 13.16 Advanced Programming 2004

• A constrained property is a property that can have any changes vetoed by any interested listener.

• When the value of a constrained property of a bean changes, the bean must send out a PropertyChangeEvent to the list of interested VetoableChangeListener objects. If any of these objects throws a PropertyVetoException, the property value is not changed, and the PropertyVetoException is propagated back to the property setter method.

slide 13.17 Advanced Programming 2004

JavaBeans Conventions

• The JavaBeans component model relies on a number of rules and conventions that bean-developers must follow.

• These conventions are referred to as design patterns. They specify such things as method names and signatures for property accessor methods defined by a bean.

• The reason for these design patterns is interoperability between beans and the beantool programs that manipulate them.

• One such convention, for example, is that the getter and setter methods for a property should begin with get and set.

slide 13.18 Advanced Programming 2004

JavaBeans Conventions: Beans

A bean itself must adhere to the following conventions:• Class name: There are no restrictions on the class name

of a bean.• Superclass: A bean can extend any other class. Beans

are often AWT or Swing components, but there are no restrictions.

• Instantiation: A bean must provide a no-parameter constructor or a file that contains a serialized instance, so a beantool can instantiate the bean. The file that contains the bean should have the same name as the bean, with an extension .ser.

• Bean name: The name of a bean is the name of the class that implements it or the name of the file that holds the serialized instance of the bean.

slide 13.19 Advanced Programming 2004

JavaBeans Conventions: Properties

A bean defines a property p of type T if it has accessor methods that follow these patterns (if T is boolean, a

special form of getter method is allowed):• Getter: public T getP( )• Boolean getter: public boolean isP( )• Setter: public void setP(T)• Exceptions: Property accessor methods can throw any

type of checked or unchecked exceptions.

slide 13.20 Advanced Programming 2004

JavaBeans Conventions: Indexed Properties

A bean defines an indexed property p of type T[] if it defines

the following accessor methods:• Array getter: public T[] getP( )• Element getter: public T getP(int)• Array setter: public void setP(T[])• Element setter: public void setP(int,T)• Exceptions: Indexed property accessor methods can

throw any type of checked or unchecked exceptions. In particular, they should throw an ArrayIndexOutOfBoundsException if the supplied index is out of bounds.

slide 13.21 Advanced Programming 2004

JavaBeans Conventions: Bound Properties

Here are the conventions for a bound property:• Accessor methods: follow the same conventions as a

regualr property.• Introspection: A beantool cannot distinguish a bound

property from a nonbound property through introspection alone. Therefore, we should implement a BeanInfo class that returns a PropertyDescriptor object for the property. The isBound( ) method of this PropertyDescriptor should return true.

• Listener registration: A bean that defines one or more bound properties must define a pair of methods for the registration of listeners that are notified when any bound property value changes. The methods must have these signatures:

slide 13.22 Advanced Programming 2004

JavaBeans Conventions: Bound Properties (cont.)

public void addPropertyChangeListener( PropertyChangeListener) public void removePropertyChangeListener( PropertyChangeListener)

• Named property listener registration: A bean can optionally provide additional methods that allow event listeners to be registered for changes to a single bound property value. These methods are passed the name of a property and have the following signatures:

public void addPropertyChangeListener( String, PropertyChangeListener) public void removePropertyChangeListener( String, PropertyChangeListener)

slide 13.23 Advanced Programming 2004

JavaBeans Conventions: Bound Properties (cont.)

• Per-property listener registration: A bean can optionally provide additional event listener registration methods that are specific to a single property. For a property p, these methods have the following signatures:

public void addPListener( PropertyChangeListener) public void removePListener( PropertyChangeListener)

Methods of this type allow a beantool to distinguish a bound property from a nonbound property.

• Notification: When the value of a bound property changes, the bean should update its internal state to reflect the change and then pass a PropertyChangeEvent to the propertyChange() method of every PropertyChangeListener object registered for the bean or the specific bound property.

• Support: java.beans.PropertyChangeSupport is a helpful class for implementing bound properties.

slide 13.24 Advanced Programming 2004

JavaBeans Conventions: Constrained Properties

• Getter: The getter method for a constrained property is the same as the getter method for a regular property.

• Setter: The setter method of a constrained property throws a PropertyVetoException if the property change is vetoed. For a property p of type T, the signature looks like this:

public void setP(T) throws PropertyVetoException

• Listener registration: A bean that defines one or more constrained properties must define a pair of methods for the registration of listeners that are notified when any constrained property value changes. The methods must have these signatures: public void addVetoableChangeListener(

VetoableChangeListener) public void removeVetoableChangeListener( VetoableChangeListener)

slide 13.25 Advanced Programming 2004

JavaBeans Conventions: Constrained Properties (cont.)

• Named property listener registration: A bean can optionally provide additional methods that allow event listeners to be registered for changes to a single constrained property value. These methods are passed the name of a property and have the following signatures:

public void addVetoableChangeListener( String, VetoableChangeListener) public void removeVetoableChangeListener( String, VetoableChangeListener)

• Per-property listener registration: A bean can optionally provide additional event listener registration methods that are specific to a single property. For a property p, these methods have the following signatures:

public void addPListener( VetoableChangeListener) public void removePListener( VetoableChangeListener)

slide 13.26 Advanced Programming 2004

JavaBeans Conventions: Constrained Properties (cont.)

• Notification: When the value of a constrained property changes, the bean should generate a PropertyChangeEvent that describes the requested change and pass the event to the vetoableChange() method of every VetoableChangeListener object registered for the bean or the specific constrained property. If any listener vetoes the change by throwing a PropertyVetoException, the bean must send out another PropertyChangeEvent to revert the property to its original value, and then it should throw a PropertyVetoException itself. If, on the other hand, the property change is not vetoed, the bean should update its internal state to reflect the change. If the constrained property is also a bound property, the bean should notify PropertyChangeListener objects at this point.

• Support: java.beans.VetoableChangeSupport is a helpful class for implementing constrained properties.

slide 13.27 Advanced Programming 2004

JavaBeans Conventions: Events

In addition to PropertyChangeEvent events generated when bound

and constrained properties are changed, a bean can generate other

types of events. An event named E should follow these conventions:

• Event class: The event class should directly or indirectly extend java.util.EventObject and should be named EEvent.

• Listener interface: The event must be associated with an event listener interface that extends java.util.EventListener and is named EListener.

• Listener methods: The event listener interface can define any number of methods that take a single argument of type EEvent and return void.

slide 13.28 Advanced Programming 2004

JavaBeans Conventions: Events (cont.)

• Listener registration: The bean must define a pair of methods for registering event listeners that want to be notified when an E event occurs. The methods should have the following signatures:

public void addEListener(EListener) public void removeEListener(EListener)

• Unicast events: A unicast event allows only one listener object to be registered at a single time. If E is a unicast event, the listener registration method should have the signature:

public void addEListener(EListener) throws TooManyListenersException

slide 13.29 Advanced Programming 2004

JavaBeans Conventions: Methods

A beantool can expose the methods of a bean to application designers. The only formal convention is that these methods

must bedeclared public. The following guidelines are also useful:• Method name: A method can have any name that does not

conflict with the property and event names.• Parameters: A method can have any number and type of

parameters.• Excluding methods: A bean can explicitly specify the list of

methods it exports by providing a BeanInfo implementation.• Documentation: A bean can provide user-friendly, human-

readable localized names and descriptions for methods through MethodDescriptor objects returned by a BeanInfo implementation.

slide 13.30 Advanced Programming 2004

JavaBeans Conventions: Auxiliary Classes

A bean can provide the following auxiliary classes:• BeanInfo: To provide additional information about a bean B,

implement the BeanInfo interface in a class named BBeanInfo.

• Property editor for a specific type: To enable a beantool to work with properties of type T, implement the PropertyEditor interface in a class named TEditor. The class must have a no-parameter constructor.

• Property editor for a specific property: To customize the way a beantool allows the user to enter the values for a single property,define a class that implements the PropertyEditor interface and has a no-parameter constructor, and register that class with a PropertyDescriptor object returned by the BeanInfo class for the bean.

slide 13.31 Advanced Programming 2004

JavaBeans Conventions: Auxiliary Classes (cont.)

• Customizers: To define a customizer, or wizard, for configuring a bean B, define an AWT or Swing component with a no-parameter constructor that does the customization. The class is commonly named BCustomizer. Register the class with the BeanDescriptor object returned by the BeanInfo class for the bean.

• Documentation: Define default documentation for a bean B in HTML format and store that documentation in a file named B.html.

slide 13.32 Advanced Programming 2004

JavaBeans Conventions: Bean Packaging

Beans are distributed in JAR archive files that have the following format:• Content: The class or classes that implement a bean should

be included in the JAR file, along with auxiliary classes such as BeanInfo and PropertyEditor implementations. If the bean is instantiated from a serialized instance, that instance should be included in the JAR archive with a filename ending in .ser. The JAR file can contain HTML documentation for the bean and should also contain any resource files, such as images, required by the bean and its auxiliary classes. A single JAR file can contain more than one bean. Within a JAR file, / is always used as the directory separator.

• Java-Bean attribute: The manifest of the JAR file must mark any .class and .ser files that define a bean with the attribute:

Java-Bean: True

slide 13.33 Advanced Programming 2004

trivial beans• The following class is a Bean, albeit an invisible and useless

one:

public class Trivial implements java.io.Serializable { }

• It doesn't have any properties, and it doesn't do anything. But it's a Bean nonetheless, and we can drag it into NetBeans/BDK.

• If we modify this class to extend javax.swing.JComponent, we suddenly have a graphical Bean, with lots of standard Swing properties, such as size and color:

public class TrivialComponent extends javax.swing.JComponent { }

slide 13.34 Advanced Programming 2004

The Dial Bean

slide 13.35 Advanced Programming 2004

File: beans/Dial.javapackage beans;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import javax.swing.*;

public class Dial extends JComponent {

//instance variables:

int minValue, nvalue, maxValue, radius;

//constructors:

public Dial() {

this(0, 100, 0);

}

slide 13.36 Advanced Programming 2004

public Dial(int minValue, int maxValue, int value) {

setMinimum( minValue );

setMaximum( maxValue );

setValue( value );

setForeground( Color.orange );

addMouseListener(new MouseAdapter() {

public void mousePressed(MouseEvent e) { spin(e); }

});

addMouseMotionListener(new MouseMotionAdapter() {

public void mouseDragged(MouseEvent e) { spin(e); }

});

}

slide 13.37 Advanced Programming 2004

protected void spin( MouseEvent e ) {

int y = e.getY();

int x = e.getX();

double th = Math.atan((1.0 * y - radius) / (x - radius));

int value=(int)(th / (2 * Math.PI) * (maxValue - minValue));

if (x < radius)

setValue( value + (maxValue-minValue) / 2 + minValue);

else if (y < radius)

setValue( value + maxValue );

else

setValue( value + minValue);

}

slide 13.38 Advanced Programming 2004

public void paintComponent(Graphics g) {

Graphics2D g2 = (Graphics2D)g;

int tick = 10;

radius = Math.min( getSize().width,getSize().height )/2 - tick;

g2.setPaint( getForeground().darker() );

g2.drawLine( radius * 2 + tick / 2, radius,

radius * 2 + tick, radius);

g2.setStroke( new BasicStroke(2) );

draw3DCircle( g2, 0, 0, radius, true );

int knobRadius = radius / 7;

double th = nvalue * (2 * Math.PI) / (maxValue - minValue);

int x = (int)(Math.cos(th) * (radius - knobRadius * 3));

int y = (int)(Math.sin(th) * (radius - knobRadius * 3));

g2.setStroke(new BasicStroke(1));

draw3DCircle(g2, x + radius - knobRadius,

y + radius - knobRadius, knobRadius, false );

}

slide 13.39 Advanced Programming 2004

private void draw3DCircle(

Graphics g, int x, int y, int radius, boolean raised) {

Color foreground = getForeground();

Color light = foreground.brighter();

Color dark = foreground.darker();

g.setColor(foreground);

g.fillOval(x, y, radius * 2, radius * 2);

g.setColor(raised ? light : dark);

g.drawArc(x, y, radius * 2, radius * 2, 45, 180);

g.setColor(raised ? dark : light);

g.drawArc(x, y, radius * 2, radius * 2, 225, 180);

}

public Dimension getPreferredSize() {

return new Dimension(100, 100);

}

public void setValue( int value ) {

this.nvalue = value - minValue;

repaint();

fireEvent();

}

slide 13.40 Advanced Programming 2004

public int getValue() { return nvalue+minValue; }

public void setMinimum(int minValue){ this.minValue = minValue; }

public int getMinimum() { return minValue; }

public void setMaximum(int maxValue) {this.maxValue = maxValue; }

public int getMaximum() { return maxValue; }

//the variable listenerList is inherited from JComponent

public void addDialListener(DialListener listener) {

listenerList.add( DialListener.class, listener );

}

public void removeDialListener(DialListener listener) {

listenerList.remove( DialListener.class, listener );

}

void fireEvent() {

Object[] listeners = listenerList.getListenerList();

for ( int i = 0; i < listeners.length; i += 2 )

if ( listeners[i] == DialListener.class )

((DialListener)listeners[i + 1]).dialAdjusted(

new DialEvent(this, getValue()) );

}

slide 13.41 Advanced Programming 2004

public static void main(String[] args) {

JFrame frame = new JFrame("DialBean");

final JLabel statusLabel = new JLabel("Welcome to DialBean");

final Dial dial = new Dial();

frame.getContentPane().add(dial, BorderLayout.CENTER);

frame.getContentPane().add(statusLabel, BorderLayout.SOUTH);

dial.addDialListener(new DialListener() {

public void dialAdjusted(DialEvent e) {

statusLabel.setText("Value is " + e.getValue());

}

});

frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

frame.setSize( 150, 150 );

frame.setVisible( true );

}

}

slide 13.42 Advanced Programming 2004

File: beans/DialListener.java

package beans;

public interface DialListener extends

java.util.EventListener {

void dialAdjusted( DialEvent e );

}

slide 13.43 Advanced Programming 2004

File: beans/DialEvent.javapackage beans;

public class DialEvent extends

java.util.EventObject {

int value;

DialEvent( Dial source, int value ) {

super( source );

this.value = value;

}

public int getValue() {

return value;

}

}

slide 13.44 Advanced Programming 2004

Customizing with BeanInfo• The java.beans.Introspector class gathers information

on a bean using reflection, then analyzes and describes the bean to any tool that wants to know about it.

• The introspection process works only if the class follows the JavaBeans naming conventions. It gives us little control over exactly what properties and events appear in NetBeans menus.

• For example, by default, NetBeans shows all the stuff inherited from the base Swing component.

• We can change that by creating BeanInfo classes for our beans.

• A BeanInfo class provides the JavaBeans introspector with explicit information about the properties, methods, and events of a bean.

slide 13.45 Advanced Programming 2004

Customizing with BeanInfo (cont.)

• A BeanInfo class implements the BeanInfo interface.• But for simplicity, we can extend the SimpleBeanInfo

class, which implements all BeanInfo's methods. We can override specific methods to provide the information we want. When we don't override a method, we'll get the introspector's default behavior.

• As an example, we'll develop a DialBeanInfo class that provides explicit information about our Dial bean.

slide 13.46 Advanced Programming 2004

Getting Properties Information

• To describe the Dial's properties, we must implement the getPropertyDescriptors() method.

• This method simply returns an array of PropertyDescriptor objects, one for each property we want to publicize.

• To create a PropertyDescriptor, call its constructor with two arguments: the property's name and the class.

• A useful thing about DialBeanInfo is that by providing explicit information for our properties, we automatically hide other properties that introspection might find.

slide 13.47 Advanced Programming 2004

Getting Events Information

• The Dial bean defines its own event: the DialEvent.• We want to tell development tools about this event so

that we can build applications using it.• We add a method to the DialBeanInfo class called

getEventSetDescriptors(), which returns an array of EventSetDescriptors.

• Events are described in terms of their listener interfaces, not in terms of the event classes themselves.

• We create an EventSetDescriptor object: dial. The constructor takes four arguments: the class that generates the event, the name of the event, the listener class, and the name of the method to which the event can be delivered.

slide 13.48 Advanced Programming 2004

Supplying Icons

• In order to make NetBeans display our bean on the palette with a cute icon, we supply an icon by having the BeanInfo class implement the getIcon() method.

• We may supply up to four icons, with sizes of 16x16 or 32x32, in either color or monochrome.

slide 13.49 Advanced Programming 2004

File: beans/DialBeanInfo.javapackage beans;

import java.beans.*;

public class DialBeanInfo extends SimpleBeanInfo {

public PropertyDescriptor[] getPropertyDescriptors() {

try {

PropertyDescriptor value =

new PropertyDescriptor("value", Dial.class);

PropertyDescriptor minimum =

new PropertyDescriptor("minimum", Dial.class);

PropertyDescriptor maximum =

new PropertyDescriptor("maximum", Dial.class);

value.setBound(true);

minimum.setBound(false);

maximum.setBound(false);

return new PropertyDescriptor [] { value, minimum, maximum };

} catch (IntrospectionException e) { return null; }

}

slide 13.50 Advanced Programming 2004

public EventSetDescriptor[] getEventSetDescriptors() {

try {

EventSetDescriptor dial = new EventSetDescriptor( Dial.class,

"dialAdjusted", DialListener.class, "dialAdjusted");

dial.setDisplayName("Dial Adjusted");

EventSetDescriptor changed = new EventSetDescriptor(

Dial.class, "propertyChange",

PropertyChangeListener.class, "propertyChange" );

changed.setDisplayName("Bound property change");

return new EventSetDescriptor [] { dial, changed };

} catch (IntrospectionException e) { return null; }

}

slide 13.51 Advanced Programming 2004

public java.awt.Image getIcon(int iconKind) {

if (iconKind == BeanInfo.ICON_COLOR_16x16) {

return loadImage("DialIconColor16.gif");

} else

if (iconKind == BeanInfo.ICON_COLOR_32x32) {

return loadImage("DialIconColor32.gif");

} else

if (iconKind == BeanInfo.ICON_MONO_16x16) {

return loadImage("DialIconMono16.gif");

} else

if (iconKind == BeanInfo.ICON_MONO_32x32) {

return loadImage("DialIconMono32.gif");

}

return null;

}

} //end class DialBeanInfo