Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

An inside view of Observer

The Observer pattern facilitates communication between decoupled objects

  • Print
  • Feedback

Page 4 of 6

Figure 4a. A listener listens for window close events

Figure 4b. A dialog box lets users save changes

The application shown in Figure 4 is listed in Example 4:

Example 4. Vetoable observers

import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import java.util.*;
public class Test extends JFrame {
   private JDesktopPane desktopPane = new JDesktopPane();
   public Test() {
      Container contentPane = getContentPane();
      contentPane.add(desktopPane, BorderLayout.CENTER);
      desktopPane.setLayout(new FlowLayout());
      JInternalFrame jif = new JInternalFrame(
            "A Window with a Vetoable Change Listener", // Title
            false,  // Resizable
            true);  // Closable
      jif.setPreferredSize(new Dimension(400, 350));
      jif.show();
      jif.addVetoableChangeListener(new CloseListener());
      desktopPane.add(jif);
   }
   public static void main(String args[]) {
      GJApp.launch(new Test(), 
               "Vetoing Internal Frame Closing",
               300,300,550,400);
   }
}
class CloseListener implements VetoableChangeListener { 
   private Test applet;
   public void vetoableChange(PropertyChangeEvent e) 
                           throws PropertyVetoException {
      String name = e.getPropertyName();
      if(name.equals(JInternalFrame.IS_CLOSED_PROPERTY)) {
         Component internalFrame = (Component)e.getSource();
         Boolean oldValue = (Boolean)e.getOldValue(),
                   newValue = (Boolean)e.getNewValue();
         if(oldValue == Boolean.FALSE && 
            newValue == Boolean.TRUE) {
            int answer = JOptionPane.showConfirmDialog(
                  internalFrame,      // ParentComponent
                  "Save Changes?",    // Message
                  "Unsaved Changes",    // Title
                  JOptionPane.YES_NO_CANCEL_OPTION); 
            if(answer == JOptionPane.CANCEL_OPTION) {
               throw new PropertyVetoException("close cancelled", e);
            }
         }
      }
   }
}
class GJApp extends WindowAdapter {
   // Application class not listed here for the sake of brevity.
}


The difference between regular change listeners and vetoable change listeners is that the latter can throw a PropertyVetoException(), as illustrated in Example 4. Throwing the exception rolls back the change, in this case, the window close operation, so the window stays open.

Now that you know how to use the Observer pattern's Swing and JavaBeans implementations, let's see how you can implement the Observer pattern in your own code.

Implement the Observer pattern

This section extends an example from a previous Java Design Patterns column, "Take Control with the Proxy Design Pattern." In that example, I implemented a proxy for Swing image icons that creates images on demand. In this section, I extend that example by implementing the Observer pattern: when the proxy finishes loading its image, it fires a property change event, and a listener displays a dialog box.

The application, shown in Figures 5a, 5b, and 5c, contains a regular Swing image icon on the left and an image icon proxy on the right. The icon loads its image when it's created, so it appears when the application starts. The proxy, on the other hand, draws a rectangle around its perimeter and displays the message Loading image... until the image loads. Subsequently, when the image loads, the proxy paints the image and fires a property change event. An application-specific listener reacts to the property change event by displaying a dialog box, as shown in Figure 5c.

  • Print
  • Feedback

Resources