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  package org.apache.log4j.chainsaw;
    18
    19  import java.awt.BorderLayout;
    20  import java.text.MessageFormat;
    21  import java.util.Date;
    22  import javax.swing.BorderFactory;
    23  import javax.swing.JEditorPane;
    24  import javax.swing.JPanel;
    25  import javax.swing.JScrollPane;
    26  import javax.swing.JTable;
    27  import javax.swing.ListSelectionModel;
    28  import javax.swing.event.ListSelectionEvent;
    29  import javax.swing.event.ListSelectionListener;
    30  import org.apache.log4j.Logger;
    31
    32  /**
    33   * A panel for showing a stack trace.
    34   *
    35   * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
    36   */
    37  class DetailPanel
    38      extends JPanel
    39      implements ListSelectionListener
    40  {
    41      /** used to log events **/
    42      private static final Logger LOG =
    43          Logger.getLogger(DetailPanel.class);
    44
    45      /** used to format the logging event **/
    46      private static final MessageFormat FORMATTER = new MessageFormat(
    47          "<b>Time:</b> <code>{0,time,medium}</code>" +
    48          "&nbsp;&nbsp;<b>Priority:</b> <code>{1}</code>" +
    49          "&nbsp;&nbsp;<b>Thread:</b> <code>{2}</code>" +
    50          "&nbsp;&nbsp;<b>NDC:</b> <code>{3}</code>" +
    51          "<br><b>Logger:</b> <code>{4}</code>" +
    52          "<br><b>Location:</b> <code>{5}</code>" +
    53          "<br><b>Message:</b>" +
    54          "<pre>{6}</pre>" +
    55          "<b>Throwable:</b>" +
    56          "<pre>{7}</pre>");
    57
    58      /** the model for the data to render **/
    59      private final MyTableModel mModel;
    60      /** pane for rendering detail **/
    61      private final JEditorPane mDetails;
    62
    63      /**
    64       * Creates a new <code>DetailPanel</code> instance.
    65       *
    66       * @param aTable the table to listen for selections on
    67       * @param aModel the model backing the table
    68       */
    69      DetailPanel(JTable aTable, final MyTableModel aModel) {
    70          mModel = aModel;
    71          setLayout(new BorderLayout());
    72          setBorder(BorderFactory.createTitledBorder("Details: "));
    73
    74          mDetails = new JEditorPane();
    75          mDetails.setEditable(false);
    76          mDetails.setContentType("text/html");
    77          add(new JScrollPane(mDetails), BorderLayout.CENTER);
    78
    79          final ListSelectionModel rowSM = aTable.getSelectionModel();
    80          rowSM.addListSelectionListener(this);
    81      }
    82
    83      /** @see ListSelectionListener **/
    84      public void valueChanged(ListSelectionEvent aEvent) {
    85          //Ignore extra messages.
    86          if (aEvent.getValueIsAdjusting()) {
    87              return;
    88          }
    89
    90          final ListSelectionModel lsm = (ListSelectionModel) aEvent.getSource();
    91          if (lsm.isSelectionEmpty()) {
    92              mDetails.setText("Nothing selected");
    93          } else {
    94              final int selectedRow = lsm.getMinSelectionIndex();
    95              final EventDetails e = mModel.getEventDetails(selectedRow);
    96              final Object[] args =
    97              {
    98                  new Date(e.getTimeStamp()),
    99                  e.getPriority(),
    100                 escape(e.getThreadName()),
    101                 escape(e.getNDC()),
    102                 escape(e.getCategoryName()),
    103                 escape(e.getLocationDetails()),
    104                 escape(e.getMessage()),
    105                 escape(getThrowableStrRep(e))
    106             };
    107             mDetails.setText(FORMATTER.format(args));
    108             mDetails.setCaretPosition(0);
    109         }
    110     }
    111
    112     ////////////////////////////////////////////////////////////////////////////
    113     // Private methods
    114     ////////////////////////////////////////////////////////////////////////////
    115
    116     /**
    117      * Returns a string representation of a throwable.
    118      *
    119      * @param aEvent contains the throwable information
    120      * @return a <code>String</code> value
    121      */
    122     private static String getThrowableStrRep(EventDetails aEvent) {
    123         final String[] strs = aEvent.getThrowableStrRep();
    124         if (strs == null) {
    125             return null;
    126         }
    127
    128         final StringBuffer sb = new StringBuffer();
    129         for (int i = 0; i < strs.length; i++) {
    130             sb.append(strs[i]).append("\n");
    131         }
    132
    133         return sb.toString();
    134     }
    135
    136     /**
    137      * Escape &lt;, &gt; &amp; and &quot; as their entities. It is very
    138      * dumb about &amp; handling.
    139      * @param aStr the String to escape.
    140      * @return the escaped String
    141      */
    142     private String escape(String aStr) {
    143         if (aStr == null) {
    144             return null;
    145         }
    146
    147         final StringBuffer buf = new StringBuffer();
    148         for (int i = 0; i < aStr.length(); i++) {
    149             char c = aStr.charAt(i);
    150             switch (c) {
    151             case '<':
    152                 buf.append("&lt;");
    153                 break;
    154             case '>':
    155                 buf.append("&gt;");
    156                 break;
    157             case '\"':
    158                 buf.append("&quot;");
    159                 break;
    160             case '&':
    161                 buf.append("&amp;");
    162                 break;
    163             default:
    164                 buf.append(c);
    165                 break;
    166             }
    167         }
    168         return buf.toString();
    169     }
    170 }