by Mark Johnson

A fistful of values

how-to
Nov 1, 199830 mins

Add indexed properties and complex property editors to your JavaBeans

If you’re a JavaBeans developer, you already know that a JavaBeans property is a named access to part of the internal state of a JavaBean. (If you don’t know about properties, read all about them in my previous JavaBeans column, “Double Shot, Half Decaf, Skinny Latte — Customize your Java,” listed in this column’s Resources.) You also know that a property editor can be used to configure and/or customize JavaBeans at design time. (To get up to speed on property editors and customization, check out “The trick to controlling bean customization” and “Soup up your Java classes with customization,” also listed in the Resources section.)

What you may not know is that JavaBeans properties are not limited to scalar (that is, single-valued) values. A JavaBeans property can also be an array of values, accessed by an integer index, called an indexed property.

This month, we’re going to tackle creating a shiny new JavaBean with an indexed property, and a custom property editor that allows the developer to manipulate the indexed property at design time. We’ll start by creating a basic URLFileLoader bean that downloads a file from an arbitrary URL on the Web, and stores it in a disk file on demand (taking a quick side excursion into boolean properties, a simple property type). Then we’ll improve the URLFileLoader class loader, enabling it to fetch files using HTTP GET with parameters maintained by a new indexed property. (We’ll go over GET later on in the text.) Next, we’ll create a custom editor (so we can access the property graphically), and see how to specify this custom editor with the builder tool (in our case, Sun’s BeanBox.) We’ll wrap up with a discussion of possible extensions to this project.

Index property backgrounder

Before we dive into creating a property editor for an indexed property, let’s have a look at why indexed properties are useful.

As noted above, an indexed property is nothing more than a JavaBeans property whose value is an integer-indexed array, instead of being a single scalar value like a String or an int. For example, a RelationalTable bean might have a property called Columns that returns an array of Column objects that describe the table’s columns. A ScatterPlot bean could have a property called DataPoints, itself being an array of DataPoint objects that the bean displays. A SpreadSheet bean could have two properties: Rows, which manipulates a list of Column objects, and Columns, which manipulates a list of Row objects. Each Row (or Column) object could itself be a bean with an indexed property called Cells, an array of Cell objects.

Indexed properties provide enormous flexibility to JavaBeans. Implementing them can be confusing, though, as some of my e-mail from readers attests. I own five books on JavaBeans, and most explain what indexed properties are, but none provides sample code for an indexed property editor. This was mostly because the BeanBox, the standard JavaBeans test container, didn’t support indexed property editors until quite recently. (For more on the BeanBox, see the links in Resources.)

An HTTP file loader bean

For a tutorial example of creating a bean with indexed properties, let’s start with a simple bean: the URLFileLoader. We’ll first go over the requirements of this new class, and then extend it to include an indexed property and its associated editor.

Requirements

Let’s start by describing our new component’s requirements in terms of functionality and properties. In the following description, note that the properties we define are italicized.

On request, the URLFileLoader JavaBean fetches the content of a particular URL on the Web using the HTTP protocol. It stores the content it receives in a file in a directory on a local disk. By the way, this bean is intended to be used in Java applications, not with applets, as it accesses both the filesystem and the network. Also, it optionally communicates through a firewall proxy, which listens at a specific port number. (If you don’t know what a firewall is exactly, see the introductory article link to the World Wide Web Security FAQ in the Resources section below.)

All the terms italicized above are bean attributes a user (meaning an application developer) may want to control at design or runtime. Developers do this by accessing the bean via the properties we define for it, which appear in the following table:

PropertyTypeDescription
URLStringThe URL to load from the Web
FileStringThe file in which to store the received content
DirStringThe directory in which to create the file
UseFirewallboolean (!)Whether or not to connect through a firewall
FirewallStringFirewall name
PortintThe port number of the firewall http proxy

Figure 2. URLFileLoader properties

The above properties customize the bean to get information from a certain place, storing it in a certain other place, optionally doing it a certain way. In short, customization is the use of properties to define what all of those “certain” things are.

Now that we’ve defined what the bean is going to do, let’s define how it does it.

Implementation

I’ve chosen to implement URLFileLoader as a subclass of an abstract base class, because I know that eventually I’m going to extend that base class to handle other kinds of URL storing. Regardless of how the data is accessed, there are three basic steps to fetching and storing a file with HTTP:

  1. Open a connection to the remote server
  2. Download and save the content
  3. Close the connection

Somewhere in there, I also have to specify what to do if there’s a firewall in the way. These are abstract operations; in other words, saying “connect to a server” does nothing about how that connection is made. Of course, if any particular operation (such as downloading and saving content from an open connection) has a reasonable default implementation, it makes sense to put it in the base class and let subclasses inherit and reuse it.

But when subclasses differ in how they implement abstract operations, the base class simply defines the signature (name, return type, and argument number and types) of the method, and then tags it with the abstract keyword. Java won’t allow creation of an instance of a class that contains an abstract method declaration, so any subclass of an abstract base class must either define an implementation of every abstract method in all of its superclasses, or end up being abstract itself. There’s no way to say “don’t inherit” a method from a parent.

I’m planning to create at least two classes: one that gets files from Web sites via HTTP (URLFileLoader) and one that fetches contents from Web sites that require HTTP GET parameters. You also might imagine another bean that downloads the result of HTTP POST, or another bean that transfers files via FTP. All these beans can be implementations of the abstract operations open connection, transfer data and store, and close connection, differing only in how they implement those operations.

In the text box below, you’ll find the source for abstract class URLLoader.

Figure 3. URLLoader.java

The URLLoader.java class has accessor methods for all the properties described in Figure 2, as well as the following operations:

MethodTypeDescription
setupFirewall()protected voidIf using a firewall, set up Java environment to access HTTP connections through a proxy.
fetchContent()public voidGet the content from the URL and store it in the file.
execute()public voidOpen the connection to the data source, fetch and store the contents, and close the connection.
openConnection()public abstract voidOpen a connection to the URL.
closeConnection()public abstract voidClose the open connection.

Figure 4. Operations of the abstract class URLLoader

These operations provide a basis for implementing subclasses that get files from the Web. Notice that only two of the methods, openConnection() and closeConnection(), are abstract; all the others are provided as default implementations. This is pretty sensible, since the subclasses only differ in how they connect to their data source.

A boolean property

Notice that on line 50 above, there’s a method:

public void setUseFirewall(boolean _bUseFirewall) {

and on line 53, another method:

public boolean isUseFirewall() {

The method setUseFirewall looks like a standard property editor, but what is isUseFirewall()? This is a standard design pattern (Sun’s unfortunate term for naming conventions) for a boolean property. When java.beans.Introspector runs across a pair of methods with signatures that look like void setPropertyName(boolean) and boolean isPropertyName(), it treats PropertyName as a boolean property. The builder tool can display boolean properties any way it chooses: as a checkbox, a True or False pull-down list (the BeanBox’s choice), or any other two-state widget. You’ll notice that when we see an instance of URLFileLoader running in the BeanBox, the boolean property useFirewall appears as a True or False pull-down list.

Let’s continue with a class that actually loads and copies files.

Accessing file URLs

To create the URLFileLoader class, we need only define the methods openConnection() and closeConnection(). If you’re a follower of JavaWorld‘s Java Tips column, you may recognize the technique used in these functions. (See “Java Tip 34: POSTing via Java”.) The source code for URLFileLoader appears here:

Figure 5. URLFileLoader.java copies a URL to local file

In the code above, openConnection() creates an open connection to a URL by calling getURL() to get the URL from the parent.

An aside: It’s always polite to ask your parent class for property values via the accessor, instead of rummaging through its fields directly. It’s sometimes said that inheritance breaks encapsulation, meaning that if you change the implementation of a superclass method, but your subclasses depend on that implementation, you may break subclass functionality. Using superclass accessors makes this less likely. The superclass fields I do access (uc_ and so on) suffer from this liability, and a purist would set and get these objects through calls on protected methods in the parent class, but I didn’t want to obfuscate the code.

After opening the URLConnection, openConnection() creates the buffered I/O streams that fetchContent() uses to transfer data. It can also use the superclass’s setupFirewall() method to initialize the Java environment to communicate through a firewall, if the bean is customized to do so. The closeConnection() method shuts down the connection and closes streams.

To use this bean in the BeanBox:

  1. Package URLFileLoader.class in a jar file (instructions can be found on Sun’s java.sun.com Web site — see Resources)
  2. Put the jar file in the BeanBox’s classpath (the easiest way to do this is to put it in bdk/jarfiles in the BDK distribution)
  3. Drop a URLFileLoader object into the BeanBox
  4. Customize the loader bean as you wish using the property sheet
  5. Add a Button of some sort to the BeanBox, and select the button
  6. Using the menu item Edit->Events->button push->actionPerformed, bind the button’s actionPerformed event to the URLFileLoader‘s execute event.
  7. When you click the button, the bean will go and fetch the contents of the URL and copy them to your local disk.

Now that we have a functioning URL loader, let’s create a loader class that can handle parameters.

Handling HTTP GET parameters

There are two common ways of passing parameters to a CGI script in HTML: GET and POST. In this section, we’re going to discuss GET and leave POST as an exercise for the reader. (If it’s an exercise you want to do, JavaWorld‘s Java Tips on “POSTing” via Java in Resources below may be of some help.) HTTP GET passes parameters to a CGI program by specifying the values of variables in the URL itself. For example, searching for “post applet” on JavaWorld‘s search engine (at http://www.javaworld.com/javaworld/search.html, itself being an HTML form that uses POST) results in a URL like this:

http://search.javaworld.com/query.html?rq=0&col=jw&qp=&qt=post+applet&qs=&qc=&ws=0&qm=0&st=1&nh=10&lk=1&rf=0&oq=&rq=0

Everything following the question mark (?) in the URL is an encoded list of variables passed to the script. Each variable/value pair is separated by an ampersand (&), and spaces are encoded as plus marks (+). This is the standard text format for transferring variables in HTTP. The query program uses these variables to search the database, make decisions about formatting, and so on.

Now, we could stuff this ungainly URL into our URLFileLoader‘s URL property, and it would operate correctly. But it would be much more pleasant (and flexible) to create a single property of the bean that allows us to specify an arbitrary number of parameters to a CGI program. But how to do that? (Bet you can guess.)

Indexed property naming conventions

Builder tools can automatically identify indexed properties that conform to the indexed property naming and signature conventions (design patterns) described in the JavaBeans Specification. Since each property is an array, we simply add an index value to both property accessors.

Let’s say we have an indexed property of String called formData. Then, the property accessor signatures look like this:

    public String getFormData(int index)
    public void setFormData(String value, int index)

The index indicates which element in the array is being accessed. If the index is negative or otherwise out of range, the accessor can throw an ArrayIndexOutOfBoundsException. (This exception is not checked, so it doesn’t need to appear in the throws clause of the accessor.) Anyone who uses this bean can now set and get form data by index, just as if the accessor were an array.

Optionally, a bean developer can add another pair of accessors that set and get the entire array at once:

    public String[] getFormData()
    public void setFormData(String[] value)

In these cases, the index is gone because we’re getting or setting the entire array at once.

Implementing the FormData indexed property

Now let’s create a class that implements the String[] property FormData. I’ve chosen to create an intermediate class between URLLoader and the new class, URLGetLoader. I’ve called this intermediate class URLDataLoader. The reason I’ve done this is because I also plan to implement a URLPostLoader bean, and I’ve placed all of the code that both classes have in common in their common base class. The inheritance tree for all of these classes appears in Figure 6, below.

You can browse the source code for the URLDataLoader class in the text box in Figure 7. Note that URLDataLoader is abstract because its base class (URLLoader) is abstract, but URLDataLoader doesn’t implement its abstract methods. This is an example of using inheritance to extend the functionality of an existing class, even though URLDataLoader can’t be used to create instances.

Figure 7. URLDataLoader.java with indexed properties

You’ll notice in URLDataLoader.java that the implementations of the two accessors String[]getFormData() and void setFormData(String[]_sFormData) look pretty much like any other simple accessor. String getFormData(int index) is also very simple. The only one with any complexity is void setFormData(String[]_sFormData), which simply grows the sFormData_ array if it gets an index that is too large. This “auto-grow” isn’t a requirement for an indexed property; in fact, in some applications it wouldn’t be appropriate. It’s up to the designer to make the call whether or not to use it. In this case, I want the number of form variables I can enter to be arbitrarily long.

We’ll use the other method in URLDataLoadergetFormDataEncoded() — in the subclasses.

The URLGetLoader class: ‘Getting’ from a CGI

One of the nice things about creating a large number of classes is that each class has fewer methods and so is easier to understand. The concrete (as opposed to abstract) class URLGetLoader, seen in Figure 8, is almost identical to class URLFileLoader, except that it appends a question mark (?) (indicating that a GET is occurring) and a list of encoded form variables to the URL is being fetched. The method URLDataLoader.getFormDataEncoded() takes each element of the formData indexed property, splits it into variable (everything before the first equal-to sign [=]) and value (everything after the equal-to sign), and url-encodes the value. It then joins all variable/value pairs with an equal-to sign, and joins all of the elements of the formData to create a single string. This string conforms to the standard format for specifying parameters to an HTTP GET request. (The GET request itself is specified by the question mark (?) in the URL.) With the exception of this single string, URLGetLoader is identical to URLFileLoader.

Figure 8 shows the source code for the URLGetLoader bean. Notice that it extends URLDataLoader, just as URLFileLoader does.

Figure 8. URLGetLoader.java gets files via HTTP GET

Creating a complex property editor

Because URLGetLoader is a bean, you can put its class file in a jar and drop it into the BeanBox. Unfortunately, you’ll be in for a nasty surprise: the BeanBox doesn’t have a standard property editor for an indexed property. Fortunately, the JavaBeans Spec provides a way for us to create our own property editor by extending java.beans.PropertyEditor.

In the past (see the “Customization” links in Resources), we’ve used the simple interfaces on java.beans.PropertyEditorSupport to handle simple property editors. This time, we’re going for the big enchilada: a complete property editor that allows us to edit this indexed property. We’re going to create a custom editor called FormDataEditor, and it will be capable of editing an indexed property of type String[]. After creating the custom editor, we’ll tell the builder tool how to access it, and we’ll see it running in the BeanBox. Let’s start by getting an in-depth understanding of the property editor interface.

The interface java.beans.PropertyEditor

The interface java.beans.PropertyEditor is pretty complex, and takes some figuring out. A property editor is essentially a custom component that a builder tool (like the BeanBox) “plugs into” a property sheet. Each instance of a property editor manipulates a single property of an individual bean by firing property change events at the source bean, thereby notifying it whenever a property has changed. (Find out more about property change events in “Keep listening for upcoming events”; you’ll find a link to this article in Resources below.) I’m going to assume for this discussion that you’re already up to speed on the PropertyChangeListener interface.

Usually, a programmer can just subclass the convenience class java.beans.PropertyEditorSupport, override a method or two, and get a slightly better property editor. Unfortunately, there’s no way to do that for indexed properties. You pretty much have to implement the entire interface. But it’s really not too bad once you’ve been through it.

Keep in mind that, while we’re writing a complex property editor in order to edit an indexed property, property editors can be used for any property of any level of complexity. Custom property editors are not only for indexed properties. Also, consider using a Customizer instead of a property editor when using indexed properties. (You can find a link to a previous JavaBeans article on Customizers in Resources below.)

The property editor interface has a few groups of methods that work together. Let’s go through the methods one by one:

Property change listener methods

The following methods add and remove property change listeners:

  • addPropertyChangeListener()
  • removePropertyChangeListener()

Typically, you’ll use a PropertyChangeSupport object to implement these. As a property editor developer, you’re responsible for firing property change events any time the user changes a property in your editor. (You get to decide when the event is fired, though.)

Value accessors

Just as a JavaBean has accessor methods that allow the user to set and get properties, the builder tool uses the following methods to get and set the value being edited in the property editor:

  • getValue()
  • setValue()

When the property editor is first created, the builder calls getValue() to set the initial value of the object. The property editor should maintain and edit a copy of the object passed in, not the object itself. (Going into the reasons for this rule are beyond our scope here — just trust me.)

The builder tool also registers itself as a PropertyChangeListener on the property editor. When the user changes a value in the editor, the property editor fires a PropertyChangeEvent. The builder tool responds by calling getValue() to get the new value of the property. This happens regardless of the content of the PropertyChangeEvent. This explains the firePropertyChange("", null, null) that you’ll see in the code that follows shortly.

Painting methods

These methods are for displaying a graphical representation of the property editor in the property sheet:

  • isPaintable()
  • paintValue()

Usually, the space in the property sheet is inhabited by a text item or dropdown list. But if your PropertyEditor returns true for isPaintable, then repaints for the small area within the property sheet are delegated to the paintValue() method you supply. In our sample class below (FormDataEditor), this method simply paints the whole area bright red, to make it stand out like a sore thumb. To activate the property editor, you double-click anywhere inside the paint area (the red box). This is BeanBox functionality — other builder tools might handle this quite differently.

Getting the component

The following methods invokes the component:

  • supportsCustomEditor()
  • getCustomEditor()

If supportsCustomEditor returns true, a builder tool may then call getCustomEditor(), which must return the entire custom Component that is the GUI editor for the property.

In our case, we return a subclass of java.awt.Panel (the most common choice) that is used to edit a list of strings.

Miscellaneous inapplicable methods

These methods have to do with alternate ways of specifying property editors:

  • getAsText()
  • setAsText()
  • getTags()

These should return null, if they return anything at all.

Oddball method

This method is used in code generation.

  • getJavaInitializationString()

It’s used to set the initial value of the property when your builder tool generates code for new instances of this object. We’re not going to consider it any further here.

The FormDataEditor property editor

The source for the FormDataEditor class is pretty complex. First, it’s a GUI component that edits the list of strings passed to it via setValue. It accepts registration of PropertyChangeListeners, at which it fires PropertyChangeEvents whenever any value in the string list changes. The class also implements several event listener interfaces in order to handle user interaction. Finally, it completely implements java.beans.PropertyEditor, including returning itself as a custom editor. (See getCustomEditor() in the source code.) The source code appears in Figure 9.

Figure 9. The FormDataEditor custom property editor

There are a couple of “gotchas” you’ll need to watch out for. When working with the BeanBox, if getValue() returns null when the BeanBox is initializing, the BeanBox will ignore the property, and that property will never make it into the property sheet. Also, never put null strings into a java.awt.List object, unless you’re planning to never display the list. That’s a general Java programming tip.

Interfacing with builder tools

Now that we have a custom property editor, there’s one final step: telling the builder tool (in this case, the BeanBox) about the custom editor. According to the JavaBeans Spec, a developer can provide detailed information to a builder tool in a java.beans.BeanInfo object. A builder tool locates the BeanInfo for a bean by appending BeanInfo to the bean’s class name and trying to load a class with that name. For example, if a builder loads a JavaBean called Pinto, it will search for and load (if found) a class called PintoBeanInfo.

Separating the BeanInfo from the bean sounds confusing, but it’s actually a great idea. BeanInfo is usually used at design time only. By separating design-time code from runtime code, a developer can customize and distribute JavaBeans with customizers and property editors, but avoid the overhead of distributing design-time-only code to end users.

The contents of BeanInfo merit a column or two on their own. If you want to brush up on BeanInfo, see my article “Controlling Customization,” in the Resources section.

The source code for the URLDataLoaderBeanInfo appears in Figure 10.

Figure 10. URLDataLoaderBeanInfo informs the builder about properties and property editors

The URLDataLoaderBeanInfo code that appears in Figure 9 simply defines all of the properties of the bean in the standard way. One new twist is the creation of an IndexedPropertyDescriptor, which is the special PropertyDescriptor class for indexed properties. It is in this descriptor that we set the editor class, by calling FormDataPD.setPropertyEditorClass(FormDataEditor.class).

Pulling it all together

After all this coding, we finally have a usable indexed property editor. In Figure 10 below, you can see the finished product. And, if you’ve got JDK 1.1 or later, and the BDK, you can download the jar file from the Resources link and try it for yourself!

When you double-click the red box in the property sheet, the BeanBox creates a dialog on the fly, called PropertyEditor.getCustomEditor(), and embeds the component it gets back in the dialog. That’s the dialog you see floating above the property sheet: the custom editor. The bean URLGetLoader receives FormDataEditor as its custom property editor because the Introspector (we’ll cover that some other time) searches superclasses for property editors if subclasses don’t define them, and then uses a default class if nothing else is found.

Future possibilities

If you like, you might try building an application based around these URL-copying beans. Parse the HTML as it comes in and recursively load the image and class files referenced in the page. Create timers that fire and interact with Web sites at preset times. Build your own Web spider!

I wanted to create a bean that stores the result of a POST, but I’m going to leave that as an exercise for the reader. Notice that while the JavaBeans we’re using this month have a visible interface at design-time, they’re invisible at runtime. Many people think of JavaBeans as pluggable interface components, and they do excel in that role. JavaBeans is, however, a completely general component technology in its own right. JavaBeans doesn’t only mean “user interface component” any more than Java only means “browser applet.”

So, learn to use indexed properties in your designs! With indexed properties and custom property editors, your JavaBeans can have more elegant interfaces, both technically and visually.

Mark Johnson has a BS in computer and electrical engineering from Purdue University (1986). He is a fanatical devotee of the design pattern approach in object-oriented architecture, of software components in theory, and of JavaBeans in practice. Over the past several years, he worked for Kodak, Booz-Allen and Hamilton, and EDS in Mexico City, developing Oracle and Informix database applications for the Mexican Federal Electoral Institute and for Mexican Customs. He currently works as a designer and developer for Object Products, Inc. in Fort Collins, CO.