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.messages;
    19
    20  import org.apache.log4j.Layout;
    21  import org.apache.log4j.Level;
    22  import org.apache.log4j.Logger;
    23  import org.apache.log4j.TTCCLayout;
    24  import org.apache.log4j.chainsaw.ChainsawConstants;
    25  import org.apache.log4j.chainsaw.LoggingEventWrapper;
    26  import org.apache.log4j.chainsaw.PopupListener;
    27  import org.apache.log4j.chainsaw.SmallButton;
    28  import org.apache.log4j.chainsaw.icons.ChainsawIcons;
    29  import org.apache.log4j.varia.ListModelAppender;
    30
    31  import javax.swing.*;
    32  import javax.swing.event.ListDataEvent;
    33  import javax.swing.event.ListDataListener;
    34  import java.awt.*;
    35  import java.awt.event.ActionEvent;
    36  import java.beans.PropertyChangeSupport;
    37
    38
    39  /**
    40   * The MessageCenter is central place for all elements within Chainsaw to
    41   * notify the user of important information.
    42   * <p>
    43   * This class uses log4j itself quite significantly.  All user message
    44   * are sent to this classes log4j Logger (org.apache.log4j.chainsaw.message.MessageCenter).
    45   * <p>
    46   * To register a message with the user, you can use the addMessage(String) style methods on
    47   * this class, or just as easily, get a handle to this class' logger, and log
    48   * it as you would normally do.
    49   * <p>
    50   * All events to this logger are trapped within a Custom appender (additivity
    51   * will be switched OFF), which stores the events in a ListModel.
    52   * <p>
    53   * You can invoke the setVisible() method to display all the messages
    54   *
    55   * @author Paul Smith &lt;psmith@apache.org&gt;
    56   */
    57  public class MessageCenter {
    58      private static final MessageCenter instance = new MessageCenter();
    59      private final Logger logger = Logger.getLogger(MessageCenter.class);
    60      private Layout layout = new TTCCLayout();
    61      private final JList<org.apache.log4j.spi.LoggingEvent> messageList = new JList<>();
    62      private final ListModelAppender appender = new ListModelAppender();
    63      private ListCellRenderer listCellRenderer =
    64          new LayoutListCellRenderer(layout);
    65      private PropertyChangeSupport propertySupport =
    66          new PropertyChangeSupport(this);
    67      private JScrollPane pane = new JScrollPane(messageList);
    68      private final JToolBar toolbar = new JToolBar();
    69      private JPopupMenu popupMenu = new JPopupMenu();
    70      private PopupListener popupListener = new PopupListener(popupMenu);
    71      private Action clearAction;
    72      private final JPanel componentPanel = new JPanel(new BorderLayout());
    73
    74      private MessageCenter() {
    75          setupActions();
    76          setupComponentPanel();
    77          setupLogger();
    78          setupListeners();
    79          setupPopMenu();
    80          setupToolbar();
    81      }
    82
    83      /**
    84       *
    85       */
    86      private void setupPopMenu() {
    87          popupMenu.add(clearAction);
    88      }
    89
    90      /**
    91       *
    92       */
    93      private void setupToolbar() {
    94          JButton clearButton = new SmallButton(clearAction);
    95          clearButton.setText(null);
    96          toolbar.add(clearButton);
    97
    98          toolbar.setFloatable(false);
    99      }
    100
    101     private void setupActions() {
    102         clearAction =
    103             new AbstractAction("Clear") {
    104                 public void actionPerformed(ActionEvent e) {
    105                     appender.clearModel();
    106                 }
    107             };
    108         clearAction.putValue(
    109             Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DELETE));
    110     }
    111
    112     private void setupListeners() {
    113         propertySupport.addPropertyChangeListener(
    114             "layout",
    115             evt -> {
    116                 Layout newLayout = (Layout) evt.getNewValue();
    117                 messageList.setCellRenderer(new LayoutListCellRenderer(newLayout));
    118             });
    119         messageList.addMouseListener(popupListener);
    120
    121         appender.getModel().addListDataListener(
    122             new ListDataListener() {
    123                 public void contentsChanged(ListDataEvent e) {
    124                     updateActions();
    125                 }
    126
    127                 public void intervalAdded(ListDataEvent e) {
    128                     updateActions();
    129                 }
    130
    131                 public void intervalRemoved(ListDataEvent e) {
    132                     updateActions();
    133                 }
    134             });
    135     }
    136
    137     /**
    138      *
    139      */
    140     private void updateActions() {
    141         clearAction.putValue(
    142             "enabled",
    143             (appender.getModel().getSize() > 0) ? Boolean.TRUE : Boolean.FALSE);
    144     }
    145
    146     private void setupLogger() {
    147         logger.addAppender(appender);
    148         logger.setAdditivity(true);
    149         logger.setLevel(Boolean.getBoolean("log4j.debug") ? Level.DEBUG : Level.INFO);
    150     }
    151
    152     private void setupComponentPanel() {
    153         messageList.setModel(appender.getModel());
    154         messageList.setCellRenderer(listCellRenderer);
    155
    156         componentPanel.add(this.toolbar, BorderLayout.NORTH);
    157         componentPanel.add(this.pane, BorderLayout.CENTER);
    158     }
    159
    160     public final JComponent getGUIComponent() {
    161         return componentPanel;
    162     }
    163
    164     public ListModel<org.apache.log4j.spi.LoggingEvent> getModel() {
    165         return messageList.getModel();
    166     }
    167
    168     public static MessageCenter getInstance() {
    169         return instance;
    170     }
    171
    172     public void addMessage(String message) {
    173         logger.info(message);
    174     }
    175
    176
    177     /**
    178      * @return Returns the layout used by the MessageCenter.
    179      */
    180     public final Layout getLayout() {
    181         return layout;
    182     }
    183
    184     /**
    185      * @param layout Sets the layout to be used by the MessageCenter .
    186      */
    187     public final void setLayout(Layout layout) {
    188         Layout oldValue = this.layout;
    189         this.layout = layout;
    190         propertySupport.firePropertyChange("layout", oldValue, this.layout);
    191     }
    192
    193     /**
    194      * Returns the logger that can be used to log
    195      * messages to display within the Message Center.
    196      *
    197      * @return logger
    198      */
    199     public final Logger getLogger() {
    200         return this.logger;
    201     }
    202
    203     /**
    204      * This class simply renders an event by delegating the effort to a
    205      * Log4j layout instance.
    206      *
    207      * @author Paul Smith &lt;psmith@apache.org&gt;
    208      */
    209     private static class LayoutListCellRenderer extends DefaultListCellRenderer {
    210         private Layout layout;
    211
    212         /**
    213          * @param layout
    214          */
    215         public LayoutListCellRenderer(Layout layout) {
    216             super();
    217             this.layout = layout;
    218         }
    219
    220         /* (non-Javadoc)
    221          * @see javax.swing.ListCellRenderer#getListCellRendererComponent(javax.swing.JList, java.lang.Object, int, boolean, boolean)
    222          */
    223         public Component getListCellRendererComponent(
    224             JList list, Object value, int index, boolean isSelected,
    225             boolean cellHasFocus) {
    226             value = layout.format(((LoggingEventWrapper) value).getLoggingEvent());
    227
    228             Component c =
    229                 super.getListCellRendererComponent(
    230                     list, value, index, isSelected, cellHasFocus);
    231             c.setBackground(
    232                 ((index % 2) == 0) ? ChainsawConstants.COLOR_EVEN_ROW_BACKGROUND
    233                     : ChainsawConstants.COLOR_ODD_ROW_BACKGROUND);
    234
    235             return c;
    236         }
    237     }
    238 }