KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > broker > StopMonitor


1 package com.ca.directory.jxplorer.broker;
2
3 import java.util.Vector JavaDoc;
4 import java.util.logging.Logger JavaDoc;
5 import java.awt.*;
6 import java.awt.event.*;
7 import javax.swing.*;
8
9 import com.ca.directory.jxplorer.*;
10 import com.ca.commons.cbutil.*;
11
12 /**
13  * The Stop Monitor interacts with the Brokers to cancel unwanted
14  * data queries. Since these data queries may well hang on
15  * dud connections etc., they are set to self-destruct whenever
16  * they 'complete' a cancelled request. Because of this the Stop Monitor starts
17  * up a replacement thread immediately after cancelling a particular
18  * request.
19  */

20  
21 public class StopMonitor
22 {
23     /**
24      * The Stop Monitor starts with a list of
25      * Brokers to keep track off.
26      */

27     
28     Vector JavaDoc watchList; // A vector of Brokers to monitor
29
Frame parent; // a link to the 'owning' gui, to be passed to the local gui
30

31     Vector JavaDoc watchingComponents; // A vector of components (e.g. gui 'stop buttons') linked to the StopMonitor state
32

33     StopMonitorGUI monitor;
34
35     static int threadID = 0; // a unique ID used for thread debugging.
36

37     private static Logger JavaDoc log = Logger.getLogger(StopMonitor.class.getName());
38
39     // An internal use data holder - we need to keep associations
40
// of threads and brokers, and threads/brokers/queries
41

42     protected class QueryBroker
43     {
44         public Broker broker;
45         public DataQuery query;
46         public int id;
47         
48         QueryBroker(Broker b, DataQuery q)
49         {
50             broker = b;
51             query = q;
52             id = q.id;
53         }
54     }
55
56     /**
57      * Creates a stop monitor to look after a list of brokers and the (single)
58      * thread that runs each broker.
59      */

60           
61     public StopMonitor(Broker[] brokerList, Frame parent)
62     {
63         this.parent = parent;
64     
65         watchList = new Vector JavaDoc(brokerList.length);
66     
67         watchingComponents = new Vector JavaDoc(4);
68     
69         for (int i=0; i<brokerList.length; i++)
70             add(brokerList[i]);
71     }
72
73     /**
74      * Add a new broker to the stop monitor.
75      */

76      
77     public void add(Broker b)
78     {
79         watchList.add(b);
80         b.registerStopMonitor(this);
81     }
82
83     /**
84      * Get a list of all the queries outstanding, and which brokers they
85      * belong to.
86      * @return a vector of QueryBroker objects.
87      */

88      
89     protected Vector JavaDoc getQueryBrokers()
90     {
91         int i, noBrokers = watchList.size();
92         
93         Vector JavaDoc doublets = new Vector JavaDoc(noBrokers*2); // guess initial size
94

95         // first get the queries currently being executed
96
for (i=0; i<noBrokers; i++)
97         {
98             Broker broker = (Broker)watchList.get(i);
99             DataQuery query = broker.getCurrent();
100             if (query != null && !query.isCancelled())
101                 doublets.add(new QueryBroker(broker, query));
102         }
103         
104         // now get all the queries waiting in queues.
105
for (i=0; i<noBrokers; i++)
106         {
107             Broker broker = (Broker)watchList.get(i);
108             Vector JavaDoc queries = broker.getRequestQueue();
109             for (int j=0; j<queries.size(); j++)
110                 doublets.add(new QueryBroker(broker, (DataQuery)queries.get(j)));
111         }
112         
113         return doublets;
114     }
115
116     /**
117     * See if any of the monitored brokers has any outstanding requests.
118     */

119     public boolean queriesPending()
120     {
121         // now get all the queries waiting in queues.
122
for (int i=0; i<watchList.size(); i++)
123         {
124             if ( ((Broker)watchList.get(i)).hasRequests() )
125                 return true;
126         }
127         
128         return false;
129     }
130
131     /**
132      * This registers a graphics component (such as a button) that
133      * should be enabled when there are queries pending, and disabled
134      * when there aren't.
135      */

136     public void addWatcher(Component c)
137     {
138         watchingComponents.add(c);
139     }
140
141     /**
142      * This works through all the registered 'watcher' components,
143      * and enables or disables them depending on whether there
144      * are queries waiting to be cancelled or not.
145      */

146      
147     public void updateWatchers()
148     {
149         boolean enableStatus = queriesPending();
150         
151         for (int i=0; i<watchingComponents.size(); i++)
152         {
153             Component c = (Component)watchingComponents.get(i);
154             if (c.isEnabled() != enableStatus)
155             {
156                 c.setEnabled(enableStatus);
157                 c.repaint();
158             }
159         }
160         
161     }
162
163
164      // PROG NOTE - this is intended to be run from the newly
165
// created StopMonitorPanel thread.
166

167     /**
168      * This cancels a particular query in a particular broker's queue.
169      * If the query is already in progress it marks the query as cancelled
170      * which will eventually lead to the death of the thread executing that
171      * query, and starts another thread to take over...
172      */

173       
174     protected void cancelQuery(QueryBroker pair)
175     {
176         if (pair == null) return;
177     
178         DataQuery query = pair.query;
179         Broker broker = pair.broker;
180         
181         //PROG NOTE - danger of contention here. Remember that a broker thread
182
// may briefly have a lock on the requestQuery queue
183

184         synchronized(this)
185         {
186             if (query.isRunning()) // badness - maybe a connection has hung or something. We have
187
{ // kill the query and start a new thread...
188
query.cancel();
189                 
190                 new Thread JavaDoc(broker, "restarted thread for: " + (threadID++) + " " + broker.getClass()).start();
191             }
192             else // nice 'n simple! - dump it from the array of queries and our work is done!
193
{
194                 broker.removeQuery(query);
195             }
196         }
197     }
198
199     /**
200      * This prompts the stop monitor to create a GUI showing the user the possible
201      * queries available to be stopped.
202      */

203      
204     public void show()
205     {
206         Vector JavaDoc QBs = getQueryBrokers();
207
208         if (QBs.size() == 0)
209         {
210              JOptionPane.showMessageDialog(parent,
211              CBIntText.get("There are no outstanding directory queries to cancel."),
212              CBIntText.get("Nothing to do."), JOptionPane.INFORMATION_MESSAGE);
213              return;
214         }
215     
216         if (monitor!=null)
217         {
218             monitor.update();
219             if (monitor.singleDelete() == false)
220                 monitor.setVisible(true);
221         }
222         else
223         {
224             monitor = new StopMonitorGUI(this, QBs);
225             monitor.setSize(300, 400);
226             CBUtility.center(monitor, parent);
227     
228             // We need to stick the monitor in a separate thread, because the action
229
// of deleting a query may itself hang...
230
Thread JavaDoc buttonMonitor = new Thread JavaDoc(monitor, "Stop Monitor Thread");
231             buttonMonitor.start();
232             
233             if (monitor.singleDelete() == false)
234                 monitor.setVisible(true);
235         }
236     }
237
238
239
240     //
241
// START StopMonitorGUI class
242
//
243

244     /**
245      * This class is used to display a gui list of cancel-able queries to the user.
246      * The main StopMonitor class does the hard work.
247      * The gui implements a runnable thread that is notified when the user
248      * hits a button, and calls (from the separate thread) the main StopMonitor
249      * class to delete queries. The thread is ended when the gui is closed.
250      */

251      
252     class StopMonitorGUI extends JDialog implements Runnable JavaDoc
253     {
254         JList list;
255         DefaultListModel model;
256         StopMonitor myMonitor;
257         boolean finished = false; // whether the stop monitor has been closed by the user
258
boolean selected = false; // whether a selection has been made by the user
259
QueryBroker selectedQuery = null; // which data query has been selected.
260

261         StopMonitorGUI(StopMonitor myMonitor, Vector JavaDoc queryBrokers)
262         {
263             super(myMonitor.parent);
264             this.myMonitor = myMonitor;
265             
266             model = new DefaultListModel();
267             list = new JList(model);
268             for (int i=0; i<queryBrokers.size(); i++)
269                 model.addElement(queryBrokers.get(i));
270                             
271             list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
272             list.setSelectionModel(new CBSingleSelectionModel(list)); //TE: tries to ensure that the selected item is visible.
273
list.setCellRenderer(new StopMonitorListRenderer());
274             list.setVisibleRowCount(6);
275             list.setSelectedIndex(0);
276             
277             JScrollPane scrollPane = new JScrollPane();
278             scrollPane.getViewport().setView(list);
279             getContentPane().add("Center", scrollPane);
280             
281             JPanel buttonPanel = new JPanel();
282             buttonPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
283             
284             CBButton ok, cancel, help;
285             buttonPanel.add(ok = new CBButton(CBIntText.get("Delete Query"), CBIntText.get("Delete the current query.")));
286             buttonPanel.add(cancel = new CBButton(CBIntText.get("Exit"), CBIntText.get("Exit this window.")));
287             buttonPanel.add(help = new CBButton(CBIntText.get("Help"), CBIntText.get("Open the help.")));
288             CBHelpSystem.useDefaultHelp(help, HelpIDs.ABORT); //TE: direct link to the topic in the help.
289
getContentPane().add("South", buttonPanel);
290             
291             ok.addActionListener(new ActionListener()
292             {
293                 public void actionPerformed(ActionEvent e)
294                 {
295                     cancelSelectedQuery(); // get the selected query and cancel it.
296
}
297             });
298             
299             cancel.addActionListener(new ActionListener()
300             {
301                 public void actionPerformed(ActionEvent e)
302                 {
303                     setVisible(false);
304                 }
305             });
306
307             list.addMouseListener(new MouseAdapter()
308             {
309                  public void mouseClicked(MouseEvent e)
310                  {
311                      if (e.getClickCount() == 2) cancelSelectedQuery(); // get the selected query and cancel it.
312
}
313             });
314         }
315         
316         
317
318         /**
319          * Updates the list of queries/Broker pairs, maintaining the selection (if possible)
320          */

321         protected void update()
322         {
323             int selectedID = -1;
324             
325             Vector JavaDoc queryBrokers = myMonitor.getQueryBrokers();
326             
327             QueryBroker selectedQuery = (QueryBroker)list.getSelectedValue(); // cache currently selected query
328
if (selectedQuery != null)
329                 selectedID = selectedQuery.id;
330             
331             model.removeAllElements();
332             
333             for (int i=0; i<queryBrokers.size(); i++)
334             {
335                 QueryBroker newQuery = (QueryBroker)queryBrokers.get(i);
336                 model.addElement(newQuery);
337                 if (selectedID == newQuery.id)
338                     list.setSelectedValue(newQuery, true); // re-assert selection
339
}
340                 
341         }
342
343
344
345         /**
346          * Called when the user has selected an item, and either double clicked
347          * or hit 'o.k.'.
348          */

349          
350         protected void cancelSelectedQuery()
351         {
352             synchronized(this)
353             {
354                 if (list.getSelectedIndex() == -1)
355                 {
356                      JOptionPane.showMessageDialog(this.getContentPane(),
357                      CBIntText.get("You must select a query to stop from the list") + "\n" +
358                      CBIntText.get("otherwise you can just use the 'cancel' button."),
359                      CBIntText.get("Stop Monitor Help"), JOptionPane.INFORMATION_MESSAGE);
360                 }
361                 else
362                 {
363                     selectedQuery = (QueryBroker)list.getSelectedValue();
364                     selected = true;
365                     model.removeElement(selectedQuery);
366                     notify();
367                 }
368             }
369         }
370         
371         public void setVisible(boolean status)
372         {
373             super.setVisible(status);
374             synchronized(this)
375             {
376                 if (status == true) notify(); // wake up status polling thread.
377
}
378         }
379
380         /**
381         * Checks if there is only a single query to delete. If there is, it
382         * deletes it and returns true. Otherwise it sets the selected index
383         * to zero, and returns false.
384         * @return whether there was only a single query, now deleted.
385         */

386         public boolean singleDelete()
387         {
388             if (model.size() == 0) return false; // *huh*? shouldn't ever happen.
389
list.setSelectedIndex(0);
390             if (model.size() == 1)
391             {
392                 cancelSelectedQuery();
393                 return true;
394             }
395             return false;
396         }
397         
398         /**
399          * Do thread magic. This loops, waiting until it is
400          * notified that selectedQuery has changed. It will
401          * then attempt to delete that query. While the monitor
402          * is visible it should also poll the queue status every
403          * 250 ms for changes.
404          */

405          
406         public void run()
407         {
408             while (!finished)
409             {
410                 try
411                 {
412                     synchronized(this)
413                     {
414                         if (selectedQuery != null)
415                         {
416                             myMonitor.cancelQuery(selectedQuery); // cancel query
417
selectedQuery = null; // and reset 'query to cancel' variable.
418
}
419                         
420                         if (isVisible()) // we want to keep polling the task list while active.
421
wait(250);
422                         else
423                             wait();
424                             
425                         update();
426                     }
427                 }
428                 catch (InterruptedException JavaDoc e)
429                 {
430                     CBUtility.error("Exception in stop monitor: ", e);
431                 }
432             }
433         }
434     }
435
436
437
438     //
439
// END StopMonitorGUI class
440
//
441

442
443     //
444
// START StopMonitorListRenderer class
445
//
446

447
448     /**
449      * A quicky cell renderer to allow us to display active and pending
450      * queries in different colours, and to display the text of a
451      * QueryBroker object.
452      */

453      
454     class StopMonitorListRenderer extends JLabel implements ListCellRenderer
455     {
456         Color highlight = new Color(0,0,128);
457         Color active = new Color(128,0,0);
458         Color pending = new Color(0,128,0);
459         Color cancelled = new Color(64,64,64);
460         
461         StopMonitorListRenderer()
462         {
463             setOpaque(true);
464         }
465     
466         public Component getListCellRendererComponent(JList list, Object JavaDoc value, int index,
467                                                         boolean isSelected, boolean cellHasFocus)
468         {
469             if (value instanceof QueryBroker == false) // should never happen :-)
470
{
471                 log.warning("Rendering error in StopMonitor"); setText("error"); return this;
472             }
473             
474             if (index == -1)
475             {
476                 int selected = list.getSelectedIndex();
477                 if (selected == -1)
478                     return this;
479                 else
480                     index = selected;
481             }
482
483             DataQuery item = ((QueryBroker)value).query;
484             
485             if (item == null) // shouldn't happen
486
{
487                 setBackground(Color.white);
488                 setForeground(cancelled);
489                 setText("<deleted>");
490                 return this;
491             }
492             
493             setText(item.toString());
494             Color back = Color.white;
495             Color fore = Color.black;
496          
497             if (item.isCancelled())
498                 fore = cancelled;
499             else if (item.isRunning())
500                 fore = active;
501             else
502                 fore = pending;
503                 
504             if (isSelected)
505             {
506                 setBackground(highlight);
507                 setForeground(Color.white);
508             }
509             else
510             {
511                 setBackground(back);
512                 setForeground(fore);
513             }
514             return this;
515         }
516     }
517
518     //
519
// STOP StopMonitorListRenderer class
520
//
521
}
Popular Tags