Updating ZooKeeperList automatically
The ZooKeeperList object needs some way of being notified whenever a change to the collection of zookeeper objects held by the administrator changes, in order that it can update its model and thus be reflected in the list of items displayed. This can be accomplished by defining suitable event and listener objects, as follows:
Create a sub-package under virtualzoo.core called event, within which you will define the class ZooKeeperEvent and the interface ZooKeeperListener.
Define a ZooKeeperEvent class in package virtualzoo.core.event:
package virtualzoo.core.event;
import virtualzoo.core.*;
import java.util.*;
public class ZooKeeperEvent extends EventObject {
public ZooKeeperEvent(ZooKeeper zooKeeper) {
super(zooKeeper);
}
public ZooKeeper getZooKeeper() {
return (ZooKeeper) getSource();
}
}
- The class extends
EventObject, which is a Java supplied class intended for sub-classing by different event types; - The constructor requires a
ZooKeeperobject to be passed in and which is in turn passed to the superclass constructor (which accepts anyObject); - The
EventObjectclass defines agetSource()method so client objects can determine the source of the event. BecausegetSource()returns it as anObjecta cast is required to get it back into itsZooKeepertype which you know it has to be. To save client objects the inconvenience of having to do this cast you have defined agetZooKeeper()method that performs the cast here.
Define a ZooKeeperListener interface in package virtualzoo.core.event.
package virtualzoo.core.event;
import java.util.*;
public interface ZooKeeperListener extends EventListener {
public void zooKeeperCreated(ZooKeeperEvent event);
public void zooKeeperChanged(ZooKeeperEvent event);
public void zooKeeperRemoved(ZooKeeperEvent event);
}
- The interface extends
EventListener, which is a Java supplied interface intended for sub-classing by different event listeners - Separate methods are specified for when a
ZooKeeperis created, changed or removed. Note the argument for each isZooKeeperEvent
Because ZooAdministrator stores the collection of ZooKeeper objects it is a natural place to maintain references to objects that want to know about new, changed or removed zoo keepers (i.e., ZooKeeperListeners) and to notify them whenever these events occur.
In ZooAdministrator define an import for virtualzoo.core.event and add the following instance variable to store a collection of listeners:
private Collection<ZooKeeperListener> zooKeeperListeners;
Instantiate the collection inside the constructor:
zooKeeperListeners = new ArrayList<ZooKeeperListener>();
Now define two new public methods so that client objects can register themselves as listeners:
public void addZooKeeperListener(ZooKeeperListener listener) {
zooKeeperListeners.add(listener);
}
public void removeZooKeeperListener(ZooKeeperListener listener) {
zooKeeperListeners.remove(listener);
}
- The above methods simply delegate to the
add()andremove()methods of the collection
Define a private helper method that notifies all registered listeners whenever a new zookeeper is added:
private void fireZooKeeperCreated(ZooKeeper zooKeeper) {
ZooKeeperEvent event = new ZooKeeperEvent(zooKeeper);
for (ZooKeeperListener listener : zooKeeperListeners) {
listener.zooKeeperCreated(event);
}
}
- The above method creates a
ZooKeeperEventand then iterates over each registered listener notifying them of the fact that a new zookeeper has been created
Modify the createZooKeeper() method to invoke fireZooKeeperCreated() once the ZooKeeper object has been added to the collection:
public ZooKeeper createZooKeeper(String name, String address,
String email, String salary) throws ValidationException {
try {
ZooKeeper zooKeeper = new ZooKeeper(new Person(name, address),
new Email(email),
new BigDecimal(salary));
zooKeepers.add(zooKeeper);
fireZooKeeperCreated(zooKeeper);
return zooKeeper;
} catch (NumberFormatException ex) {
throw new ValidationException(salary + " is not a valid amount.");
} catch (IllegalArgumentException ex) {
throw new ValidationException(ex.getMessage());
}
}
You can now define methods fireZooKeeperChanged() and fireZooKeeperRemoved(), each very similar to fireZooKeeperAdded():
private void fireZooKeeperChanged(ZooKeeper zooKeeper) {
ZooKeeperEvent event = new ZooKeeperEvent(zooKeeper);
for (ZooKeeperListener listener : zooKeeperListeners) {
listener.zooKeeperChanged(event);
}
}
private void fireZooKeeperRemoved(ZooKeeper zooKeeper) {
ZooKeeperEvent event = new ZooKeeperEvent(zooKeeper);
for (ZooKeeperListener listener : zooKeeperListeners) {
listener.zooKeeperRemoved(event);
}
}
Modify changeZooKeeper() and removeZooKeeper() to invoke the respective "fire" methods:
public void changeZooKeeper(ZooKeeper zooKeeper, String name,
String address, String email, String salary)
throws ValidationException {
try {
zooKeeper.setPerson(new Person(name, address));
zooKeeper.setEmail(new Email(email));
zooKeeper.setSalary(new BigDecimal(salary));
fireZooKeeperChanged(zooKeeper);
} catch (NumberFormatException ex) {
throw new ValidationException(salary + " is not a valid amount.");
} catch (IllegalArgumentException ex) {
throw new ValidationException(ex.getMessage());
}
}
public void removeZooKeeper(ZooKeeper zooKeeper) {
zooKeepers.remove(zooKeeper);
fireZooKeeperRemoved(zooKeeper);
}
The purpose of ZooAdministrator maintaining a collection of listener objects is so that it need have no direct knowledge of any of the classes which are likely to want to be notified of when a zookeeper is created, changed or removed. In this way, your classes accomplish loose-coupling, meaning that they are not directly dependent upon any more classes than is strictly necessary.
The ZooKeeperList class can now be modified to implement the ZooKeeperListener interface (note you need to import virtualzoo.core.event):
package virtualzoo.ui;
import virtualzoo.core.*;
import virtualzoo.core.event.*;
import java.util.*;
import javax.swing.*;
public class ZooKeeperList extends JList implements ZooKeeperListener {
If you click the glyph that appears to the left of the class declaration statement above, you can click the option to implement all abstract methods. The following code will appear:
@Override
public void zooKeeperCreated(ZooKeeperEvent event) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void zooKeeperChanged(ZooKeeperEvent event) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void zooKeeperRemoved(ZooKeeperEvent event) {
throw new UnsupportedOperationException("Not supported yet.");
}
NetBeans generated the statements to throw an UnsupportedOperationException merely so that the code will compile. It is up to you to replace these lines with the actual code that should occur in response to the events. In all three cases you simply want the data in the list model (held in the ZooKeeperListModel inner class) to be reloaded. To do this you can invoke the loadModel() method from within the event listener methods, so make the following modifications:
@Override
public void ZooKeeperCreated(ZooKeeperEvent event) {
model.loadModel();
}
@Override
public void ZooKeeperChanged(ZooKeeperEvent event) {
model.loadModel();
}
@Override
public void ZooKeeperRemoved(ZooKeeperEvent event) {
model.loadModel();
}
You now need to wire up the ZooKeeperList object which is referenced in ZooKeeperPanel so that it listens to events. In ZooKeeperPanel define a new instance variable to reference the ZooAdministrator object (you need to import import virtualzoo.core):
private ZooAdministrator admin;
Now change the constructor to obtain the ZooAdministrator object add call its addZooKeeperListener() method:
public ZooKeeperPanel() {
initComponents();
admin = ZooAdministrator.getInstance();
admin.addZooKeeperListener(zooKeeperList);
}
You can now run the application, enter and save one (or several) zookeepers, and you should find the list automatically updates itself:
It would be better to clear the editor form after adding a new zookeeper ready for adding a new one, so add a call to clearZooKeeper() in the saveButtonActionPerformed() method of ZooKeeperEditor:
private void saveButonActionPerformed(java.awt.event.ActionEvent evt) {
ZooAdministrator admin = ZooAdministrator.getInstance();
if (zooKeeper == null) {
// Adding a new zoo keeper
admin.addZooKeeper(nameField.getText(),
adressArea.getText(),
emailField.getText(),
salaryField.getText());
messageLabel.setText("New zoo keeper added");
clearZooKeeper();
} else {
// Changing an existing zoo keeper
admin.changeZooKeeper(zooKeeper,
nameField.getText(),
addressArea.getText(),
emailField.getText(),
salaryField.getText());
messageLabel.setText("Zoo keeper details changed");
}
}
Verify that the form gets cleared after successfully adding a new zookeeper.
Comments