Archive for September, 2006

Developing Java Beans // change the stock at

Friday, September 29th, 2006

Developing Java Beans // change the stock at the specified indexstocks.setElementAt(stock, index); } } 4.3 Bound Properties In the previous example, property changes can take place when one of the setStocks() methods are invoked. This results in the state of the WatchList being changed. What would happen if two objects were using the WatchList and one of them changed the Stocks property? It’s possible that users of the WatchList will want to know if its properties are changed. A Bean component can provide change notifications for its properties. These notifications take the form of events, and they conform to the event model described in the earlier chapters. Properties that support change notifications are known as bound properties, because other objects can bind themselves to changes in their value. 4.3.1 Non-Specific Property Binding An object can bind itself to non-specific property changes. In this case the source object sends notifications to the bound object whenever the value of one of its bound properties has changed. The notification takes the form of a java.beans.PropertyChangeEvent. The public methods for this class are shown below, without their implementations: public class java.beans.PropertyChangeEvent extends java.util.EventObject{ // contructor PropertyChangeEvent(Object source, // the source of the event String propertyName, // the property name Object oldValue, Object newValue); // the old value// the new value // get the new value of the propertypublic Object getNewValue(); // get the old value of the propertypublic Object getOldValue(); // get the event propagation idpublic Object getPropagationId(); // get the name of the property that changedpublic String getPropertyName(); // set the event propagation id public void setPropagationId(); } The java.beans.PropertyChangeEvent class treats old and new values as instances of class Object. If the property that changed uses one of the primitive data types like int or float, you’ll have to use the object version of the type here, such as java.lang.Integer or java.lang.Float. It is possible that when the event is fired the old or new values are not known, or that multiple values have changed. In this case null can be returned from the getOldValue() or getNewValue() method. This is also true of the property name. If multiple properties have page 55

Developing Java Beans 4.2 Indexed Properties So far

Friday, September 29th, 2006

Developing Java Beans 4.2 Indexed Properties So far we have been talking about properties that have only one value. For each named property, we have a single associated value. But this is not always the best way to represent properties; sometimes a property is better modeled as having multiple values. You can create properties that are actually an ordered collection of values associated with a single name. The individual values are accessed using an integer index, much the same way you would with an array. There is an additional design pattern for indexed properties. The in the standard property method design pattern may be an array, as follows: public [] get(); public void set([] value); These methods are used to access the entire array of property values at one time. An additional method can be used to provide access to individual values in the property array. The method signatures for this pattern are: public get(int index); public void set(int index, value); As with the single value pattern, these methods are allowed to include a throws clause for throwing checked exceptions. Specifically, the indexed methods may throw a java.lang.ArrayIndexOutOfBoundsException if an index is used that is outside the bounds of the property array. Although this is an important aspect of indexed properties, it isn’t required for the indexed properties pattern. Since the indexed properties are considered ordered collections, I think the indexed get() and set() methods should always declare the ArrayIndexOutOfBoundsException. It might have been better to make it a requirement for this pattern. Imagine that we are building a system that tracks stock prices in real time. First, let’s think about building a watch list object that keeps track of prices for a set of stocks. We’ll call this class a WatchList. We then define a property of the WatchList called Stocks which contains a list of stocks for which prices are being tracked. The type of the Stocks property is a String array, and each individual stock is represented by a String. We also implement a read-only property called StockCount that returns the number of stocks in the WatchList. The code looks like this: import java.util.*; public class WatchList { // a vector that contains the actual stock names protected Vector stocks = new Vector(); // constructor public WatchList() { } // the get method for the StockCount property public synchronized int getStockCount() { // the StockCount property is derived from the size of the // stocks Vector return stocks.size(); } page 53

Developing Java Beans // get method for Stocks

Friday, September 29th, 2006

Developing Java Beans // get method for Stocks property arraypublic synchronized String[] getStocks() { // we don’t currently deal with the case where the watch list // is empty // allocate an array of strings for the stock names String[] s = new String[getStockCount()]; // copy the elements of the stocks Vector into the string array, // and then return the array stocks.copyInto(s); return s; } // set method for Stocks property arraypublic synchronized void setStocks(String[] s) { // the existing list of stocks is removed in favor of the // new set of stocks // set the size of the stocks vector to match the length // of the new array stocks.setSize(s.length); // copy the values into the stocks vector for (int i = 0; i < s.length; i++) { // use the single stock set method try { setStocks(i, s[i]); } catch (ArrayIndexOutOfBoundsException e) { } } } // get method for single element of Stocks propertypublic synchronized String getStocks(int index) throws ArrayIndexOutOfBoundsException { // make sure the index is in boundsif (index < 0 || index >= getStockCount()) { throw new ArrayIndexOutOfBoundsException(); } // get the stock and return it String s = (String)stocks.elementAt(index); return s; } // set an individual element of the Stocks property arraypublic synchronized void setStocks(int index, String stock) throws ArrayIndexOutOfBoundsException { // make sure the index is in boundsif (index < 0 || index >= getStockCount()) { throw new ArrayIndexOutOfBoundsException(); } page 54

Developing Java Beans exposed externally. If Celsius is

Friday, September 29th, 2006

Developing Java Beans exposed externally. If Celsius is not used, then Fahrenheit is being used, and vice versa. We’ll put off implementing the property until later. So the code for the Thermometer class now looks like this: package BeansBook.Simulator; public class Thermometer implements TempChangeListener { // a reference to the temperature object that we are monitoringprotected Temperature theTemperature; Thermometer(Temperature temperature) { theTemperature = temperature; // register for temperature change events theTemperature.addTempChangeListener(this); } // handle the temperature change events public void tempChanged(TempChangedEvent evt) { // do something with the temperature that we can retrieve // by calling evt.getTemperature() } // the get method for the DisplayingCelsius propertypublic boolean isDisplayingCelsius() { … } // an alternate get method for the DisplayingCelsius propertypublic boolean getDisplayingCelsius() { return isDisplayingCelsius(); } // the set method for the DisplayingCelsius propertypublic void setDisplayingCelsius(boolean value) { … } } In this example I’ve provided both forms of the get method for the boolean property DisplayingCelsius. You’ll notice that the only method that has an implementation so far is getDisplayingCelsius(), which does nothing but call the isDisplayingCelsius() method. We’ll fill in the code later. Whenever two methods are provided that perform the same function, it is a good idea to implement one in terms of the other. There is no requirement to do this, but it is a good programming practice. Following this guideline will eliminate the need to repeat code, and to modify multiple areas of code when the implementation changes. Normally when a property value is changed, the object will react in some way. Later, when our Thermometer object is capable of displaying a temperature value, we will have to implement code that reacts to a change to the DisplayingCelsius property by redisplaying the temperature according to the temperature units being used (Celsius or Fahrenheit). page 52

Developing Java Beans public void set( value); public

Friday, September 29th, 2006

Developing Java Beans public void set( value); public get(); The existence of a matching pair of methods that conform to this pattern represents a read/write property with the name of the type . If only the get() method exists, the property is considered to be read-only; if only the set() method exists, the property is considered to be write-only. If the is boolean, the get() method can be replaced or augmented with a method that uses the following signature: public boolean is(); Let’s look back at the Temperature class. The current temperature is stored within an object of type Temperature, but up until now we have not provided a way to access that value. So now we can add a read-only property called CurrentTemperature. The code for the Temperature class will now include the following: package BeansBook.Simulator; import java.util.Vector; public class Temperature { // the current temperature in Celsius protected double currentTemp = 22.2; [The rest of the existing code goes here] // the get method for property CurrentTemperature public double getCurrentTemperature() { return currentTemp; } } It is important to recognize that properties are not defined by data members of the object’s class. One reason for this is that it would break encapsulation. More importantly, properties can be computed when they are needed without having to be stored explicitly. In an earlier example we described a Thermometer class that tracked temperatures from two locations. We could define a property called NumberOfLocations. This is a read-only property that describes how many locations are being tracked by the thermometer. In this case we don’t need to explicitly store a data member for this property, we just know that the value is always 2. We could add a property get method to access this value, as follows: public int getNumberOfLocations() { return 2: } Although our thermometer isn’t a visual component yet, imagine that at some point it will be capable of displaying the temperature from one of its source thermometers. Let’s design the Thermometer so that it is capable of displaying temperatures in either Celsius or Fahrenheit. We call this property DisplayingCelsius, and we expose it using a boolean data type. Remember that this doesn’t refer to the way that the property is stored internally, only the way that the property is page 51

Developing Java Beans Now let’s run Example3 again.

Friday, September 29th, 2006

Developing Java Beans Now let’s run Example3 again. This time the events are being queued by the PollerAdapter, so the Poller thread can continue running without interference. The following output is generated when the program runs: Value: 3 Received Event Number: 3 Value: 6 Value: 9 Value: 12 Value: 15 Received Event Number: 6 Value: 18 Value: 21 Value: 24 Received Event Number: 9 Value: 27 Value: 30 Value: 33 Received Event Number: 12 Value: 36 Value: 39 Value: 42 Received Event Number: 15 Value: 45 Chapter 4. Properties Properties are named attributes or characteristics. They define the behavior and state of an object. For instance, the current temperature value of the Temperature object is a property, as are the high and low temperature thresholds of the GenericTemperatureThresholdAdapter from the previous chapter. Properties are referenced by their name and can have any type, including primitives such as int, and class and interface types such as java.awt.Color. The name of the low threshold property is LowThreshold, and its type is double. Properties are usually part of the persistent state of an object. This will be dealt with later in Chapter 5. Properties are exposed to visual programming tools and scripting environments, as well as to traditional Java programming. They are manipulated in a visual programming tool through some kind of property-editing interface. In a scripting environment, properties are exposed through a field-style syntax such as Object.Property = value, and value = Object.Property. These are syntactical conveniences provided by the scripting environment. As a Beans developer, you’ll expose your properties as described in the rest of this chapter. 4.1 Accessing Properties An object’s properties are accessed by calling methods that are defined for setting and getting the property value. Any property that can be read will have an associated method for getting its value. Likewise, any property that can be written will have an associated method for setting its value. We’ll see shortly that objects don’t always provide both access mechanisms for every property. Properties can be read/write, read-only, or write-only. The methods used for getting and setting property values should conform to the standard design pattern for properties. These methods are allowed (but not required) to throw checked exceptions. The method signatures are as follows: page 50

Developing Java Beans { lowThreshold = low; }

Friday, September 29th, 2006

Developing Java Beans // clone the queue so we don’t tie up anyone else Vector tempQueue; synchronized (queue) { tempQueue = (Vector)queue.clone(); // delete the ones we have from the real queue queue.removeAllElements(); } // empty the queue in FIFO order and notify listener while (!tempQueue.isEmpty()) { PollEvent evt = (PollEvent)tempQueue.elementAt(0); tempQueue.removeElementAt(0); listener.pollSent(evt); } } } } We have to make some changes to the Watcher class as well. We need an instance of the PollerAdapter class, and the Watcher constructor will be modified to use the adapter instead of being the PollerListener itself. Notice that the Watcher still implements the PollerListener interface because that is the way the adapter forwards the events to it. The code for the Watcher now looks like this: class Watcher implements PollerListener { // the poller objectprotected Poller poller = new Poller(); // the adapter protected PollerAdapter adapter; // the constructor public Watcher() { // create the adapter adapter = new PollerAdapter(this, poller); } // the event handler simulates work by sleeping for // 2 seconds before returning public void pollSent(PollEvent evt) { try { System.out.println(”Received Event Number: ” + evt.getValue()); Thread.sleep(2000); } catch (InterruptedException e) { } } } page 49
Note: If you are looking for cheap and reliable provider to host and run your servlet application check Vision servlet hosting services

Developing Java Beans { lowThreshold = low; }

Friday, September 29th, 2006

Developing Java Beans // the constructor public Watcher() { // register as the event listener try { poller.addPollerListener(this); } catch (TooManyListenersException e) { } } // the event handler simulates work by sleeping for// 2 seconds before returningpublic void pollSent(PollEvent evt) { try { System.out.println(”Received Event Number: ” + evt.getValue()); Thread.sleep(2000); } catch (InterruptedException e) { } } } public class Example3 { // the application entry pointpublic static void main(String[] args) { // create the watcher objectWatcher h = new Watcher(); } } Since Example3 is an application, not an applet, you can run it by issuing the following on the command line: java Example3 When you do so, the following will be printed to your console window: Value: 3 Received Event Number: 3 Value: 6 Received Event Number: 6 Value: 9 Received Event Number: 9 Value: 12 Received Event Number: 12 Value: 15 Received Event Number: 15 Value: 18 Received Event Number: 18 Value: 21 Received Event Number: 21 page 47
Note: If you are looking for cheap and reliable provider to host and run your servlet application check Vision servlet hosting services

Developing Java Beans { lowThreshold = low; }

Friday, September 29th, 2006

Developing Java Beans You can see from this output that the Poller thread is being held up by the Watcher object. The Poller thread is supposed to be looping every 200 milliseconds to update the counter, printing its message every third update. So we would expect to see a few “Value: x” messages for each “Received Event: x” message. This is clearly not happening. We can correct this by introducing an asynchronous queuing adapter between the Poller and Watcher objects. This adapter queues the events received from the Poller, and it fires the events to the Watcher from its own notification thread, allowing the Poller to continue its work. The code for the PollerAdapter class is shown below: class PollerAdapter extends Thread implements PollerListener { // the event queueprotected Vector queue = new Vector(); // the real listener protected PollerListener listener; public PollerAdapter(PollerListener l, Poller p) { // save a reference to the target listener listener = l; // register myself as the event listener try { p.addPollerListener(this); } catch (TooManyListenersException e) { } // start my thread start(); } // receive events public synchronized void pollSent(PollEvent e) { // add an element to the queue synchronized (queue) { queue.addElement(e); } this.notify(); } // the run loop of the thread public void run() { // loop forever for (;;) { // suspend until there is work to do try { this.wait(); } catch (Exception e) { } page 48
Note: If you are looking for cheap and reliable provider to host and run your servlet application check Vision servlet hosting services

Developing Java Beans { lowThreshold = low; }

Friday, September 29th, 2006

Developing Java Beans throw new TooManyListenersException(); } listener = l; } // remove the listener public void removePollerListener(PollerListener l) { if (listener == l) { listener = null; } } // the run loop for this thread public synchronized void run() { // loop forever for (;;) { try { // we sleep for 200 milliseconds at a time this.sleep(200); // bump the counter cnt++; // every 3rd time, fire the event if ((cnt % 3) == 0) { // print out which event we’re firingSystem.out.println(”Value: ” + cnt); // fire the event if (listener != null) { listener.pollSent(new PollEvent(this, cnt)); } } } catch (InterruptedException e) { } } } } With no listener object, the Poller loops unimpeded. It bumps its counter every 200 milliseconds, and with every third update it prints its message. Now let’s introduce an object called a Watcher that implements the PollerListener interface. Whenever the event is fired on the Watcher, it prints out the value of the event it received and sleeps for 2 full seconds. This will interfere with the Poller run loop, because the synchronous delivery of events results in the Poller thread being held up by the event handling method of the Watcher object. The code for the Watcher, as well as the application code to get the whole thing started, is given below: class Watcher implements PollerListener { // the poller objectprotected Poller poller = new Poller(); page 46
Note: If you are looking for cheap and reliable provider to host and run your servlet application check Vision servlet hosting services