Clover coverage report - JFCUnit Test Coverage
Coverage timestamp: Mon Dec 20 2004 23:38:10 MST
file stats: LOC: 404   Methods: 20
NCLOC: 208   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
WindowMonitor.java 75% 86% 75% 82.2%
coverage coverage
 1   
 package junit.extensions.jfcunit;
 2   
 
 3   
 import java.awt.AWTEvent;
 4   
 import java.awt.Frame;
 5   
 import java.awt.Toolkit;
 6   
 import java.awt.Window;
 7   
 import java.awt.event.AWTEventListener;
 8   
 import java.awt.event.WindowEvent;
 9   
 
 10   
 import java.util.ArrayList;
 11   
 import java.lang.ref.WeakReference;
 12   
 
 13   
 
 14   
 /**
 15   
  * The WindowMonitor class is used to monitor for windows
 16   
  * that might not show up in Frame.getFrames(). So we must watch for these
 17   
  * windows to be opened.
 18   
  *
 19   
  * @author Kevin Wilson
 20   
  * @author <a href="mailto:vraravam@thoughtworks.com">Vijay Aravamudhan : ThoughtWorks Inc.</a>
 21   
  */
 22   
 public final class WindowMonitor implements AWTEventListener {
 23   
     /**
 24   
      * A handle to this class instance.
 25   
      */
 26   
     private static WindowMonitor s_singleton = null;
 27   
 
 28   
     /**
 29   
      * The dispatch thread used to process the event queue.
 30   
      */
 31   
     private static DispatchThread s_dt = null;
 32   
 
 33   
     /**
 34   
      * Flag used to shutdown the window monitor.
 35   
      */
 36   
     private static volatile boolean s_running = true;
 37   
 
 38   
     /**
 39   
      * Event queue item or null if no pending items.
 40   
      * The event queue is a linked list.
 41   
      */
 42   
     private static WindowEventItem s_windowEventQueue = null;
 43   
 
 44   
     /**
 45   
      * Lock for the event queue and dispatch thread.
 46   
      */
 47   
     private static final Object QLOCK = new Object();
 48   
 
 49   
     /**
 50   
      * All Non-Popup Windows which have been found.
 51   
      */
 52   
     private static final ArrayList WINDOWS = new ArrayList();
 53   
 
 54   
     /**
 55   
      * Constructor.
 56   
      *
 57   
      * Private use the static start() method.
 58   
      */
 59  79
     private WindowMonitor() {
 60  79
         super();
 61   
 
 62  79
         if (s_dt == null) {
 63   
             // Survey the current windows open.
 64  79
             Frame[] frames = Frame.getFrames();
 65   
 
 66  79
             for (int i = 0; i < frames.length; i++) {
 67  0
                 populateWindows(frames[i]);
 68   
             }
 69   
 
 70  79
             s_dt = new DispatchThread("WindowMonitor-DispatchThread");
 71  79
             s_dt.setDaemon(true);
 72  79
             s_dt.start();
 73  79
             Toolkit.getDefaultToolkit().addAWTEventListener(this,
 74   
                 AWTEvent.WINDOW_EVENT_MASK);
 75   
         }
 76   
     }
 77   
 
 78   
     /**
 79   
      * Get all of the windows which are open.
 80   
      *
 81   
      * @return Window[] containing all of the windows
 82   
      * which have been instantiated.
 83   
      */
 84  276
     public static Window[] getWindows() {
 85  276
       ArrayList v = new ArrayList();
 86  276
       ArrayList toRemove = new ArrayList();
 87  276
       for (int i = 0; i < WINDOWS.size(); i++) {
 88  516
         WeakReference r = (WeakReference) WINDOWS.get(i);
 89  516
         Window w = (Window) r.get();
 90  516
         if (w == null) {
 91  0
           toRemove.add(r);
 92   
         } else {
 93  516
           v.add(w);
 94   
         }
 95   
       }
 96  276
       WINDOWS.removeAll(toRemove);
 97   
 
 98  276
       return (Window[]) v.toArray(new Window[0]);
 99   
     }
 100   
 
 101   
     /**
 102   
      * Start the monitor.
 103   
      */
 104  81
     public static void start() {
 105  81
         getSingleton();
 106   
     }
 107   
 
 108   
     /**
 109   
      * Stop the monitor.
 110   
      */
 111  0
     public static void stop() {
 112  0
         getSingleton().stopInternal();
 113   
     }
 114   
 
 115   
     /**
 116   
      * Event dispatch implementation.
 117   
      *
 118   
      * @param theEvent AWTEvent which is to be processed.
 119   
      */
 120  1775
     public void eventDispatched(final AWTEvent theEvent) {
 121  1775
         processEvent(theEvent);
 122   
     }
 123   
 
 124   
     /**
 125   
      * return the singleton instance.
 126   
      * If the singleton has not been created,
 127   
      * then create one.
 128   
      *
 129   
      * @return WindowMonitor singleton instance.
 130   
      */
 131  81
     private static WindowMonitor getSingleton() {
 132  81
         if (s_singleton == null) {
 133  79
             s_singleton = new WindowMonitor();
 134   
         }
 135   
 
 136  81
         return s_singleton;
 137   
     }
 138   
 
 139   
     /**
 140   
      * Flush the AWT Event Queue.
 141   
      */
 142  0
     private static void flushAWT() {
 143   
         // Invoke the below to insure that we have flushed the queue
 144   
         // of all current pending events.
 145  0
         if (Toolkit.getDefaultToolkit().getSystemEventQueue().isDispatchThread()) {
 146  0
             return;
 147   
         }
 148   
 
 149  0
         try {
 150  0
             Toolkit.getDefaultToolkit().getSystemEventQueue().invokeAndWait(
 151   
                 new Runnable() {
 152  0
                     public void run() {
 153   
                     }
 154   
                 });
 155   
         } catch (Exception e) {
 156   
             // don't do anything here
 157   
         }
 158   
     }
 159   
 
 160   
     /**
 161   
      * Populate frames.
 162   
      * @param w Frame to be traversed.
 163   
      */
 164  0
     private static void populateWindows(final Window w) {
 165  0
         WINDOWS.add(new WeakReference(w));
 166   
 
 167  0
         Window[] windows = w.getOwnedWindows();
 168   
 
 169  0
         for (int i = 0; i < windows.length; i++) {
 170  0
             populateWindows(windows[i]);
 171   
         }
 172   
     }
 173   
 
 174   
     /**
 175   
      * Processes the events by adding the event onto the
 176   
      * event queue to be processed by the dispatch thread.
 177   
      *
 178   
      * @param theEvent The event to be processed.
 179   
      */
 180  1775
     private static void processEvent(final AWTEvent theEvent) {
 181  1775
         switch (theEvent.getID()) {
 182  309
         case WindowEvent.WINDOW_OPENED:
 183  297
         case WindowEvent.WINDOW_ACTIVATED:
 184  290
         case WindowEvent.WINDOW_DEACTIVATED:
 185  259
         case WindowEvent.WINDOW_CLOSING:
 186  1155
             queueWindowEvent((WindowEvent) theEvent);
 187   
 
 188  1155
             break;
 189   
 
 190  620
         default:
 191  620
             break;
 192   
         }
 193   
     }
 194   
 
 195   
     /**
 196   
      * Queue the event.
 197   
      *
 198   
      * @param we WindowEvent to be queued.
 199   
      */
 200  1155
     private static void queueWindowEvent(final WindowEvent we) {
 201  1155
         synchronized (QLOCK) {
 202  1155
             WindowEventItem qi = new WindowEventItem(we);
 203   
 
 204  1155
             if (s_windowEventQueue == null) {
 205  1096
                 s_windowEventQueue = qi;
 206   
             } else {
 207  59
                 WindowEventItem q = s_windowEventQueue;
 208   
 
 209  59
                 while (true) {
 210  96
                     if (q.getNext() != null) {
 211  37
                         q = q.getNext();
 212   
                     } else {
 213  59
                         break;
 214   
                     }
 215   
                 }
 216   
 
 217  59
                 q.setNext(qi);
 218   
             }
 219   
 
 220  1155
             QLOCK.notifyAll();
 221   
         }
 222   
     }
 223   
 
 224   
     /**
 225   
      * Stop the window monitor.
 226   
      */
 227  0
     private void stopInternal() {
 228  0
         s_running = false;
 229   
 
 230   
         //dt.interrupt();
 231   
     }
 232   
 
 233   
     /**
 234   
      * Handle all Component events in a separate thread. The reason for
 235   
      * this is that WindowEvents tend to be used to do lots of processing
 236   
      * on the Window hierarchy. As a result, it can frequently result
 237   
      * in deadlock situations.
 238   
      */
 239   
     private class DispatchThread extends Thread {
 240   
         /**
 241   
          * Constructor.
 242   
          *
 243   
          * @param name Name of the thread.
 244   
          */
 245  79
         public DispatchThread(final String name) {
 246  79
             super(name);
 247  79
             setDaemon(true);
 248   
         }
 249   
 
 250   
         /**
 251   
          * Run the Dispatch thread.
 252   
          * Process the events recieved and track the windows.
 253   
          */
 254  79
         public void run() {
 255  79
             WindowEvent we = null;
 256   
 
 257  1234
             while (s_running) {
 258  1234
                 while (WindowMonitor.s_windowEventQueue == null) {
 259  3410
                     synchronized (WindowMonitor.QLOCK) {
 260  3410
                         try {
 261  3410
                             WindowMonitor.QLOCK.wait(500);
 262   
                         } catch (ExitException exe) {
 263   
                             // don't do anything, but still catch it
 264   
                         } catch (InterruptedException e) {
 265   
                             // don't do anything, but still catch it
 266   
                         }
 267   
                     }
 268   
                 }
 269   
 
 270  1155
                 synchronized (WindowMonitor.QLOCK) {
 271  1155
                     we                                   = WindowMonitor.s_windowEventQueue
 272   
                         .getEvent();
 273  1155
                     WindowMonitor.s_windowEventQueue     = WindowMonitor.s_windowEventQueue
 274   
                         .getNext();
 275   
 
 276  1155
                     switch (we.getID()) {
 277  309
                     case WindowEvent.WINDOW_OPENED:
 278  297
                     case WindowEvent.WINDOW_ACTIVATED:
 279  290
                     case WindowEvent.WINDOW_DEACTIVATED:
 280   
 
 281  896
                         if (!containsKey(we.getWindow())) {
 282  309
                             WINDOWS.add(
 283   
                                 new WeakReference(we.getWindow()));
 284   
                         }
 285   
 
 286  896
                         break;
 287   
 
 288  259
                     case WindowEvent.WINDOW_CLOSING:
 289  259
                         remove(we.getWindow());
 290  259
                         break;
 291   
 
 292  0
                     default:
 293  0
                         break;
 294   
                     }
 295   
 
 296  1155
                     try {
 297  1155
                         WindowMonitor.QLOCK.notifyAll();
 298   
                     } catch (ExitException exe) {
 299   
                         // don't do anything, but still catch it
 300   
                     }
 301   
                 }
 302   
             }
 303   
         }
 304   
     }
 305   
 
 306   
     /**
 307   
      * WindowEventItem is the basic type that handles the
 308   
      * queue for queueWindowEvent and the DispatchThread.
 309   
      */
 310   
     private static class WindowEventItem {
 311   
         /**
 312   
          * Event to be processed by the dispatch thread.
 313   
          */
 314   
         private WindowEvent m_event;
 315   
 
 316   
         /**
 317   
          * Next event item to be processed. Null if no more.
 318   
          */
 319   
         private WindowEventItem m_next;
 320   
 
 321   
         /**
 322   
          * Constructor.
 323   
          *
 324   
          * @param evt Event to construct the queue item for.
 325   
          */
 326  1155
         WindowEventItem(final WindowEvent evt) {
 327  1155
             m_event     = evt;
 328  1155
             m_next      = null;
 329   
         }
 330   
 
 331   
         /**
 332   
          * Get the event.
 333   
          *
 334   
          * @return the event.
 335   
          */
 336  1155
         public WindowEvent getEvent() {
 337  1155
             return m_event;
 338   
         }
 339   
 
 340   
         /**
 341   
          * Set the next entry.
 342   
          *
 343   
          * @param n next item.
 344   
          */
 345  59
         public void setNext(final WindowEventItem n) {
 346  59
             m_next = n;
 347   
         }
 348   
 
 349   
         /**
 350   
          * Get the next entry.
 351   
          *
 352   
          * @return WindowEventItem next item.
 353   
          */
 354  1288
         public WindowEventItem getNext() {
 355  1288
             return m_next;
 356   
         }
 357   
     }
 358   
 
 359   
     /**
 360   
      * Check to see if the key is in the current
 361   
      * list.
 362   
      *
 363   
      * @param key Window to search for.
 364   
      * @return boolean true if the window is in the list.
 365   
      */
 366  896
     private boolean containsKey(final Window key) {
 367  896
       ArrayList toRemove = new ArrayList();
 368  896
       boolean result = false;
 369  896
       for (int i = 0; i < WINDOWS.size() && !result; i++) {
 370  2188
         WeakReference r = (WeakReference) WINDOWS.get(i);
 371  2188
         Window w = (Window) r.get();
 372  2188
         if (w == null) {
 373  3
           toRemove.add(r);
 374  2185
         } else if (w == key) {
 375  587
           result = true;
 376   
         }
 377   
       }
 378  896
       WINDOWS.removeAll(toRemove);
 379  896
       return result;
 380   
     }
 381   
 
 382   
     /**
 383   
      * Remove the window from the list.
 384   
      * @param key Window to be removed.
 385   
      * @return Object Window which was removed.
 386   
      */
 387  259
     private Object remove(final Window key) {
 388  259
       ArrayList toRemove = new ArrayList();
 389  259
       Object result = null;
 390  259
       for (int i = 0; i < WINDOWS.size() && result == null; i++) {
 391  546
         WeakReference r = (WeakReference) WINDOWS.get(i);
 392  546
         Window w = (Window) r.get();
 393  546
         if (w == null) {
 394  0
           toRemove.add(r);
 395  546
         } else if (w == key) {
 396  258
           toRemove.add(r);
 397  258
           result = w;
 398   
         }
 399   
       }
 400  259
       WINDOWS.removeAll(toRemove);
 401  259
       return result;
 402   
     }
 403   
 }
 404