- Bean Construction Basics
- Designing a Bean
- Installing the BDK
- Testing Beans with the BeanBox Test Container
- Working with Beans in the BeanBox
- Wiring Beans Together with Events
- Saving Your Work
- Packaging Beans with JAR Files
This chapter begins a very hands-on part of the book in which you eventually learn how to develop your own beans. Even though you don't actually create any beans in this chapter, you learn all about the tools and techniques necessary to do so. By the end of this chapter, you will have all the information you need to begin constructing and using your own beans. So, if you are anxious to get started developing your own beans, just bear with me through this chapter and I promise you won't be let down throughout the rest of the book.
This chapter recaps the major parts of a bean and what types of decisions you need to make in terms of these parts when you are developing a new bean. With these design concepts out of the way, you move on and learn how to install and configure the Beans Development Kit (BDK). You then move on to possibly the most interesting topic of the chapter: the BeanBox. The BeanBox is a test container in which you can try out beans while you are developing them. You can use the BeanBox to easily test out all aspects of your beans, including visual property editing, event wiring, and bound property management. The chapter finishes off with a look at Java ARchive (JAR) files and how you use them to compress and group beans together for distribution.
You learn about the following major issues in this chapter:
- Bean design basics
- Installing the Beans Development Kit (BDK)
- Testing beans
- Packaging beans for distribution
Although beans typically are small development projects in terms of the sheer amount of code involved, the fact that they are reusable makes their initial design very critical. It's important for you to fully evaluate the functional requirements of a bean before you jump into writing code. Of course, this is good wisdom to apply to any programming situation, but it is especially important in JavaBeans because of the nature of bean components and how they are used. For example, the very fact that a bean must be backwardly compatible as it evolves is reason enough to make sure that the interfaces you define are extensible enough to provide room for future functionality.
The planning process you go through when you initially design a bean will pay off in many ways when it comes down to first developing the bean as well as maintaining the bean in the future. Too many programmers fall victim to the urge to get an object working in a hurry without thinking of the larger picture in which it will be used. Even though this narrow-minded approach can work in some limited environments with a certain degree of success, it must be strictly avoided when it comes to JavaBeans. Trying to hack together a bean in a hurry when the overall aim is to make beans widely reusable in a variety of different ways simply isn't smart.
Stepping down from my soap box, let me now soften the tone and add that the initial
design phase for a typical bean isn't very involved. Beans usually are such small
pieces of software that they just don't warrant a large or complex design. Furthermore,
because beans are geared toward being simple and
minimal at the very core, it only makes sense that bean developers should carry on with this tradition in the design of beans at a higher level. All I'm really suggesting is that you spend a little time pondering what exactly your bean is going to accomplish, along with how it will be practically used and in what ways it might evolve in the future. Just so you get the idea, let me break these three ideas down as questions to ask yourself while you are designing a bean.
- 1. What does the bean do?
2. How is the bean used?
3. How might the bean change in the future?
The first question might be the easiest to answer because it is probably the question that drove you to design a bean in the first place. Even so, it's important to clearly identify what the bean is going to accomplish as a piece of reusable software. The second question also is fairly straightforward because you probably already have an application in mind that could use your bean. You might even be developing a bean as a specific part of an application, in which case you decided on making it a bean so that you would have the option of reusing it in other projects. Regardless of the motives that drove you to develop your bean, make sure you have a good idea of how the bean is going to be used by an end user, whether that user is yourself or thousands of developers who are going to buy your bean for use in their own projects.
The third and final question is the one you probably haven't given much thought to because most people tend to think in terms of the present and what problems need to be addressed immediately. However, a little insight on the front end of a bean development effort can make things infinitely easier for you later when the inevitable time comes that you want to add a new feature or alter an old one. Try to assess any potential features or changes you might see as being possible in the future, along with how they impact the bean in its current state. You might see that a small concession in an initial design might leave the door open for future enhancements. On the other hand, you might decide that you are content that your bean is fine for your purposes and that it will never need to evolve. That's a perfectly acceptable attitude to have as long as you understand that it limits your options in the future. How far you want to go in trying to assess the future direction of a bean is ultimately up to you. All I can do is encourage you to at least entertain the thought of making a bean more open for future modification.
NOTE: I personally know that I'm sometimes fickle and short-sighted enough that I feel better with a design that is very extensible. I like the idea of knowing that decisions I make today are open for change in the future just in case I manage to figure out a better way of doing things. This attitude is actually useful far beyond the realm of programming and JavaBeans, but that's another book!
Now that I've grilled you a little about approaching bean development with at least a minimal amount of planning, it's time to move on to some specifics. The design of a bean ultimately should culminate in a detailed description of the various parts of a bean. The rest of this section is devoted to the design issues surrounding the three primary parts of a bean, which follow:
The heart of a bean is its internal state. Similar to normal Java classes, the internal state of a bean is reflected by the bean's member variables. Properties are public member variables that are accessible externally. Even though all member variables are important to a bean's functionality, properties take on a more critical importance because they enable you to query a bean for information or modify a bean's state from outside the bean. Of course, you are never allowed to directly read or write properties externally; you must always do so through accessor methods.
Even if you aren't sure about all the data your bean will need to function properly,
you should make a solid attempt to define all of the bean's properties during the
initial design. Trust me, this isn't asking too much. Properties are usually fairly
easy to determine because they often directly relate to a piece of functionality.
For example, it's pretty obvious that a button bean would need a property representing
the label that is drawn on the button. Furthermore, you could define properties for
the background and foreground colors of the
When you lay out the properties for your bean, be sure to decide whether the property is read-only, write-only, or read/write, because it will impact the accessor methods you have to implement later. Again, this should be a very simple and straightforward task because you've no doubt already thought about the characteristics of the bean that map to properties. You should also decide at this point if any of the properties are bound or constrained, because this will also impact methods you must implement later.
Although defining properties is an important step in the design of a bean, it is by no means something that you can't go back and change later. It might turn out that you will think of some more properties for the bean later based on some new functionality you want to add. By all means, feel free to add or modify the properties of your bean while you are coding. I'm mainly just trying to encourage you to think about a core set of properties to begin with, because they will become the first member variables you define when you begin to code.
After you've determined a set of suitable bean properties, you are ready to decide on some methods that interact with them. Similar to properties, at this point you should focus on the public methods that are going to be accessible outside of the bean. If you happen to already have an idea about non-public methods, feel free to go ahead and make note of them, just don't feel like you have to worry about them just yet. The primary goal is to define the public interface that will be used to access your bean, which is determined by the public methods implemented by the bean.
The first place to start when you are defining public methods is with accessor methods, which enable you to read and write the values of properties. Because you've already defined the properties for the bean, defining accessor methods is a simple task of listing getter and setter methods for each property based on its read/write capabilities. Keep in mind that these methods form the only direct link between a user and your bean's properties.
After you've established your bean's accessor methods, you need to check and see whether any of the bean's properties are bound or constrained. If so, you need to add methods for registering and removing appropriate bound and constrained listeners. This is very straightforward because these methods come in pairs and conform to a strict design pattern.
After the property-related methods are squared away, you need to assess other public methods needed by your bean. These methods are entirely bean dependent, so deciding what other public methods are required of your bean is totally up to you. Typically, public non-accessor methods are used to perform some type of more involved function, as opposed to the simple getting and setting of properties performed by accessor methods. For example, you might have a bean that performs some type of complex calculation that impacts a variety of properties. You obviously would want this functionality available externally, so you would place it in a public method.
Keep in mind that the constructors for your bean should also be defined at this stage. You are free to provide as many or as few constructors as you want; just remember that it's often nice to give users a variety of constructors that use default values for some properties and require less explicit information.
The last major design area you need to assess is events. In terms of bean design there are two different ways that events come into play. The first has to do with the events that a bean is capable of firing. The functionality of a bean determines the types of events it is capable of firing. Your bean can fire standard events defined in the Java API, or you can choose to define your own custom events and go from there. In the latter case, remember that you will need to implement a class for each type of custom event you are going to use. Regardless of whether you decide on standard events, custom events, or a mixture of the two, the next step is to define the registration methods for listeners of each type. These methods are very similar to the methods defined for bound and constrained property listeners because they conform to similar design patterns.
The second way in which events come into play when you are designing beans relates to events that a bean handles for itself. For example, a button bean would need to catch and respond to mouse clicks, focus changes, and some key presses. These are the types of things you should decide up front how to handle so you will have less surprises when you start coding. The events processed by a bean basically result in overriding methods that handle different groups of events. Because most of your beans will be derived from an AWT class such as Canvas, these event processor methods will simply be overridden in your bean class. Even so, go ahead and try to determine which ones you plan on overriding and why.
After you have carefully designed the three major parts of your bean, you are ready to start actually building the bean. Although the initial design work isn't always the most thrilling part of bean development, it will pay huge dividends when you begin coding. For example, you should be able to put together a pretty solid skeletal bean based on the properties and methods just covered. In other words, by merely defining properties and creating empty methods for the methods you listed in the design of the bean, you will have a pretty good start on your bean class.
With a skeletal bean class in hand, you are ready to push on to the meat of JavaBeans development. Unfortunately, you'll have to wait until the next chapter to get into the details. However, the rest of this chapter covers some critical tool-related issues that are necessities for practical bean development.
Turning a bean design into reality wouldn't be possible without the Beans Development Kit (BDK), which is freely available from JavaSoft. You can download the latest version of the BDK from JavaSoft's Web site at http://www.javasoft.com. The BDK comes complete with all the classes and documentation necessary to create and test your own beans. Please note that the BDK requires the Java Developer's Kit (JDK) version 1.1 or later, which provides all the core Java functionality used by JavaBeans.
NOTE: The BDK for Windows 95/NT and Solaris 2.4 and 2.5 and JDK for Windows, Solaris, and Macintosh are included on the CD-ROM accompanying this book. Even so, you might want to check JavaSoft's Web site to ensure that you have the very latest version. Development kits like these tend to evolve very rapidly, so new versions are released periodically.
The custom beans about which you learn in this book were developed using a beta version of the BDK, which has a few caveats in regard to how it must be installed. Because of these subtle installation details, I felt compelled to at least describe how I installed the JDK and BDK so that they work together seamlessly for bean development. Again, you can download both of these development kits for free directly from JavaSoft's Web site.
First, it's important that you install the JDK before the BDK because it has all the core support required of the BDK. Although you are free to install the JDK however you choose, I recommend creating a jdk directory just below your root directory. Copy the JDK installation executable to this directory and execute it to install the JDK. The JDK will expand into a java directory beneath the jdk directory you created.
After you install the JDK, you are ready to install the BDK. Copy the BDK installation executable to the top-level jdk directory just as you did with the JDK, and then execute it to install the BDK. Similar to the JDK installation, the BDK will expand into a beans directory beneath the jdk directory.
NOTE: When you are finished installing the JDK and BDK, be sure to delete the setup files used for the installation of each. These files are not cleaned up automatically and must be manually deleted.
After you install the JDK and BDK, you should have a directory structure just
like the one shown in
Figure 9.1. The
directory structure for the JDK and BDK installations.
his directory structure is by no means a strict requirement for JavaBeans development, but it is consistent and has worked well for me. The consistency comes from the fact that the JDK and BDK are separate development kits for Java, which implies that they should reside at a similar level hierarchically. By creating a common jdk directory and installing different development kits below this directory, you have a very clear picture of how the development kits relate to each other.
As you've learned throughout the book thus far, one of the key benefits of JavaBeans is the capability for beans to be used in visual application builder tools. You've learned a great deal about the inner workings of JavaBeans that make this type of functionality possible, and now it's time to see it all in action and learn how to work with JavaBeans in a visual environment. The BDK ships with a test container called the BeanBox that enables you to lay out, edit, and interconnect beans visually. The BeanBox isn't intended to be a fully functional development tool for creating applications with beans, but instead is intended to provide a simple example of how beans can be manipulated visually. Even so, the BeanBox is an indispensable tool for bean development because it provides a simple test bed for trying out beans.
The BeanBox is a stand-alone application that is executed using the JDK interpreter. Rather than running it directly using the interpreter, however, the BeanBox comes with a batch file, run.bat, which is in the BDK's beanbox directory and is responsible for setting the CLASSPATH environment variable before executing. You should use this batch file to run the BeanBox because it sets CLASSPATH to values that are specific to using the BeanBox. Following are the contents of the run.bat batch file used to execute the BeanBox:
set CLASSPATH=../classes;classes;unjar java sun.beanbox.BeanBoxFrame
As you can see, the batch file first sets CLASSPATH to a few different paths, and then it executes the BeanBox within the JDK interpreter. Don't worry too much about the CLASSPATH settings, because they are based on the internal workings of the BeanBox. To run the BeanBox, just execute the run batch file. When you run the batch file, the BeanBox will execute and display three different windows. Each of these windows performs a different function within the scope of the BeanBox. The first window is the ToolBox, which lists all the beans registered for use with the BeanBox. Figure 9.2 shows the BeanBox's ToolBox window.
9.2. The BeanBox's ToolBox window.
As you can see, the ToolBox lists a variety of different available beans. These beans are all demo beans provided with the BDK to demonstrate the development and use of beans. Notice that some of the beans have graphical icons associated with them. These beans use a bean information class to specify the icon to be displayed in visual development environments. Other beans are listed in the ToolBox by name only.
The second window associated with the BeanBox is the main container window, which is shown in Figure 9.3.
9.3. The BeanBox's main container window.
The main container window is the central BeanBox window because it is where you actually lay out beans. The main container window is very similar in function to form windows in other types of visual development environments such as Visual Basic. This window has two menu items, File and Edit, which enable you to load and save BeanBox files and connect beans together.
The last window in the BeanBox is the PropertySheet window, which lists the properties associated with the currently selected bean. Figure 9.4 shows how the PropertySheet window looks.
9.4. The BeanBox's PropertySheet window.
This window is responsible for providing the visual editing capabilities of the BeanBox because it displays a property editor for each property defined in a bean. When you first run the BeanBox, the PropertySheet window displays the properties for the BeanBox container itself. You can try to edit these properties by clicking one of them with the mouse. For example, try clicking the background property to change the background color for the container. Figure 9.5 shows the property editor dialog box displayed for changing the background color.
9.5. The property editor dialog box for the
background color property.
This property editor dialog box enables you to easily change the background color for the container by either entering RGB (Red, Green, Blue) colors or by selecting a standard color from a drop-down list. Try selecting a different color and clicking Done to see how it affects the container.
NOTE: For beans that have an associated customizer, the Edit menu in the BeanBox provides a Customize command that runs the customizer on the bean.
Working with beans in the BeanBox is very simple and demonstrates the real benefit of visual editing with beans. The first thing you do is select a bean from the ToolBox and add it to the main container window. You do this by clicking a bean's name or icon in the ToolBox window, which turns the mouse pointer into a cross. You then click the container window in the location where you want the bean to be placed. A new bean will appear in the location with a default size and set of properties.
Try laying out one of the demo beans that comes with the BDK. Click the OurButton bean in the ToolBox window, and then click somewhere in the container window to place the bean. After you do this, the container window should look similar to Figure 9.6.
9.6. The main container window after adding
an OurButton bean to the BeanBox.
Notice that the new bean is drawn with a hashed boundary. This indicates that the bean is the currently selected bean, which means that the PropertySheet window reflects the properties for this bean. Beans are selected by default when you add them to the container window. To select a bean that isn't selected, just click outside of the bean in the area where the hashed boundary is to appear. Some beans enable you to click anywhere on them to select them, but in the beta version of the BDK this behavior is somewhat inconsistent. The version of the BeanBox in the final release of the BDK will no doubt be more robust.
You're going to be using the OurButton bean you just laid out to control an animation bean in a moment, but first you need to change its label property. You accomplish this through the PropertySheet window, where you must change the bean's label property to Start Animation. Now you need to add one more OurButton bean, so follow the same steps you just went through by clicking the bean in the ToolBox and positioning it in the container. Then edit its label property and set the value to Stop Animation. After you've done this, the container window should look similar to Figure 9.7.
9.7. The main container window after adding
both OurButton beans to the BeanBox.
Now it's time to throw in a little excitement by adding a bean that displays an animation. Select the Juggler bean from the ToolBox and add it to the container just below the OurButton beans. After you've done this, the container window should look similar to Figure 9.8.
Figure 9.8. The main container window after adding a Juggler bean to
If your beans aren't quite lined up the way they are in the figure, feel free to move them around. You can do this by selecting one of the beans, clicking the hashed border, and holding down the button while you drag the mouse. This enables you to move the bean around in the container. You also can resize beans that support resizing by clicking in one of the corners on the hashed border and dragging the mouse. There is no need to resize any of the beans in this example because they automatically size themselves to fit their content.
A particularly useful function of the BeanBox is wiring beans together using events. For example, you can easily connect a bean's event to a public method defined in another bean, which effectively ties the two beans together functionally. The BeanBox enables you to do this visually, which makes the task very simple. As you might guess, the two buttons you've laid out thus far are perfectly situated to control the Juggler animation bean. So, let's go ahead and wire them up to see what happens.
Select the first OurButton bean and click the Edit menu in the BeanBox. You'll see an Events menu item that has a group of event types beneath it. Select the action event menu item and then the actionPerformed command beneath it. You'll see a line originating from the button that moves as you move the mouse around. Move the mouse over the Juggler bean and click to connect the button bean's action event to the Juggler bean. You'll be presented with a dialog box that shows the available target methods defined in the Juggler bean. Figure 9.9 shows this dialog box.
9.9. The EventTargetDialog box for the Juggler
bean. Select the start() method from the dialog box to signify it as the
receiver of the event action.
When you do this, the start() method is called on the Juggler bean any time the first OurButton bean is pressed. Repeat this procedure to connect the second OurButton bean to the stop() method of the Juggler bean. After you do this, you can test the buttons by clicking them to start and stop the animating Juggler bean. It's as simple as that!
NOTE: It's worth noting that the version of the BeanBox available as of this writing (beta 3) is a little tricky to use at times. The selection of beans tends to be inconsistent at times, occasionally resulting in the addition of a new bean when you really wanted to select an existing bean. I think it's safe to assume that the final version of the BeanBox will be much more robust.
You can easily save the contents of the BeanBox using the Save command in the File menu. When you save the contents of the BeanBox, the persistence features of JavaBeans are used to store the state of each bean. You then can reload the beans later using the Load command, in which case the persistence features are used to reconstruct the beans just as you left them.
After you have developed and tested your bean, you have to consider packaging it so others can use it. Things aren't so simple as the good old days of Java 1.0 where you could just provide executable class files and everyone would be happy. The standard method of distributing beans involves packaging them into compressed archives called JAR (Java ARchive) files. JAR files are similar to other types of compressed files such as ZIP files or TAR files, except they are specifically tailored around packaging Java classes and resources.
NOTE: JAR files use a compression scheme based on the one used in ZIP files. Check out the java.util.zip package in the JDK 1.1 documentation for more information.
JAR files basically enable you to group the classes and resources for beans into one compressed unit to organize them and conserve space. Bean resources can include anything from images and sounds to custom resources such as data files. Being able to group resources with the classes for a bean cleans up the delivery of beans considerably because it eliminates the chore of keeping up with a bunch of different support files. Additionally, having a single file for beans being delivered over an Internet connection results in only one HTTP transaction, which is much faster than transferring multiple individual files.
Just in case you are thinking maybe you don't need to worry about bundling your bean in a JAR file, understand that most visual development tools expect beans to be included in JAR files. The BeanBox is an example of such a tool because it strictly looks for JAR files when it assembles the beans in its ToolBox. You might be wondering how a tool such as the BeanBox knows what beans are included in a JAR file, because JAR files ultimately are just a bunch of classes and associated resources. The answer to this question is found in manifest files, which are text files that describe the beans contained in a JAR file, along with encryption information if so desired. The encryption information is used for code signing purposes, which is another whole topic beyond the scope of this chapter. You learn more about bean security and code signing in Chapter 15, "Advanced JavaBeans." You learn more about manifest files in the next chapter when you build your first custom bean.
NOTE: JAR files are capable of storing multiple beans. Just as with individual beans, the manifest file is responsible for formally listing all the beans contained in a JAR file.
Version 1.1 of the JDK ships with a tool called jar that enables you to create and modify JAR files. It works similar to PKZip or tar in that it enables you to combine and compress multiple files into a single archive. The jar utility also enables you to sign individual files in a JAR file for security purposes. The syntax for jar follows:
jar Options Files
The Files argument specifies the files to be used when working with a
JAR file and varies according to the options. The Options argument specifies
options related to how the jar utility manipulates a JAR file. Following is a list of the jar utility options:
- c--Specifies that a new archive is to be created.
- --Specifies that the manifest file for the archive is to be created based on
an external manifest file. The external manifest file is provided as the second file
in the list of files following the options.
- --Used to list the contents of an archive.
- File--Extracts all the files in an archive, or just the named files if additional
files are provided.
- --Used to specify the name of the archive in question, where the name is provided
as the first file in the file list. The f option is used in conjunction
with all the other options.
- --Causes the jar utility to provide verbose output, which results in greater information about what actions are being performed on a JAR file.
CAUTION: Unlike most command-line utilities, the jar utility doesn't require the use of a / or - when specifying options.
So you can see how the jar utility works in a practical scenario, following is a jar command that compresses and adds all the Java classes in the current directory into a JAR file called BigStuff:
jar cf BigStuff.jar *.class
In this example, the c and f options are used to specify that a new archive is to be created with the name BigStuff.jar. The files to be added to the archive are specified by the wildcard *.class. As you can see, there's nothing complicated about JAR files. Granted, it gets a little messier when you start dealing with code signing, but you don't have to worry with any of that at this point.
This chapter took a sharp turn from the first two parts of the book by tackling some practical issues concerning bean development. You first learned about initial design issues relating to beans, including the importance of carefully defining the different parts of a bean before you write any code. You then moved on to the installation of the Beans Development Kit (BDK), which has a few caveats that must be dealt with in order for things to work smoothly. From there, you dove straight into visual bean manipulation with the BeanBox test container. The BeanBox is perhaps the most significant tool provided by the BDK because it enables you to test the capabilities of your beans in a minimal environment. Finally, you ended the chapter with a look at JAR (Java ARchive) files, which enable you to compress the classes and resources for a bean into a single file for distribution.
This chapter covered a variety of different topics to prepare you for developing your own beans from scratch. You now are ready to get into the specifics of building your own beans and testing them, which is ultimately the most fun part of this book if you like to see things in action. Sure, concepts and theories are great, but at some point you want to see something real. The next chapter takes you through the design and development of a complete bean, which will put much of your newfound knowledge to the test and enable you to have some fun along the way.