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;
    19
    20  import org.apache.log4j.chainsaw.filter.FilterModel;
    21  import org.apache.log4j.rule.RuleFactory;
    22  import org.apache.log4j.spi.LoggingEventFieldResolver;
    23
    24  import javax.swing.*;
    25  import javax.swing.text.JTextComponent;
    26  import java.awt.*;
    27  import java.awt.event.*;
    28
    29  /**
    30   * A popup menu which assists in building expression rules.  Completes event keywords, operators and
    31   * context if available.
    32   *
    33   * @author Scott Deboy &lt;sdeboy@apache.org&gt;
    34   */
    35  public class ExpressionRuleContext extends KeyAdapter {
    36      RuleFactory factory = RuleFactory.getInstance();
    37      LoggingEventFieldResolver resolver = LoggingEventFieldResolver.getInstance();
    38      JPopupMenu contextMenu = new JPopupMenu();
    39      JList list = new JList();
    40      FilterModel filterModel;
    41      JScrollPane scrollPane = new JScrollPane(list);
    42      final JTextComponent textComponent;
    43      private DefaultListModel fieldModel = new DefaultListModel();
    44      private DefaultListModel operatorModel = new DefaultListModel();
    45
    46      public ExpressionRuleContext(
    47          final FilterModel filterModel, final JTextComponent textComponent) {
    48          this.filterModel = filterModel;
    49          this.textComponent = textComponent;
    50          fieldModel.addElement("LOGGER");
    51          fieldModel.addElement("LEVEL");
    52          fieldModel.addElement("CLASS");
    53          fieldModel.addElement("FILE");
    54          fieldModel.addElement("LINE");
    55          fieldModel.addElement("METHOD");
    56          fieldModel.addElement("MSG");
    57          fieldModel.addElement("NDC");
    58          fieldModel.addElement("EXCEPTION");
    59          fieldModel.addElement("TIMESTAMP");
    60          fieldModel.addElement("THREAD");
    61          fieldModel.addElement("PROP.");
    62
    63          operatorModel.addElement("&&");
    64          operatorModel.addElement("||");
    65          operatorModel.addElement("!");
    66          operatorModel.addElement("!=");
    67          operatorModel.addElement("==");
    68          operatorModel.addElement("~=");
    69          operatorModel.addElement("LIKE");
    70          operatorModel.addElement("EXISTS");
    71          operatorModel.addElement("<");
    72          operatorModel.addElement(">");
    73          operatorModel.addElement("<=");
    74          operatorModel.addElement(">=");
    75
    76          //make long to avoid scrollbar
    77          list.setVisibleRowCount(13);
    78
    79          PopupListener popupListener = new PopupListener();
    80          textComponent.addMouseListener(popupListener);
    81
    82          list.addKeyListener(
    83              new KeyAdapter() {
    84                  public void keyPressed(KeyEvent e) {
    85                      if (e.getKeyCode() == KeyEvent.VK_ENTER) {
    86                          String value = list.getSelectedValue().toString();
    87                          String contextKey = getContextKey();
    88                          if (contextKey != null && (!(contextKey.endsWith(".")))) {
    89                              value = "'" + value + "'";
    90                          }
    91
    92                          updateField(value);
    93                          contextMenu.setVisible(false);
    94                      }
    95                  }
    96              });
    97
    98          list.addMouseListener(
    99              new MouseAdapter() {
    100                 public void mouseClicked(MouseEvent e) {
    101                     if (e.getClickCount() == 2) {
    102                         String value = list.getSelectedValue().toString();
    103                         String contextKey = getContextKey();
    104                         if (contextKey != null && (!(contextKey.endsWith(".")))) {
    105                             value = "'" + value + "'";
    106                         }
    107
    108                         updateField(value);
    109                         contextMenu.setVisible(false);
    110                     }
    111                 }
    112             });
    113
    114         contextMenu.insert(scrollPane, 0);
    115     }
    116
    117     private void updateField(String value) {
    118         if (textComponent.getSelectedText() == null) {
    119             if (!(value.endsWith("."))) {
    120                 value = value + " ";
    121             }
    122         }
    123
    124         textComponent.replaceSelection(value);
    125     }
    126
    127     public void keyPressed(KeyEvent e) {
    128         if (
    129             (e.getKeyCode() == KeyEvent.VK_SPACE)
    130                 && (e.getModifiers() == InputEvent.CTRL_MASK)) {
    131             displayContext();
    132         }
    133     }
    134
    135     public void displayContext() {
    136         String lastField = getContextKey();
    137
    138         if (lastField != null) {
    139             ListModel model = filterModel.getContainer().getModel(lastField);
    140             if (model == null) {
    141                 return;
    142             }
    143             list.setModel(model);
    144             list.setSelectedIndex(0);
    145
    146             Point p = textComponent.getCaret().getMagicCaretPosition();
    147             contextMenu.doLayout();
    148             contextMenu.show(textComponent, p.x, (p.y + (textComponent.getHeight() - 5)));
    149             list.requestFocus();
    150         } else {
    151             if (isOperatorContextValid()) {
    152                 list.setModel(operatorModel);
    153                 list.setSelectedIndex(0);
    154
    155                 Point p = textComponent.getCaret().getMagicCaretPosition();
    156                 contextMenu.doLayout();
    157                 contextMenu.show(textComponent, p.x, (p.y + (textComponent.getHeight() - 5)));
    158                 list.requestFocus();
    159             } else if (isFieldContextValid()) {
    160                 list.setModel(fieldModel);
    161                 list.setSelectedIndex(0);
    162
    163                 Point p = textComponent.getCaret().getMagicCaretPosition();
    164
    165                 if (p == null) {
    166                     p = new Point(
    167                         textComponent.getLocation().x,
    168                         (textComponent.getLocation().y - textComponent.getHeight() + 5));
    169                 }
    170                 contextMenu.doLayout();
    171                 contextMenu.show(textComponent, p.x, (p.y + (textComponent.getHeight() - 5)));
    172                 list.requestFocus();
    173             }
    174         }
    175     }
    176
    177     private boolean isFieldContextValid() {
    178         String text = textComponent.getText();
    179         int currentPosition = textComponent.getSelectionStart();
    180
    181         return ((currentPosition == 0)
    182             || (text.charAt(currentPosition - 1) == ' '));
    183     }
    184
    185     private String getContextKey() {
    186         String field = getField();
    187
    188         if (field == null) {
    189             field = getSubField();
    190         }
    191
    192         return field;
    193     }
    194
    195     private boolean isOperatorContextValid() {
    196         String text = textComponent.getText();
    197
    198         int currentPosition = textComponent.getSelectionStart();
    199
    200         if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
    201             return false;
    202         }
    203
    204         int lastFieldPosition = text.lastIndexOf(" ", currentPosition - 1);
    205
    206         if (lastFieldPosition == -1) {
    207             return false;
    208         }
    209
    210         int lastFieldStartPosition =
    211             Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
    212         String field =
    213             text.substring(lastFieldStartPosition, lastFieldPosition).toUpperCase()
    214                 .trim();
    215
    216         return resolver.isField(field);
    217
    218     }
    219
    220     //returns the currently active field which can be used to display a context menu
    221     //the field returned is the left hand portion of an expression (for example, logger == )
    222     //logger is the field that is returned
    223     private String getField() {
    224         String text = textComponent.getText();
    225
    226         int currentPosition = textComponent.getSelectionStart();
    227
    228         if ((currentPosition < 1) || (text.charAt(currentPosition - 1) != ' ')) {
    229             return null;
    230         }
    231
    232         int symbolPosition = text.lastIndexOf(" ", currentPosition - 1);
    233
    234         if (symbolPosition < 0) {
    235             return null;
    236         }
    237
    238         int lastFieldPosition = text.lastIndexOf(" ", symbolPosition - 1);
    239
    240         if (lastFieldPosition < 0) {
    241             return null;
    242         }
    243
    244         int lastFieldStartPosition =
    245             Math.max(0, text.lastIndexOf(" ", lastFieldPosition - 1));
    246         String lastSymbol =
    247             text.substring(lastFieldPosition + 1, symbolPosition).trim();
    248
    249         String lastField =
    250             text.substring(lastFieldStartPosition, lastFieldPosition).trim();
    251
    252         if (
    253             factory.isRule(lastSymbol)
    254                 && filterModel.getContainer().modelExists(lastField)) {
    255             return lastField;
    256         }
    257
    258         return null;
    259     }
    260
    261     //subfields allow the key portion of a field to provide context menu support
    262     //and are available after the fieldname and a . (for example, PROP.)
    263     private String getSubField() {
    264         int currentPosition = textComponent.getSelectionStart();
    265         String text = textComponent.getText();
    266
    267         if (text.substring(0, currentPosition).toUpperCase().endsWith("PROP.")) {
    268             return "PROP.";
    269         }
    270         return null;
    271     }
    272
    273     class PopupListener extends MouseAdapter {
    274         PopupListener() {
    275         }
    276
    277         public void mousePressed(MouseEvent e) {
    278             checkPopup(e);
    279         }
    280
    281         public void mouseReleased(MouseEvent e) {
    282             checkPopup(e);
    283         }
    284
    285         private void checkPopup(MouseEvent e) {
    286             if (e.isPopupTrigger()) {
    287                 displayContext();
    288             }
    289         }
    290     }
    291 }