Advanced Bean programming is about customization. Beans can be customized in two senses. In both cases, you provide a basic behavior for a Bean and allow its specific behavior to be controlled by end users who interact with the Bean, typically through application builder tools. A Bean can be customized for a specific application either programmatically, through Java code, or visually, through GUI interfaces hosted by application builder tools. In the latter case, you can provide customized dialog boxes and editing tools with sophisticated controls. Such customization tools would be packaged as part of the Bean.
The Bean thus becomes a set of classes, including the Bean proper, as well as other classes that provide a clean, simple, and intuitive interface through which end users can specify precise Bean behavior in applications. Once you've worked through the examples in this segment, you'll have a solid understanding of Beans and will be well on your way to building reusable software components that others will want to use in their programs.
In this concluding segment to the JavaBeans Tutorial, you'll write more
advanced Beans. You'll see how to convert old applets and JDKTM 1.0 programs
to Beans. You'll learn about the AWT delegation event model; how Beans
can notify other objects about change events; and see how reflection and
introspection let you customize the behavior and presentation of your Beans.
Converting Existing Code to
Beans
Got some old code you'd like to update? Have a look at how it's done
with the NervousText example program that's been distributed with the JDK.
All AWT components in JDK 1.1 are Beans. This means they are already set up to be used as reusable components in builder tools. However, older JDK 1.0 programs and some JDK 1.1 demo programs are not built as Beans. This lesson describes how to convert existing programs and applets into Beans.
You'll start by taking the NervousText sample applet and turning it into a Bean. You can look at this file in the JDK 1.1 distribution tree under the directory demo/NervousText.
There are several advantages to learning about Beans by converting existing programs. First, you'll be able to concentrate on the parts of the program or applet that are unique to Beans. Second, by working on a familar example program that is somewhat typical of other programs you may need to convert, you will see the Beans features you need to learn first.
The concepts introduced include:
•Reflection
•Event Handling
•Bean Customization
Start by taking a look at the existing JDK 1.1 code for the NervousText.java. As you may already know, this applet displays jittering text on the screen, giving the impression that the text has had a little too much coffee this morning. The JDK 1.1 version of NervousText will be the starting point of reference from which subsequent changes in this lesson will be made.
The next section, Making NervousText into a Bean, contains the steps to make the conversion.
Making NervousText into a Bean
The following steps can easily be adapted to converting any Java program
or applet into a Bean.
Step 1. Select program to convert
First, select a demo applet or class to convert to a Bean. For this
particular example, you'll be using NervousText.
Step 2. Change applets to standalone Window
objects
While it's possible to make applets into Beans, it's a little easier
to convert standalone Window objects or components. To see an example of
an applet that is a Bean, look at the source code for the Juggler Bean
distributed with the Beans Development Toolkit (BDK).
To change NervousText into a standalone window object, edit the line
declaring the NervousText class. In the JDK 1.1 distribution, it reads
public
class NervousText extends java.applet.Applet
implements Runnable {
Instead of making NervousText a subclass of Applet, make it a subclass of Panel:
public class NervousText extends Panel implements Runnable {
Step 3. Add AWT and Beans import and package
statements
Add the following important statement after import java.awt.Font;:
import java.awt.*;
There are many ways to bundle a Bean to be loaded into the BeanBox, or to be loaded by other builder tools. The most effective way to manage the different Beans you'll be creating is to define them to be part of a package, and then build a JAR file based on the directory structure implicitly defined by the package name.
Since you're going to be testing the various versions of the NervousText Bean in the BeanBox, you'll need to add a package statement indicating the location of the Java class files that make up the Bean. The package reflects the subsystem where you plan to store your class files locally, and not necessarily where the BeanBox expects to find the actual class files. Once you have bundled the set of classes making up a Bean in a JAR file, you can place the JAR file in the default location where the BeanBox looks for JAR files when the BeanBox is initialized. The demo Beans for the NervousText example Beans in this lesson are declared as part of the sun.beanbox.beans package.
You could define your own package and corresponding subdirectories, but it's convenient to use this package. Add the following package statement before the first import statement, import java.awt.Graphics;:
package sun.beanbox.beans;
The beginning of the file should now look like this:
package sun.beanbox.beans;
import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Font;
import java.awt.*;
public class NervousText01
extends Panel implements
Runnable, MouseListener {
...
Step 4. Add a constructor
When converting applets to Window objects, you no longer need the init
method, but you will need a constructor, if one is not already defined.
In the case of NervousText, you can change the line declaring the init
method to a constructor, by renaming the method and removing the return
type from the method declaration. Change:
public void init() {
to:
public NervousText() {
The constructor now looks like this
public NervousText()
{
addMouseListener(this);
s = getParameter("text");
if (s == null) {
s = "HotJava";
}
separated = new char [s.length()];
s.getChars(0,s.length(),separated,0);
resize((s.length()+1)*15, 50);
setFont(new Font("TimesRoman",Font.BOLD,36));
}
Step 5. Adapt applet parameters
Since NervousText is no longer an applet, it can't call getParameter
to get the text it is going to display. In some cases you'll have to add
a line or two to hard code parameters that were formerly passed to applets.
In the case of NervousText, you'll see a conditional test that hard codes
the text displayed in the event that a parameter argument is not supplied.
if (s == null) {
s = "HotJava";
}
By commenting out the line immediately preceding this, you'll assure that the value of s is always set to "HotJava".
public void init() {
...
// s = getParameter("text");
if (s == null)
{
s = "HotJava";
}
...
}
Step 6. Start the component's thread
When NervousText was an applet, its start method was called automatically
by the browser (or appletviewer) whenever a page referencing the applet
was loaded. The start method invokes the primary thread for the applet
or, in this case, the Window Object. You'll have to call start manually
to set its thread running
Add the following line at the end of constructor NervousText, just after setFont statement.
start();
The constuctor should now look like this:
public NervousText01()
{
addMouseListener(this);
// s = getParameter("text");
if (s == null) {
//s = "HotJava";
s = "Nervous bean";
}
separated = new char [s.length()];
s.getChars(0,s.length(),separated,0);
resize((s.length()+1)*15, 50);
setFont(new Font("TimesRoman",Font.BOLD,36));
start();
}
Step 7. Add properties and support for introspection
It would be nice if users of the NervousText Bean could customize the
text it displays when they are building new applications. You can enable
builder tools to give users the option to change the text displayed by
NervousText by adding a text property. Adding the methods getText and setText
allows you to change the String value of the jittering text. Add these
methods after the NervousText constructor.
public void setText(String
newstring){
s=new String(newstring);
separated= new char[s.length()];
s.getChars(0,s.length(),separated,0);
}
public String getText(){
return(s);
}
Step 8. Define preferred size and minimum
Size for the Bean
Strictly speaking, you do not need to define both preferredSize and
minimumSize call back methods for the Bean. If these methods are defined,
builder tools (such as the BeanBox) will call them to determine how the
Bean should be drawn. Add a preferredSize method to indicate the initalial
size of the Bean. The difference between preferredSize and minimumSize
is that if minimumSize is defined and preferredSize is not, the size of
the Bean can be changed later on inside the builder tool. If preferredSize
is set, the Bean will remain a fixed size. You'll see an example version
of NervousText using minimumSize later in the lesson.
The Bean's preferredSize is called from the BeanBox at the time a user selects the Bean from the menu of available Beans to be placed in the top-level container.
Add the following preferredSize code after the gettext method that you just added.
public Dimension preferredSize() {
return (new Dimension(150,150));
}
Step 9. Remove extraneous event handlers
Some event-handler routines that make sense for applets, no longer
make sense once the applet is turned into a Bean. Within NervousText, comment
out the mouseDown action event handler as it will interfere with the operation
of the BeanBox.
public void mousePressed(MouseEvent
e) {
/*
e.consume();
if (threadSuspended)
{
killme.resume();
}
else {
killme.suspend();
}
threadSuspended
= !threadSuspended;
*/
}
Now the mouse-down handler is defined, but it no longer performs any action. Specifically, a mouse-down event no longer kills the thread and stops the nervous text from jittering.
Step 10. Test the Bean in the BeanBox
You can now add the NervousText component from the Toolbox into the
panel and change the text parameter in the PropertySheet automatically
associated with the Bean by the builder tool.
If you have a full Beans-enabled development environment, such as JBuilder,
or Mojo, you can test your Bean using them. If not, you can use the BeanBox.
When using the BeanBox, it is easiest to package the Bean as a JAR (Java
Archive File) and then load the JAR into the BeanBox. To do this you have
to use a manifest file to define the contents of the JAR so the BeanBox
or builder tool knows how to use each of the files contained in the JAR.
For example, the following commands will create a temporary manifest file,
which can be used to build a JAR file.
echo "Manifest-Version:
1.0" > manifest.tmp
echo "" >> manifest.tmp
echo "Name: sun/beanbox/beans/NervousText01.class"
>> manifest.tmp
echo "Java-bean:
True" >> manifest.tmp
jar cfm NervousText01.jar
manifest.tmp
sun/beanbox/beans/NervousText01.class
/bin/rm manifest.tmp
cp -p NervousText01.jar
/home_gvoss/work97/06/bdk/beans/jars
The resulting manifest file looks like this:
Manifest-Version: 1.0
Name: sun/beanbox/beans/NervousText01.class
Java-bean: True
This manifest indicates the JAR contains a single Java class file, NervousText01.class which is a Bean. You know that the class is a Bean because of the following line in the manifest:
Java-bean: True
Assuming you have installed the Beans Development Kit (BDK) in a directory defined as BDK_HOME, the BeanBox will look in a directory called BDK_HOME/beans/jars for the JARS defining the initial Beans it will display in its Bean menu.
Compile the source with the -d flag to make sure classes are placed in the proper subdirectories for the package.
javac -d . NervousText01.java
The dot following the -d flag indicates the the package root is the
current directory. The class file for the package sun.Beanbox.beans will
be created in the ./sun/beanbox/beans directory. When the class is compiled
and the manifest is created, build the the JAR as follows.
jar
cfm NervousText01.jar manifest.tmp
sun/beanbox/beans/NervousText01.class
You can now remove the temporary manifest file and copy the JAR file to the JAR directory for the BeanBox.
rm manifest.tmp
cp -p NervousText01.jar
BDK_HOME/beans/jars
After copying the JAR file to the BeanBox jars directory, you can start the BeanBox and NervousText01 will appear in the menu of available Beans.
Program Source Code
The makefile for this lesson automates source code compilation, JAR
file construction, and copying of JAR files to the appropriate BeanBox
directory. You'll have to edit several of the variables in the makefile
to indicate the location of your JDK 1.1 and BDK installation directories.
You may want to look at the final source file for NervousText Bean, Version 01 to verify the changes you have made to the original NervousText.java file.