View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j.chainsaw.receivers;
    19
    20  import java.awt.*;
    21  import java.awt.event.ActionEvent;
    22  import java.awt.event.ActionListener;
    23  import java.awt.event.KeyEvent;
    24  import java.util.ArrayList;
    25  import java.util.Collection;
    26  import java.util.Iterator;
    27  import java.util.List;
    28  import java.util.Map;
    29
    30  import java.io.File;
    31
    32  import javax.swing.AbstractAction;
    33  import javax.swing.Action;
    34  import javax.swing.BorderFactory;
    35  import javax.swing.Box;
    36  import javax.swing.Icon;
    37  import javax.swing.ImageIcon;
    38  import javax.swing.JComponent;
    39  import javax.swing.JDialog;
    40  import javax.swing.JFrame;
    41  import javax.swing.JMenuItem;
    42  import javax.swing.JOptionPane;
    43  import javax.swing.JPanel;
    44  import javax.swing.JPopupMenu;
    45  import javax.swing.JRadioButtonMenuItem;
    46  import javax.swing.JScrollPane;
    47  import javax.swing.JSplitPane;
    48  import javax.swing.JToolBar;
    49  import javax.swing.JTree;
    50  import javax.swing.SwingUtilities;
    51  import javax.swing.event.TreeExpansionEvent;
    52  import javax.swing.event.TreeModelEvent;
    53  import javax.swing.event.TreeModelListener;
    54  import javax.swing.event.TreeSelectionEvent;
    55  import javax.swing.event.TreeSelectionListener;
    56  import javax.swing.event.TreeWillExpandListener;
    57  import javax.swing.tree.DefaultMutableTreeNode;
    58  import javax.swing.tree.ExpandVetoException;
    59  import javax.swing.tree.TreePath;
    60
    61  import org.apache.log4j.Level;
    62  import org.apache.log4j.LogManager;
    63  import org.apache.log4j.Logger;
    64  import org.apache.log4j.chainsaw.PopupListener;
    65  import org.apache.log4j.chainsaw.SmallButton;
    66  import org.apache.log4j.chainsaw.prefs.SettingsManager;
    67  import org.apache.log4j.chainsaw.prefs.SettingsListener;
    68  import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
    69  import org.apache.log4j.chainsaw.prefs.LoadSettingsEvent;
    70  import org.apache.log4j.chainsaw.help.HelpManager;
    71  import org.apache.log4j.chainsaw.helper.SwingHelper;
    72  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
    73  import org.apache.log4j.chainsaw.icons.LevelIconFactory;
    74  import org.apache.log4j.chainsaw.icons.LineIconFactory;
    75  import org.apache.log4j.chainsaw.messages.MessageCenter;
    76  import org.apache.log4j.net.SocketNodeEventListener;
    77  import org.apache.log4j.net.SocketReceiver;
    78  import org.apache.log4j.plugins.Pauseable;
    79  import org.apache.log4j.plugins.Plugin;
    80  import org.apache.log4j.plugins.PluginEvent;
    81  import org.apache.log4j.plugins.PluginListener;
    82  import org.apache.log4j.plugins.PluginRegistry;
    83  import org.apache.log4j.plugins.Receiver;
    84  import org.apache.log4j.spi.LoggerRepository;
    85  import org.apache.log4j.spi.LoggerRepositoryEx;
    86
    87
    88  /**
    89   * This panel is used to manage all the Receivers configured within Log4j
    90   *
    91   *
    92   * @author Paul Smith &lt;psmith@apache.org&gt;
    93   * @author Scott Deboy &lt;sdeboy@apache.org&gt;
    94   */
    95  public class ReceiversPanel extends JPanel implements SettingsListener {
    96    final Action newReceiverButtonAction;
    97    final Action pauseReceiverButtonAction;
    98    final Action playReceiverButtonAction;
    99    final Action shutdownReceiverButtonAction;
    100   final Action saveReceiversButtonAction;
    101   final Action restartReceiverButtonAction;
    102   private final Action showReceiverHelpAction;
    103   private final Action startAllAction;
    104   private final JPopupMenu popupMenu = new ReceiverPopupMenu();
    105   private final JTree receiversTree = new JTree();
    106   private final NewReceiverPopupMenu newReceiverPopup =
    107     new NewReceiverPopupMenu();
    108   private final ReceiverToolbar buttonPanel;
    109   private final JSplitPane splitter = new JSplitPane();
    110   private final PluginPropertyEditorPanel pluginEditorPanel =
    111     new PluginPropertyEditorPanel();
    112   private final Logger logger = LogManager.getLogger(ReceiversPanel.class);
    113
    114   private final PluginRegistry pluginRegistry;
    115
    116
    117   public ReceiversPanel() {
    118     super(new BorderLayout());
    119     LoggerRepository repo = LogManager.getLoggerRepository();
    120     final ReceiversTreeModel model = new ReceiversTreeModel();
    121     if (repo instanceof LoggerRepositoryEx) {
    122        pluginRegistry = ((LoggerRepositoryEx) repo).getPluginRegistry();
    123        pluginRegistry.addPluginListener(model);
    124
    125        //iterate over visual receivers and call setcontainer
    126        Collection c = pluginRegistry.getPlugins(VisualReceiver.class);
    127        for (Iterator iter = c.iterator();iter.hasNext();) {
    128     	   ((VisualReceiver)iter.next()).setContainer(this);
    129        }
    130
    131        pluginRegistry.addPluginListener(new PluginListener() {
    132 		public void pluginStarted(PluginEvent e) {
    133 			//if we get a plugin started callback, set the container
    134 			if (e.getPlugin() instanceof VisualReceiver) {
    135 				((VisualReceiver)e.getPlugin()).setContainer(ReceiversPanel.this);
    136 			}
    137 		}
    138
    139 		public void pluginStopped(PluginEvent e) {
    140 		}
    141        });
    142     } else {
    143        pluginRegistry = null;
    144     }
    145
    146     receiversTree.setModel(model);
    147
    148     receiversTree.setExpandsSelectedPaths(true);
    149     model.addTreeModelListener(
    150       new TreeModelListener() {
    151         public void treeNodesChanged(TreeModelEvent e) {
    152           expandRoot();
    153         }
    154
    155         public void treeNodesInserted(TreeModelEvent e) {
    156           expandRoot();
    157         }
    158
    159         public void treeNodesRemoved(TreeModelEvent e) {
    160           expandRoot();
    161         }
    162
    163         public void treeStructureChanged(TreeModelEvent e) {
    164           expandRoot();
    165         }
    166
    167         private void expandRoot() {
    168           receiversTree.expandPath(
    169             new TreePath(model.getPathToRoot(model.RootNode)));
    170         }
    171       });
    172     receiversTree.expandPath(
    173       new TreePath(model.getPathToRoot(model.RootNode)));
    174
    175     receiversTree.addTreeWillExpandListener(
    176       new TreeWillExpandListener() {
    177         public void treeWillCollapse(TreeExpansionEvent event)
    178           throws ExpandVetoException {
    179           if (event.getPath().getLastPathComponent() == model.RootNode) {
    180             throw new ExpandVetoException(event);
    181           }
    182         }
    183
    184         public void treeWillExpand(TreeExpansionEvent event)
    185           throws ExpandVetoException {
    186         }
    187       });
    188
    189     receiversTree.addTreeSelectionListener(
    190       new TreeSelectionListener() {
    191         public void valueChanged(TreeSelectionEvent e) {
    192           TreePath path = e.getNewLeadSelectionPath();
    193
    194           if (path != null) {
    195             DefaultMutableTreeNode node =
    196               (DefaultMutableTreeNode) path.getLastPathComponent();
    197
    198             if (
    199               (node != null) && (node.getUserObject() != null)
    200                 && (node.getUserObject() instanceof Plugin)) {
    201               Plugin p = (Plugin) node.getUserObject();
    202               logger.debug("plugin=" + p);
    203               pluginEditorPanel.setPlugin(p);
    204             } else {
    205               pluginEditorPanel.setPlugin(null);
    206             }
    207           }
    208         }
    209       });
    210
    211     receiversTree.setToolTipText("Allows you to manage Log4j Receivers");
    212     newReceiverButtonAction =
    213       new AbstractAction() {
    214           public void actionPerformed(ActionEvent e) {
    215             newReceiverPopup.show(
    216               buttonPanel.newReceiverButton, 0,
    217               buttonPanel.newReceiverButton.getHeight());
    218           }
    219         };
    220     newReceiverButtonAction.putValue(
    221       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ICON_NEW_RECEIVER));
    222     newReceiverButtonAction.putValue(
    223       Action.SHORT_DESCRIPTION, "Creates and configures a new Receiver");
    224     newReceiverButtonAction.putValue(Action.NAME, "New Receiver");
    225     newReceiverButtonAction.putValue(
    226       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
    227
    228     newReceiverButtonAction.setEnabled(true);
    229
    230     playReceiverButtonAction =
    231       new AbstractAction() {
    232           public void actionPerformed(ActionEvent e) {
    233             playCurrentlySelectedReceiver();
    234           }
    235         };
    236
    237     playReceiverButtonAction.putValue(
    238       Action.SHORT_DESCRIPTION, "Resumes the selected Node");
    239     playReceiverButtonAction.putValue(Action.NAME, "Resume");
    240     playReceiverButtonAction.putValue(
    241       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ICON_RESUME_RECEIVER));
    242     playReceiverButtonAction.setEnabled(false);
    243     playReceiverButtonAction.putValue(
    244       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
    245
    246     pauseReceiverButtonAction =
    247       new AbstractAction() {
    248           public void actionPerformed(ActionEvent e) {
    249             pauseCurrentlySelectedReceiver();
    250           }
    251         };
    252
    253     pauseReceiverButtonAction.putValue(
    254       Action.SHORT_DESCRIPTION,
    255       "Pause the selected Receiver.  All events received will be discarded.");
    256     pauseReceiverButtonAction.putValue(Action.NAME, "Pause");
    257
    258     pauseReceiverButtonAction.putValue(
    259       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
    260
    261     pauseReceiverButtonAction.putValue(
    262       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.PAUSE));
    263     pauseReceiverButtonAction.setEnabled(false);
    264
    265     shutdownReceiverButtonAction =
    266       new AbstractAction() {
    267           public void actionPerformed(ActionEvent e) {
    268             shutdownCurrentlySelectedReceiver();
    269           }
    270         };
    271
    272     shutdownReceiverButtonAction.putValue(
    273       Action.SHORT_DESCRIPTION,
    274       "Shuts down the selected Receiver, and removes it from the Plugin registry");
    275     shutdownReceiverButtonAction.putValue(Action.NAME, "Shutdown");
    276
    277     shutdownReceiverButtonAction.putValue(
    278       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ICON_STOP_RECEIVER));
    279     shutdownReceiverButtonAction.putValue(
    280       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S));
    281
    282     shutdownReceiverButtonAction.setEnabled(false);
    283
    284     saveReceiversButtonAction =
    285       new AbstractAction() {
    286           public void actionPerformed(ActionEvent e) {
    287             saveReceivers();
    288           }
    289         };
    290
    291     saveReceiversButtonAction.putValue(
    292       Action.SHORT_DESCRIPTION,
    293       "Save the current receiver configuration");
    294     saveReceiversButtonAction.putValue(Action.NAME, "Save receivers");
    295
    296     saveReceiversButtonAction.putValue(
    297       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.FILE_SAVE_AS));
    298     saveReceiversButtonAction.putValue(
    299       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_V));
    300
    301
    302     restartReceiverButtonAction =
    303         new AbstractAction() {
    304             public void actionPerformed(ActionEvent e) {
    305               Receiver selectedReceiver = getCurrentlySelectedReceiver();
    306               if(selectedReceiver == null){
    307               	return;
    308               }
    309               selectedReceiver.shutdown();
    310               selectedReceiver.activateOptions();
    311               //allow the visual receiver to get a container on restart
    312               if (selectedReceiver instanceof VisualReceiver) {
    313                   ((VisualReceiver)selectedReceiver).setContainer(ReceiversPanel.this);
    314               }
    315             }
    316           };
    317
    318       restartReceiverButtonAction.putValue(
    319         Action.SHORT_DESCRIPTION,
    320         "Restarts the selected Receiver");
    321       restartReceiverButtonAction.putValue(Action.NAME, "Restart");
    322
    323       restartReceiverButtonAction.putValue(
    324         Action.SMALL_ICON, new ImageIcon(ChainsawIcons.ICON_RESTART));
    325       restartReceiverButtonAction.putValue(
    326         Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
    327
    328       restartReceiverButtonAction.setEnabled(false);
    329
    330     showReceiverHelpAction =
    331       new AbstractAction("Help") {
    332           public void actionPerformed(ActionEvent e) {
    333             Receiver receiver = getCurrentlySelectedReceiver();
    334
    335             if (receiver != null) {
    336               HelpManager.getInstance().showHelpForClass(receiver.getClass());
    337             }
    338           }
    339         };
    340
    341     showReceiverHelpAction.putValue(
    342       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.HELP));
    343     showReceiverHelpAction.putValue(
    344       Action.SHORT_DESCRIPTION, "Displays the JavaDoc page for this Plugin");
    345
    346     startAllAction =
    347       new AbstractAction(
    348         "(Re)start All Receivers", new ImageIcon(ChainsawIcons.ICON_RESTART_ALL)) {
    349           public void actionPerformed(ActionEvent e) {
    350             if (
    351               JOptionPane.showConfirmDialog(
    352                   null,
    353                   "This will cause any active Receiver to stop, and disconnect.  Is this ok?",
    354                   "Confirm", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
    355               new Thread(
    356                 new Runnable() {
    357                   public void run() {
    358                     Collection allReceivers =
    359                         pluginRegistry.getPlugins(Receiver.class);
    360
    361                     for (Iterator iter = allReceivers.iterator();
    362                         iter.hasNext();) {
    363                       Receiver item = (Receiver) iter.next();
    364                       item.shutdown();
    365                       item.activateOptions();
    366                     }
    367
    368                     updateReceiverTreeInDispatchThread();
    369                     MessageCenter.getInstance().getLogger().info(
    370                       "All Receivers have been (re)started");
    371                   }
    372                 }).start();
    373             }
    374           }
    375         };
    376
    377     startAllAction.putValue(
    378       Action.SHORT_DESCRIPTION,
    379       "Ensures that any Receiver that isn't active, is started, and any started action is stopped, and then restarted");
    380
    381     receiversTree.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    382     receiversTree.setCellRenderer(new ReceiverTreeCellRenderer());
    383     receiversTree.setRowHeight(19);
    384
    385     buttonPanel = new ReceiverToolbar();
    386     receiversTree.addTreeSelectionListener(buttonPanel);
    387
    388     PopupListener popupListener = new PopupListener(popupMenu);
    389     receiversTree.addMouseListener(popupListener);
    390     this.addMouseListener(popupListener);
    391
    392     JComponent component = receiversTree;
    393     JScrollPane pane = new JScrollPane(component);
    394
    395     splitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
    396
    397     splitter.setTopComponent(pane);
    398     splitter.setBottomComponent(pluginEditorPanel);
    399
    400     splitter.setResizeWeight(0.7);
    401     add(buttonPanel, BorderLayout.NORTH);
    402     add(splitter, BorderLayout.CENTER);
    403
    404     /**
    405      * This Tree likes to be notified when Socket's are accepted so
    406      * we listen for them and update the Tree.
    407      */
    408     SocketNodeEventListener listener =
    409       new SocketNodeEventListener() {
    410         public void socketOpened(String remoteInfo) {
    411           updateReceiverTreeInDispatchThread();
    412         }
    413
    414         public void socketClosedEvent(Exception e) {
    415           updateReceiverTreeInDispatchThread();
    416         }
    417       };
    418
    419     /**
    420      * add this listener to all SocketReceivers
    421      */
    422     if (pluginRegistry != null) {
    423     	List socketReceivers =
    424       		pluginRegistry.getPlugins(SocketReceiver.class);
    425
    426     	for (Iterator iter = socketReceivers.iterator(); iter.hasNext();) {
    427       		SocketReceiver element = (SocketReceiver) iter.next();
    428       		element.addSocketNodeEventListener(listener);
    429     	}
    430      }
    431   }
    432
    433   private void saveReceivers() {
    434     File saveConfigFile = SwingHelper.promptForFile(this, null, "Save receiver configuration XML file", false);
    435     if (saveConfigFile != null) {
    436       ReceiversHelper.getInstance().saveReceiverConfiguration(saveConfigFile);
    437     }
    438   }
    439
    440   protected ReceiversTreeModel getReceiverTreeModel() {
    441     return ((ReceiversTreeModel) receiversTree.getModel());
    442   }
    443
    444   /**
    445    *
    446    */
    447   protected void updateCurrentlySelectedNodeInDispatchThread() {
    448     SwingUtilities.invokeLater(
    449       new Runnable() {
    450         public void run() {
    451           DefaultMutableTreeNode node =
    452             (DefaultMutableTreeNode) receiversTree
    453             .getLastSelectedPathComponent();
    454
    455           if (node == null) {
    456             return;
    457           }
    458
    459           getReceiverTreeModel().nodeChanged(node);
    460           updateActions();
    461         }
    462       });
    463   }
    464
    465   /**
    466    * Returns the currently selected Receiver, or null if there is no
    467    * selected Receiver (this could be because a) nothing at all is selected
    468    * or b) a non Receiver type node is selected
    469    *
    470    * @return Receiver or null
    471    */
    472   private Receiver getCurrentlySelectedReceiver() {
    473     DefaultMutableTreeNode node =
    474       (DefaultMutableTreeNode) receiversTree.getLastSelectedPathComponent();
    475
    476     if (node == null) {
    477       return null;
    478     }
    479
    480     Object userObject = node.getUserObject();
    481
    482     if (userObject instanceof Receiver) {
    483       return (Receiver) userObject;
    484     }
    485
    486     return null;
    487   }
    488
    489   private Receiver[] getSelectedReceivers() {
    490     TreePath[] paths = receiversTree.getSelectionPaths();
    491     Collection receivers = new ArrayList();
    492
    493     for (int i = 0; i < paths.length; i++) {
    494       TreePath path = paths[i];
    495       DefaultMutableTreeNode node =
    496         (DefaultMutableTreeNode) path.getLastPathComponent();
    497
    498       if ((node != null) && node.getUserObject() instanceof Receiver) {
    499         receivers.add(node.getUserObject());
    500       }
    501     }
    502
    503     return (Receiver[]) receivers.toArray(new Receiver[0]);
    504   }
    505
    506   /**
    507    * Returns the currently seleted node's User Object, or null
    508    * if there is no selected node, or if the currently selected node has
    509    * not user Object
    510    * @return Object representing currently seleted Node's User Object
    511    */
    512   private Object getCurrentlySelectedUserObject() {
    513     DefaultMutableTreeNode node =
    514       (DefaultMutableTreeNode) receiversTree.getLastSelectedPathComponent();
    515
    516     if (node == null) {
    517       return null;
    518     }
    519
    520     return node.getUserObject();
    521   }
    522
    523   /**
    524    * Takes the currently selected Receiver and pauess it, effectively
    525    * discarding any received event BEFORE it is even posted to the logger
    526    * repository.
    527    *
    528    * The user is NOT asked to confirm this operation
    529    *
    530    */
    531   private void pauseCurrentlySelectedReceiver() {
    532     new Thread(
    533       new Runnable() {
    534         public void run() {
    535           Object obj = getCurrentlySelectedUserObject();
    536
    537           if ((obj != null) && obj instanceof Pauseable) {
    538             ((Pauseable) obj).setPaused(true);
    539             updateCurrentlySelectedNodeInDispatchThread();
    540           }
    541         }
    542       }).start();
    543   }
    544
    545   /**
    546    * Ensures that the currently selected receiver active property is set to
    547    * true
    548    *
    549    */
    550   private void playCurrentlySelectedReceiver() {
    551     new Thread(
    552       new Runnable() {
    553         public void run() {
    554           Object obj = getCurrentlySelectedUserObject();
    555
    556           if ((obj != null) && obj instanceof Pauseable) {
    557             ((Pauseable) obj).setPaused(false);
    558
    559             updateCurrentlySelectedNodeInDispatchThread();
    560           }
    561         }
    562       }).start();
    563   }
    564
    565   /**
    566    * Takes the currently selected Receiver and stops it, which effectively
    567    * removes it from the PluginRegistry.
    568    *
    569    * The user is asked to confirm this operation
    570    *
    571    */
    572   private void shutdownCurrentlySelectedReceiver() {
    573     if (
    574       JOptionPane.showConfirmDialog(
    575           null,
    576           "Are you sure you wish to shutdown this receiver?\n\nThis will disconnect any network resources, and remove it from the PluginRegistry.",
    577           "Confirm stop of Receiver", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) {
    578       new Thread(
    579         new Runnable() {
    580           public void run() {
    581             Receiver[] receivers = getSelectedReceivers();
    582
    583             if (receivers != null) {
    584               for (int i = 0; i < receivers.length; i++) {
    585                 pluginRegistry.stopPlugin(receivers[i].getName());
    586               }
    587             }
    588           }
    589         }).start();
    590     }
    591   }
    592
    593   /**
    594    * Sets the state of actions depending on certain conditions (i.e what is
    595    * currently selected etc.)
    596    */
    597   private void updateActions() {
    598     Object object = getCurrentlySelectedUserObject();
    599
    600     if ((object != null) && object instanceof Pauseable) {
    601       Pauseable pauseable = (Pauseable) object;
    602
    603       if (!pauseable.isPaused()) {
    604         pauseReceiverButtonAction.setEnabled(true);
    605         playReceiverButtonAction.setEnabled(false);
    606       } else {
    607         pauseReceiverButtonAction.setEnabled(false);
    608         playReceiverButtonAction.setEnabled(true);
    609       }
    610     } else {
    611       pauseReceiverButtonAction.setEnabled(false);
    612       playReceiverButtonAction.setEnabled(false);
    613     }
    614
    615     if (object instanceof Receiver) {
    616       newReceiverButtonAction.setEnabled(true);
    617       shutdownReceiverButtonAction.setEnabled(true);
    618       restartReceiverButtonAction.setEnabled(true);
    619     } else {
    620       shutdownReceiverButtonAction.setEnabled(false);
    621       restartReceiverButtonAction.setEnabled(false);
    622     }
    623   }
    624
    625   /**
    626    * Ensures that the Receiver tree is updated with the latest information
    627    * and that this operation occurs in the Swing Event Dispatch thread.
    628    *
    629    */
    630   public void updateReceiverTreeInDispatchThread() {
    631     logger.debug(
    632       "updateReceiverTreeInDispatchThread, should not be needed now");
    633
    634     //    if (SwingUtilities.isEventDispatchThread()) {
    635     //      updateReceiverTree.run();
    636     //    } else {
    637     //      SwingUtilities.invokeLater(updateReceiverTree);
    638     //    }
    639   }
    640
    641   /* (non-Javadoc)
    642    * @see java.awt.Component#setVisible(boolean)
    643    */
    644   public void setVisible(boolean aFlag) {
    645     boolean oldValue = isVisible();
    646     super.setVisible(aFlag);
    647     firePropertyChange("visible", oldValue, isVisible());
    648   }
    649
    650   public void loadSettings(LoadSettingsEvent event){}
    651
    652    /**
    653     * Saves all the receivers which are active at shut down as a configuration
    654     * file which can be loaded when Chainsaw will be restarted.
    655     */
    656
    657   public void saveSettings(SaveSettingsEvent event){
    658      File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
    659      ReceiversHelper.getInstance().saveReceiverConfiguration(file);
    660   }
    661
    662   /**
    663    * A popup menu that allows the user to choose which
    664    * style of Receiver to create, which spawns a relevant Dialog
    665    * to enter the information and create the Receiver
    666    *
    667    * @author Paul Smith &lt;psmith@apache.org&gt;
    668    *
    669    */
    670   class NewReceiverPopupMenu extends JPopupMenu {
    671     NewReceiverPopupMenu() {
    672       try {
    673         final List receiverList =
    674           ReceiversHelper.getInstance().getKnownReceiverClasses();
    675         String separatorCheck = null;
    676
    677         for (Iterator iter = receiverList.iterator(); iter.hasNext();) {
    678           final Class toCreate = (Class) iter.next();
    679           Package thePackage = toCreate.getPackage();
    680           final String name =
    681             toCreate.getName().substring(thePackage.getName().length() + 1);
    682
    683           if (separatorCheck == null) {
    684             separatorCheck = name.substring(0, 1);
    685           } else {
    686             String current = name.substring(0, 1);
    687
    688             if (!current.equals(separatorCheck)) {
    689               addSeparator();
    690               separatorCheck = current;
    691             }
    692           }
    693
    694           add(
    695             new AbstractAction("New " + name + "...") {
    696               public void actionPerformed(ActionEvent e) {
    697                 Container container = SwingUtilities.getAncestorOfClass(JFrame.class, ReceiversPanel.this);
    698                 final JDialog dialog = new JDialog((JFrame) container,"New " + toCreate.getName() + "..." ,true);
    699
    700                 try {
    701                   final NewReceiverDialogPanel panel =
    702                     NewReceiverDialogPanel.create(toCreate);
    703                   dialog.getContentPane().add(panel);
    704                   dialog.pack();
    705                   SwingHelper.centerOnScreen(dialog);
    706
    707                   /**
    708                    * Make the default button the ok button
    709                    */
    710                   dialog.getRootPane().setDefaultButton(panel.getOkPanel().getOkButton());
    711
    712                   /**
    713                    * Use the standard Cancel metaphor
    714                    */
    715                   SwingHelper.configureCancelForDialog(dialog, panel.getOkPanel().getCancelButton());
    716
    717
    718                   panel.getOkPanel().getOkButton().addActionListener(
    719                     new ActionListener() {
    720                       public void actionPerformed(ActionEvent e2) {
    721                         Plugin plugin = panel.getPlugin();
    722                         if (plugin.getName() != null && !plugin.getName().trim().equals("")) {
    723                             dialog.dispose();
    724                             pluginRegistry.addPlugin(plugin);
    725                             plugin.activateOptions();
    726                             MessageCenter.getInstance().addMessage("Plugin '" + plugin.getName() + "' started");
    727                         } else {
    728                             MessageCenter.getInstance().getLogger().error("Name required to create receiver");
    729                         }
    730                       }
    731                     });
    732                   dialog.setVisible(true);
    733                 } catch (Exception e1) {
    734                   e1.printStackTrace();
    735                   MessageCenter.getInstance().getLogger().error(
    736                     "Failed to create the new Receiver dialog", e1);
    737                 }
    738               }
    739             });
    740         }
    741       } catch (Exception e) {
    742         e.printStackTrace();
    743         throw new RuntimeException(e.getMessage());
    744       }
    745     }
    746   }
    747
    748   /**
    749    * A popup menu class for when the user uses the popup trigger action
    750    * on a node in the Receiver tree.
    751    *
    752    * @author Paul Smith &lt;psmith@apache.org&gt;
    753    *
    754    */
    755   class ReceiverPopupMenu extends JPopupMenu {
    756     ReceiverPopupMenu() {
    757     }
    758
    759     /* (non-Javadoc)
    760      * @see javax.swing.JPopupMenu#show(java.awt.Component, int, int)
    761      */
    762     public void show(Component invoker, int x, int y) {
    763       DefaultMutableTreeNode node =
    764         (DefaultMutableTreeNode) receiversTree.getLastSelectedPathComponent();
    765
    766       if (node == null) {
    767         return;
    768       }
    769
    770       Object userObject = node.getUserObject();
    771       removeAll();
    772
    773       if (userObject == getRootOfTree().getUserObject()) {
    774         buildForReceiversRoot();
    775       } else if (getCurrentlySelectedReceiver() != null) {
    776         buildForReceiverNode();
    777       } else {
    778         return;
    779       }
    780
    781       this.invalidate();
    782       this.validate();
    783
    784       super.show(invoker, x, y);
    785     }
    786
    787     /**
    788      *
    789      */
    790     private DefaultMutableTreeNode getRootOfTree() {
    791       return (DefaultMutableTreeNode) receiversTree.getModel().getRoot();
    792     }
    793
    794     /**
    795      * Builds the popup menu with relevant items for a selected
    796      * Receiver node in the Tree.
    797      */
    798     private void buildForReceiverNode() {
    799
    800       add(playReceiverButtonAction);
    801       add(pauseReceiverButtonAction);
    802       add(restartReceiverButtonAction);
    803       add(shutdownReceiverButtonAction);
    804       add(saveReceiversButtonAction);
    805
    806       addSeparator();
    807
    808       final Receiver r = getCurrentlySelectedReceiver();
    809       add(createLevelRadioButton(r, Level.TRACE));
    810       add(createLevelRadioButton(r, Level.DEBUG));
    811       add(createLevelRadioButton(r, Level.INFO));
    812       add(createLevelRadioButton(r, Level.WARN));
    813       add(createLevelRadioButton(r, Level.ERROR));
    814       addSeparator();
    815       add(createLevelRadioButton(r, Level.OFF));
    816       add(createLevelRadioButton(r, Level.ALL));
    817       addSeparator();
    818       add(showReceiverHelpAction);
    819     }
    820
    821     private JRadioButtonMenuItem createLevelRadioButton(
    822       final Receiver r, final Level l) {
    823       Map levelIconMap = LevelIconFactory.getInstance().getLevelToIconMap();
    824
    825       Action action =
    826         new AbstractAction(
    827           l.toString(), (Icon) levelIconMap.get(l.toString())) {
    828           public void actionPerformed(ActionEvent e) {
    829             if (r != null) {
    830               r.setThreshold(l);
    831               updateCurrentlySelectedNodeInDispatchThread();
    832             }
    833           }
    834         };
    835
    836       JRadioButtonMenuItem item = new JRadioButtonMenuItem(action);
    837       item.setSelected(r.getThreshold() == l);
    838
    839       return item;
    840     }
    841
    842     /**
    843      * Builds a relevant set of menus for when the Root node in the Receiver
    844      * tree has been selected
    845      *
    846      */
    847     private void buildForReceiversRoot() {
    848       JMenuItem startAll = new JMenuItem(startAllAction);
    849
    850       add(newReceiverButtonAction);
    851
    852       addSeparator();
    853       add(startAll);
    854     }
    855   }
    856
    857   /**
    858    * A simple Panel that has toolbar buttons for restarting,
    859    * playing, pausing, and stoping receivers
    860    *
    861    * @author Paul Smith &lt;psmith@apache.org&gt;
    862    *
    863    */
    864   private class ReceiverToolbar extends JToolBar
    865     implements TreeSelectionListener {
    866     final SmallButton newReceiverButton;
    867
    868     private ReceiverToolbar() {
    869       setFloatable(false);
    870
    871       SmallButton restartReceiverButton = new SmallButton(restartReceiverButtonAction);
    872       restartReceiverButton.setText(null);
    873
    874       SmallButton shutdownReceiverButton =
    875         new SmallButton(shutdownReceiverButtonAction);
    876       shutdownReceiverButton.setText(null);
    877
    878       SmallButton saveReceiversButton =
    879         new SmallButton(saveReceiversButtonAction);
    880       saveReceiversButton.setText(null);
    881
    882       SmallButton restartAllButton = new SmallButton(startAllAction);
    883       restartAllButton.setText(null);
    884
    885
    886
    887       newReceiverButton = new SmallButton(newReceiverButtonAction);
    888       newReceiverButton.setText(null);
    889       newReceiverButton.addMouseListener(new PopupListener(newReceiverPopup));
    890
    891       add(newReceiverButton);
    892       add(restartAllButton);
    893
    894       addSeparator();
    895
    896       add(restartReceiverButton);
    897       add(shutdownReceiverButton);
    898       add(saveReceiversButton);
    899
    900       addSeparator();
    901
    902       Action closeAction =
    903         new AbstractAction(null, LineIconFactory.createCloseIcon()) {
    904           public void actionPerformed(ActionEvent e) {
    905             ReceiversPanel.this.setVisible(false);
    906           }
    907         };
    908
    909       closeAction.putValue(
    910         Action.SHORT_DESCRIPTION, "Closes the Receiver panel");
    911
    912       add(Box.createHorizontalGlue());
    913
    914       add(new SmallButton(closeAction));
    915
    916       add(Box.createHorizontalStrut(5));
    917     }
    918
    919     /**
    920      * Ensures the enabled property of the actions is set properly
    921      * according to the currently selected node in the tree
    922      */
    923     public void valueChanged(TreeSelectionEvent e) {
    924       updateActions();
    925     }
    926   }
    927 }