You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2017/05/30 23:48:38 UTC

[01/50] [abbrv] logging-chainsaw git commit: Fixed bug in Nimbus L&F removal logic Removed property removal logic from loggingeventwrapper constructor Minor changes to Swing calls (revalidate, etc)

Repository: logging-chainsaw
Updated Branches:
  refs/heads/master [created] 025d756a6


Fixed bug in Nimbus L&F removal logic
Removed property removal logic from loggingeventwrapper constructor
Minor changes to Swing calls (revalidate, etc)


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/f543275b
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/f543275b
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/f543275b

Branch: refs/heads/master
Commit: f543275b5397d8e4577766d6ef43cd6f5b55e662
Parents: 4b6b47b
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Oct 21 05:56:34 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Oct 21 05:56:34 2010 +0000

----------------------------------------------------------------------
 .../ApplicationPreferenceModelPanel.java        | 16 +++++++++-------
 .../org/apache/log4j/chainsaw/LogPanel.java     | 20 +++++++++-----------
 .../log4j/chainsaw/LoggingEventWrapper.java     | 13 -------------
 3 files changed, 18 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f543275b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index c1d5579..35457be 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -183,18 +183,20 @@ public static void main(String[] args) {
 
       //Nimbus has major issues with colors in tables..just remove it from the list..
       //only use this if nimbus was found..
-      UIManager.LookAndFeelInfo[] newLookAndFeels = new UIManager.LookAndFeelInfo[lookAndFeels.length - 1];
+      UIManager.LookAndFeelInfo[] newLookAndFeels = new UIManager.LookAndFeelInfo[lookAndFeels.length];
       boolean useNewLookAndFeels = false;
       int j = 0;
       for (int i=0;i<lookAndFeels.length;i++) {
-          if (!lookAndFeels[i].getClassName().toLowerCase().contains("nimbus")) {
-              newLookAndFeels[j++] = lookAndFeels[i];
-          } else {
-              useNewLookAndFeels = true;
-          }
+        if (lookAndFeels[i].getClassName().toLowerCase().contains("nimbus")) {
+            useNewLookAndFeels = true;
+        } else {
+            newLookAndFeels[j++] = lookAndFeels[i];
+        }
       }
       if (useNewLookAndFeels) {
-          lookAndFeels = newLookAndFeels;
+          UIManager.LookAndFeelInfo[] replacedLookAndFeels = new UIManager.LookAndFeelInfo[lookAndFeels.length - 1];
+          System.arraycopy(newLookAndFeels, 0, replacedLookAndFeels, 0, newLookAndFeels.length - 1);
+          lookAndFeels = replacedLookAndFeels;
       }
 
       setupComponents();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f543275b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 68e289f..e2d388a 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -267,6 +267,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   private JToolBar detailToolbar;
   private boolean searchResultsDisplayed;
   private ColorizedEventAndSearchMatchThumbnail colorizedEventAndSearchMatchThumbnail;
+  private EventTimeDeltaMatchThumbnail eventTimeDeltaMatchThumbnail;
 
   /**
    * Creates a new LogPanel object.  If a LogPanel with this identifier has
@@ -854,11 +855,9 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 //             loggingEventWrapper.updateColorRuleColors(colorizer.getBackgroundColor(loggingEventWrapper.getLoggingEvent()), colorizer.getForegroundColor(loggingEventWrapper.getLoggingEvent()));
 //           }
           colorizedEventAndSearchMatchThumbnail.configureColors();
-          lowerPanel.invalidate();
           lowerPanel.revalidate();
           lowerPanel.repaint();
 
-          searchTable.invalidate();
           searchTable.revalidate();
           searchTable.repaint();
         }
@@ -1258,7 +1257,8 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     JPanel leftThumbNailPanel = new JPanel();
     leftThumbNailPanel.setLayout(new BoxLayout(leftThumbNailPanel, BoxLayout.Y_AXIS));
     leftThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
-    leftThumbNailPanel.add(new EventTimeDeltaMatchThumbnail());
+    eventTimeDeltaMatchThumbnail = new EventTimeDeltaMatchThumbnail();
+    leftThumbNailPanel.add(eventTimeDeltaMatchThumbnail);
     leftThumbNailPanel.add(Box.createVerticalStrut(scrollBarWidth.intValue()));
     leftPanel.add(leftThumbNailPanel);
 
@@ -2606,7 +2606,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       detailPanel.add(leftSpacePanel, BorderLayout.WEST);
       detailPanel.add(rightSpacePanel, BorderLayout.EAST);
  
-      detailPanel.invalidate();
       detailPanel.revalidate();
       detailPanel.repaint();
       //if the detail visible pref is not enabled, hide the detail pane
@@ -2630,7 +2629,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       rightSpacePanel.setPreferredSize(new Dimension(scrollBarWidth.intValue() -4, -1));
       detailPanel.add(leftSpacePanel, BorderLayout.WEST);
       detailPanel.add(rightSpacePanel, BorderLayout.EAST);
-      detailPanel.invalidate();
       detailPanel.revalidate();
       detailPanel.repaint();
       //if the detail visible pref is not enabled, show the detail pane
@@ -3749,7 +3747,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     private class EventTimeDeltaMatchThumbnail extends AbstractEventMatchThumbnail {
         public EventTimeDeltaMatchThumbnail() {
-            super();
+            super("timedelta");
             initializeLists();
         }
 
@@ -3782,7 +3780,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                     primaryList.add(wrapper);
                 }
             }
-            invalidate();
+            revalidate();
             repaint();
         }
 
@@ -3829,7 +3827,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   //a listener receiving color updates needs to call configureColors on this class
     private class ColorizedEventAndSearchMatchThumbnail extends AbstractEventMatchThumbnail {
         public ColorizedEventAndSearchMatchThumbnail() {
-            super();
+            super("colors");
             configureColors();
         }
 
@@ -3858,7 +3856,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                     primaryList.add(wrapper);
                 }
             }
-            invalidate();
+            revalidate();
             repaint();
         }
 
@@ -3940,7 +3938,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         protected List secondaryList = new ArrayList();
         protected final int maxEventHeight = 6;
 
-        AbstractEventMatchThumbnail() {
+        AbstractEventMatchThumbnail(final String name) {
             super();
             addMouseMotionListener(new MouseMotionAdapter() {
               public void mouseMoved(MouseEvent e) {
@@ -4062,7 +4060,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                         }
 //                        System.out.println("update - new warnings: " + warnings.size() + ", errors: " + errors.size());
                     }
-                    invalidate();
+                    revalidate();
                     repaint();
                     //run this in an invokeLater block to ensure this action is enqueued to the end of the EDT
                     EventQueue.invokeLater(new Runnable() {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f543275b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
index 3ae7ca2..68d8680 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
@@ -61,19 +61,6 @@ public class LoggingEventWrapper {
     this.syncWrapper = loggingEventWrapper;
     this.eventContainer = eventContainer;
     loggingEventWrapper.syncWrapper = this;
-    Map theseProperties = loggingEvent.getProperties();
-
-    LoggingEvent thatLoggingEvent = syncWrapper.getLoggingEvent();
-    Map syncEventPropertiesCopy = new HashMap(thatLoggingEvent.getProperties());
-    for (Iterator iter = syncEventPropertiesCopy.entrySet().iterator();iter.hasNext();) {
-      Map.Entry entry = (Map.Entry)iter.next();
-      thatLoggingEvent.removeProperty(entry.getKey().toString());
-    }
-
-    for (Iterator iter = theseProperties.entrySet().iterator();iter.hasNext();) {
-      Map.Entry entry = (Map.Entry)iter.next();
-      thatLoggingEvent.setProperty(entry.getKey().toString(), entry.getValue().toString());
-    }
   }
 
   public LoggingEvent getLoggingEvent() {


[25/50] [abbrv] logging-chainsaw git commit: Added per-tab preference to not use a search match color in the primary table Added ability to use single or double quotes to surround multi-word strings in expressions

Posted by rg...@apache.org.
Added per-tab preference to not use a search match color in the primary table
Added ability to use single or double quotes to surround multi-word strings in expressions


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/963870d0
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/963870d0
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/963870d0

Branch: refs/heads/master
Commit: 963870d06983a15c0bb99dbe534985c00c32daf3
Parents: 9784229
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Nov 12 07:09:35 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Nov 12 07:09:35 2010 +0000

----------------------------------------------------------------------
 .../chainsaw/ApplicationPreferenceModel.java    | 10 +++++++++
 .../org/apache/log4j/chainsaw/LogPanel.java     |  3 ++-
 .../log4j/chainsaw/TableColorizingRenderer.java |  2 +-
 .../apache/log4j/chainsaw/color/ColorPanel.java | 22 +++++++++++++++++++-
 .../log4j/chainsaw/help/release-notes.html      |  5 +++++
 5 files changed, 39 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/963870d0/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
index 721e634..ad0a58c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
@@ -75,6 +75,7 @@ public class ApplicationPreferenceModel {
     private static final int CONFIGURATION_URL_ENTRY_COUNT = 10;
     private List defaultColumnNames = new ArrayList();
     private boolean defaultColumnsSet;
+    private boolean bypassSearchColors = false;
 
   /**
      * @param listener
@@ -234,6 +235,7 @@ public class ApplicationPreferenceModel {
       if (model.isDefaultColumnsSet()) {
         setDefaultColumnNames(model.getDefaultColumnNames());
       }
+      setBypassSearchColors(model.isBypassSearchColors());
     }
 
     //use a lighter version of search color as the delta color
@@ -518,4 +520,12 @@ public class ApplicationPreferenceModel {
   public List getDefaultColumnNames() {
     return defaultColumnNames;
   }
+
+  public void setBypassSearchColors(boolean bypassSearchColors) {
+    this.bypassSearchColors = bypassSearchColors;
+  }
+
+  public boolean isBypassSearchColors() {
+    return bypassSearchColors;
+  }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/963870d0/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 7bdd00d..449266f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -1772,7 +1772,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
           if (currentPoint != null) {
             ((TableColorizingRenderer)currentTable.getDefaultRenderer(Object.class)).setUseNormalTimes();
             ((ChainsawCyclicBufferTableModel)currentTable.getModel()).reFilter();
-            setEnabled(false);
+            setEnabled(true);
           }
         }
     });
@@ -4280,6 +4280,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         private String lastTextToMatch;
 
         public AutoFilterComboBox() {
+            textField.setPreferredSize(getPreferredSize());
             setModel(model);
             setEditor(new AutoFilterEditor());
             ((JTextField)getEditor().getEditorComponent()).getDocument().addDocumentListener(new AutoFilterDocumentListener());

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/963870d0/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index 983db9a..b6029ff 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -431,7 +431,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         background = applicationPreferenceModel.getSearchBackgroundColor();
         foreground = applicationPreferenceModel.getSearchForegroundColor();
     } else {
-        if (colorizeSearch) {
+        if (colorizeSearch && !applicationPreferenceModel.isBypassSearchColors()) {
           background = loggingEventWrapper.isSearchMatch()?applicationPreferenceModel.getSearchBackgroundColor():loggingEventWrapper.getBackground();
           foreground = loggingEventWrapper.isSearchMatch()?applicationPreferenceModel.getSearchForegroundColor():loggingEventWrapper.getForeground();
         } else {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/963870d0/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
index dcc4621..95a8b11 100644
--- a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
@@ -46,6 +46,7 @@ import javax.swing.DefaultCellEditor;
 import javax.swing.DefaultComboBoxModel;
 import javax.swing.Icon;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JColorChooser;
 import javax.swing.JComboBox;
 import javax.swing.JDialog;
@@ -113,8 +114,9 @@ public class ColorPanel extends JPanel
   private Vector alternatingColorDataVector;
   private Vector alternatingColorDataVectorEntry;
   private ApplicationPreferenceModel applicationPreferenceModel;
+  private JCheckBox bypassSearchColorsCheckBox;
 
-    public ColorPanel(final RuleColorizer currentLogPanelColorizer, final FilterModel filterModel,
+  public ColorPanel(final RuleColorizer currentLogPanelColorizer, final FilterModel filterModel,
                       final Map allLogPanelColorizers, final ApplicationPreferenceModel applicationPreferenceModel) {
     super(new BorderLayout());
 
@@ -229,6 +231,9 @@ public class ColorPanel extends JPanel
     southPanel.add(Box.createVerticalStrut(5));
     southPanel.add(Box.createVerticalStrut(5));
     JPanel searchAndAlternatingColorPanel = buildSearchAndAlternatingColorPanel();
+    JPanel bypassSearchColorsPanel = buildBypassSearchColorsPanel();
+    bypassSearchColorsCheckBox.setSelected(applicationPreferenceModel.isBypassSearchColors());
+
     JPanel globalLabelPanel = new JPanel();
     globalLabelPanel.setLayout(new BoxLayout(globalLabelPanel, BoxLayout.X_AXIS));
     JLabel globalLabel = new JLabel("Global colors:");
@@ -236,6 +241,7 @@ public class ColorPanel extends JPanel
     globalLabelPanel.add(Box.createHorizontalGlue());
     southPanel.add(globalLabelPanel);
     southPanel.add(searchAndAlternatingColorPanel);
+    southPanel.add(bypassSearchColorsPanel);
     southPanel.add(Box.createVerticalStrut(5));
     JPanel closePanel = buildClosePanel();
     southPanel.add(closePanel);
@@ -316,6 +322,15 @@ public class ColorPanel extends JPanel
       alternatingColorDataVectorEntry.set(1, applicationPreferenceModel.getAlternatingColorForegroundColor());
   }
 
+  public JPanel buildBypassSearchColorsPanel() {
+    JPanel panel = new JPanel();
+    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
+
+    bypassSearchColorsCheckBox = new JCheckBox("Don't use a search color for matching rows");
+    panel.add(bypassSearchColorsCheckBox);
+    return panel;
+  }
+
   public JPanel buildSearchAndAlternatingColorPanel() {
       JPanel panel = new JPanel();
       panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
@@ -533,6 +548,7 @@ public class ColorPanel extends JPanel
           applyRules(currentRuleSet, colorizer);
           saveSearchColors();
           saveAlternatingColors();
+          saveBypassFlag();
         }
       });
 
@@ -566,6 +582,10 @@ public class ColorPanel extends JPanel
       applicationPreferenceModel.setAlternatingForegroundColor(alternatingColorForegroundColor);
   }
 
+  private void saveBypassFlag() {
+    applicationPreferenceModel.setBypassSearchColors(bypassSearchColorsCheckBox.isSelected());
+  }
+
   JPanel buildUpDownPanel() {
     JPanel panel = new JPanel(new BorderLayout());
     JPanel innerPanel = new JPanel();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/963870d0/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 681cfc0..cf5e053 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,6 +10,11 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>11 Nov 2010</h2>
+<ul>
+<li>Added per-tab preference to not use a search match color in the primary table</li>
+<li>Added ability to use single or double quotes to surround multi-word strings in expressions</li>
+</ul>
 <h2>6 Nov 2010</h2>
 <ul>
 <li>Updated the expression handling logic to no longer require spaces around operators & operands in expressions</li>


[13/50] [abbrv] logging-chainsaw git commit: Minor UI fixes - filedialog displayed on top of a jdialog has focus issues..now hiding the 'parent' dialog while the file dialog is displayed from the receiver config screen - since MESSAGE is the default fo

Posted by rg...@apache.org.
Minor UI fixes
 - filedialog displayed on top of a jdialog has focus issues..now hiding the 'parent' dialog while the file dialog is displayed from the receiver config screen
 - since MESSAGE is the default format, changed default pattern to LogFilePatternReceiver pattern
 - fixed bug in filedialog usage


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/5617df56
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/5617df56
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/5617df56

Branch: refs/heads/master
Commit: 5617df56985f7d93b4b3a644d3dd6272a4c2694e
Parents: 98f2a54
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Oct 30 23:54:15 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Oct 30 23:54:15 2010 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 220 +++++++++----------
 .../chainsaw/ReceiverConfigurationPanel.java    |  60 +++--
 .../log4j/chainsaw/helper/SwingHelper.java      |  16 +-
 3 files changed, 167 insertions(+), 129 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/5617df56/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 984a421..57746f1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -21,7 +21,6 @@ import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dimension;
-import java.awt.Event;
 import java.awt.EventQueue;
 import java.awt.Frame;
 import java.awt.Point;
@@ -1463,9 +1462,118 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
             new ActionListener() {
               public void actionPerformed(ActionEvent e) {
                 dialog.setVisible(false);
+
+            applicationPreferenceModel.setShowNoReceiverWarning(!receiverConfigurationPanel.isDontWarnMeAgain());
+            //using this config next time - stop all plugins
+            if (receiverConfigurationPanel.isDontWarnMeAgain()) {
+                List plugins = pluginRegistry.getPlugins();
+                for (Iterator iter = plugins.iterator();iter.hasNext();) {
+                    Plugin plugin = (Plugin)iter.next();
+                    //don't stop ZeroConfPlugin if it is registered
+                    if (!plugin.getName().toLowerCase().contains("zeroconf")) {
+                      pluginRegistry.stopPlugin(plugin.getName());
+                    }
+                }
+            }
+            URL configURL = null;
+
+            if (receiverConfigurationPanel.getModel().isNetworkReceiverMode()) {
+              int port = receiverConfigurationPanel.getModel().getNetworkReceiverPort();
+
+              try {
+                Class receiverClass = receiverConfigurationPanel.getModel().getNetworkReceiverClass();
+                Receiver networkReceiver = (Receiver) receiverClass.newInstance();
+                networkReceiver.setName(receiverClass.getSimpleName() + "-" + port);
+
+                Method portMethod =
+                  networkReceiver.getClass().getMethod(
+                    "setPort", new Class[] { int.class });
+                portMethod.invoke(
+                  networkReceiver, new Object[] { new Integer(port) });
+
+                networkReceiver.setThreshold(Level.TRACE);
+
+                pluginRegistry.addPlugin(networkReceiver);
+                networkReceiver.activateOptions();
+                receiversPanel.updateReceiverTreeInDispatchThread();
+                //setting config URL here ensures we have the receiver panel auto-saved config loaded
+                if (receiverConfigurationPanel.isDontWarnMeAgain()) {
+                    configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
+                }
+              } catch (Exception e3) {
+                MessageCenter.getInstance().getLogger().error(
+                  "Error creating Receiver", e3);
+                MessageCenter.getInstance().getLogger().info(
+                  "An error occurred creating your Receiver");
               }
-            });
+            } else if (receiverConfigurationPanel.getModel().isLoadConfig() ||
+                    receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
+              if (receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
+                  configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
+              } else {
+                  configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
+              }
+            } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {
+              try {
+                  URL fileURL = receiverConfigurationPanel.getModel().getLogFileURL();
+                  if (fileURL != null) {
+                      VFSLogFilePatternReceiver fileReceiver = new VFSLogFilePatternReceiver();
+                      fileReceiver.setName(fileURL.getFile());
+                      fileReceiver.setAutoReconnect(true);
+                      fileReceiver.setContainer(LogUI.this);
+                      fileReceiver.setAppendNonMatches(true);
+                      fileReceiver.setFileURL(fileURL.toURI().toString());
+                      fileReceiver.setTailing(true);
+                      if (receiverConfigurationPanel.getModel().isPatternLayoutLogFormat()) {
+                          fileReceiver.setLogFormat(LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(receiverConfigurationPanel.getModel().getLogFormat()));
+                      } else {
+                          fileReceiver.setLogFormat(receiverConfigurationPanel.getModel().getLogFormat());
+                      }
+                      fileReceiver.setTimestampFormat(receiverConfigurationPanel.getModel().getLogFormatTimestampFormat());
+                      fileReceiver.setThreshold(Level.TRACE);
+
+                      pluginRegistry.addPlugin(fileReceiver);
+                      fileReceiver.activateOptions();
+                      receiversPanel.updateReceiverTreeInDispatchThread();
+                      if (receiverConfigurationPanel.isDontWarnMeAgain()) {
+                          configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
+                      }
+                  }
+              } catch (Exception e2) {
+                  MessageCenter.getInstance().getLogger().error(
+                    "Error creating Receiver", e2);
+                  MessageCenter.getInstance().getLogger().info(
+                    "An error occurred creating your Receiver");
+              }
+            }
+              if (configURL != null) {
+                MessageCenter.getInstance().getLogger().debug(
+                  "Initialiazing Log4j with " + configURL.toExternalForm());
+                final URL finalURL = configURL;
+                new Thread(
+                  new Runnable() {
+                    public void run() {
+                      if (receiverConfigurationPanel.isDontWarnMeAgain()) {
+                          applicationPreferenceModel.setConfigurationURL(finalURL.toExternalForm());
+                      } else {
+                          try {
+                              if (new File(finalURL.toURI()).exists()) {
+                                  loadConfigurationUsingPluginClassLoader(finalURL);
+                              }
+                          }
+                          catch (URISyntaxException e) {
+                              //ignore
+                          }
+                      }
+
+                      receiversPanel.updateReceiverTreeInDispatchThread();
+                    }
+                  }).start();
+              }
+          }
+        });
 
+          receiverConfigurationPanel.setDialog(dialog);
           dialog.getContentPane().add(receiverConfigurationPanel);
 
           dialog.pack();
@@ -1476,114 +1584,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
             (screenSize.height / 2) - (dialog.getHeight() / 2));
 
           dialog.setVisible(true);
-          applicationPreferenceModel.setShowNoReceiverWarning(!receiverConfigurationPanel.isDontWarnMeAgain());
-          //using this config next time - stop all plugins
-          if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-              List plugins = pluginRegistry.getPlugins();
-              for (Iterator iter = plugins.iterator();iter.hasNext();) {
-                  Plugin plugin = (Plugin)iter.next();
-                  //don't stop ZeroConfPlugin if it is registered
-                  if (!plugin.getName().toLowerCase().contains("zeroconf")) {
-                    pluginRegistry.stopPlugin(plugin.getName());
-                  }
-              }
-          }
-          URL configURL = null;
-
-          if (receiverConfigurationPanel.getModel().isNetworkReceiverMode()) {
-            int port = receiverConfigurationPanel.getModel().getNetworkReceiverPort();
-
-            try {
-              Class receiverClass = receiverConfigurationPanel.getModel().getNetworkReceiverClass();
-              Receiver networkReceiver = (Receiver) receiverClass.newInstance();
-              networkReceiver.setName(receiverClass.getSimpleName() + "-" + port);
-
-              Method portMethod =
-                networkReceiver.getClass().getMethod(
-                  "setPort", new Class[] { int.class });
-              portMethod.invoke(
-                networkReceiver, new Object[] { new Integer(port) });
-
-              networkReceiver.setThreshold(Level.TRACE);
-
-              pluginRegistry.addPlugin(networkReceiver);
-              networkReceiver.activateOptions();
-              receiversPanel.updateReceiverTreeInDispatchThread();
-              //setting config URL here ensures we have the receiver panel auto-saved config loaded
-              if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                  configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-              }
-            } catch (Exception e) {
-              MessageCenter.getInstance().getLogger().error(
-                "Error creating Receiver", e);
-              MessageCenter.getInstance().getLogger().info(
-                "An error occurred creating your Receiver");
-            }
-          } else if (receiverConfigurationPanel.getModel().isLoadConfig() ||
-                  receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
-            if (receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
-                configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-            } else {
-                configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
-            }
-          } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {
-            try {
-                URL fileURL = receiverConfigurationPanel.getModel().getLogFileURL();
-                if (fileURL != null) {
-                    VFSLogFilePatternReceiver fileReceiver = new VFSLogFilePatternReceiver();
-                    fileReceiver.setName(fileURL.getFile());
-                    fileReceiver.setAutoReconnect(true);
-                    fileReceiver.setContainer(LogUI.this);
-                    fileReceiver.setAppendNonMatches(true);
-                    fileReceiver.setFileURL(fileURL.toURI().toString());
-                    fileReceiver.setTailing(true);
-                    if (receiverConfigurationPanel.getModel().isPatternLayoutLogFormat()) {
-                        fileReceiver.setLogFormat(LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(receiverConfigurationPanel.getModel().getLogFormat()));
-                    } else {
-                        fileReceiver.setLogFormat(receiverConfigurationPanel.getModel().getLogFormat());
-                    }
-                    fileReceiver.setTimestampFormat(receiverConfigurationPanel.getModel().getLogFormatTimestampFormat());
-                    fileReceiver.setThreshold(Level.TRACE);
-
-                    pluginRegistry.addPlugin(fileReceiver);
-                    fileReceiver.activateOptions();
-                    receiversPanel.updateReceiverTreeInDispatchThread();
-                    if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                        configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-                    }
-                }
-            } catch (Exception e) {
-                MessageCenter.getInstance().getLogger().error(
-                  "Error creating Receiver", e);
-                MessageCenter.getInstance().getLogger().info(
-                  "An error occurred creating your Receiver");
-            }
-          }
-            if (configURL != null) {
-              MessageCenter.getInstance().getLogger().debug(
-                "Initialiazing Log4j with " + configURL.toExternalForm());
-              final URL finalURL = configURL;
-              new Thread(
-                new Runnable() {
-                  public void run() {
-                    if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                        applicationPreferenceModel.setConfigurationURL(finalURL.toExternalForm());
-                    } else {
-                        try {
-                            if (new File(finalURL.toURI()).exists()) {
-                                loadConfigurationUsingPluginClassLoader(finalURL);
-                            }
-                        }
-                        catch (URISyntaxException e) {
-                            //ignore
-                        }
-                    }
-
-                    receiversPanel.updateReceiverTreeInDispatchThread();
-                  }
-                }).start();
-            }
-
         }
       });
   }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/5617df56/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index 8f276f1..bbc3ee3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -18,7 +18,9 @@ package org.apache.log4j.chainsaw;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.EventQueue;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
@@ -111,8 +113,10 @@ class ReceiverConfigurationPanel extends JPanel {
 
     //set by LogUI to handle hiding of the dialog
     private ActionListener completionActionListener;
+    //used as frame for file open dialogs
+    private Container dialog;
 
-    ReceiverConfigurationPanel() {
+  ReceiverConfigurationPanel() {
         setBorder(BorderFactory.createEmptyBorder(5, 15, 5, 15));
         setLayout(new GridBagLayout());
 
@@ -363,8 +367,8 @@ class ReceiverConfigurationPanel extends JPanel {
         panel.add(new JLabel(" Log file format type "), c);
 
         DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel();
-        comboBoxModel.addElement("PatternLayout format");
         comboBoxModel.addElement("LogFilePatternReceiver LogFormat");
+        comboBoxModel.addElement("PatternLayout format");
 
         logFileFormatTypeComboBox = new JComboBox(comboBoxModel);
         logFileFormatTypeComboBox.setOpaque(false);
@@ -553,15 +557,25 @@ class ReceiverConfigurationPanel extends JPanel {
      * or null if they cancelled.
      */
     private URL browseConfig() throws MalformedURLException {
-        File selectedFile = SwingHelper.promptForFile(this, null, "Choose a Chainsaw configuration file");
+        //hiding and showing the dialog to avoid focus issues with 2 dialogs
+        dialog.setVisible(false);
+        File selectedFile = SwingHelper.promptForFile(dialog, null, "Choose a Chainsaw configuration file");
+        URL result = null;
         if (selectedFile == null) {
-            return null;
+            result = null;
         }
-
-        if (!selectedFile.exists() || !selectedFile.canRead()) {
-            return null;
+        if (selectedFile != null && (!selectedFile.exists() || !selectedFile.canRead())) {
+            result = null;
+        }
+        if (selectedFile != null) {
+          result = selectedFile.toURI().toURL();
         }
-        return selectedFile.toURI().toURL();
+        EventQueue.invokeLater(new Runnable() {
+          public void run() {
+            dialog.setVisible(true);
+          }
+        });
+        return result;
     }
 
     /**
@@ -569,17 +583,25 @@ class ReceiverConfigurationPanel extends JPanel {
      * or null if they cancelled.
      */
     private URL browseLogFile() throws MalformedURLException {
-
-        File selectedFile = SwingHelper.promptForFile(this, null, "Select a log file");
+        //hiding and showing the dialog to avoid focus issues with 2 dialogs
+        dialog.setVisible(false);
+        File selectedFile = SwingHelper.promptForFile(dialog, null, "Select a log file");
+        URL result = null;
         if (selectedFile == null) {
-            return null;
+            result = null;
         }
-
-        if (!selectedFile.exists() || !selectedFile.canRead()) {
-            return null;
+        if (selectedFile != null && (!selectedFile.exists() || !selectedFile.canRead())) {
+            result = null;
         }
-
-        return selectedFile.toURI().toURL();
+        if (selectedFile != null) {
+          result = selectedFile.toURI().toURL();
+        }
+        EventQueue.invokeLater(new Runnable() {
+          public void run() {
+            dialog.setVisible(true);
+          }
+        });
+        return result;
     }
 
     public static void main(String[] args) {
@@ -599,7 +621,11 @@ class ReceiverConfigurationPanel extends JPanel {
         return dontwarnIfNoReceiver.isSelected();
     }
 
-    /**
+  public void setDialog(Container dialog) {
+    this.dialog = dialog;
+  }
+
+  /**
      * This class represents the model of the chosen options the user
      * has configured.
      *

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/5617df56/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
index 018e45c..89045a6 100644
--- a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
@@ -20,10 +20,10 @@ package org.apache.log4j.chainsaw.helper;
 import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.EventQueue;
 import java.awt.FileDialog;
 import java.awt.Frame;
 import java.awt.Toolkit;
-import java.awt.EventQueue;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
 import java.io.File;
@@ -38,6 +38,7 @@ import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JFileChooser;
 import javax.swing.KeyStroke;
+import javax.swing.SwingUtilities;
 
 /**
  * A collection of standard utility methods for use within Swing.
@@ -109,7 +110,14 @@ public final class SwingHelper {
   public static File promptForFile(Container parent, String defaultPath, String title) {
         if (SwingHelper.isMacOSX()) {
             //use filedialog on mac
-            FileDialog fileDialog = new FileDialog((Frame)null, title);
+            Component root = SwingUtilities.getRoot(parent);
+            Frame frame = null;
+            if (root instanceof Frame) {
+              frame = (Frame) root;
+            }
+
+            FileDialog fileDialog = new FileDialog(frame, title);
+            fileDialog.setModal(true);
             if (defaultPath != null) {
               fileDialog.setDirectory(defaultPath);
             }
@@ -118,7 +126,11 @@ public final class SwingHelper {
             if (fileString == null) {
               return null;
             }
+          if (fileDialog.getDirectory() != null) {
+            return new File(fileDialog.getDirectory(), fileString);
+          } else {
             return new File(fileString);
+          }
           } else {
 
                 JFileChooser chooser;


[43/50] [abbrv] logging-chainsaw git commit: Updating maven-assembly-plugin to 2.4, adding ID, updating HOWTOBUILD to clarify a mainClass is required when executing osxappbundle:bundle

Posted by rg...@apache.org.
Updating maven-assembly-plugin to 2.4, adding ID, updating HOWTOBUILD to clarify a mainClass is required when executing osxappbundle:bundle


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/7e8c5835
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/7e8c5835
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/7e8c5835

Branch: refs/heads/master
Commit: 7e8c5835b427ea916536c3f28c501ea080b096e2
Parents: e55aeec
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Feb 21 05:30:31 2013 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Feb 21 05:30:31 2013 +0000

----------------------------------------------------------------------
 HOWTOBUILD.txt       | 2 +-
 pom.xml              | 2 +-
 src/assembly/bin.xml | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7e8c5835/HOWTOBUILD.txt
----------------------------------------------------------------------
diff --git a/HOWTOBUILD.txt b/HOWTOBUILD.txt
index ebbd4bb..99c14d2 100644
--- a/HOWTOBUILD.txt
+++ b/HOWTOBUILD.txt
@@ -38,7 +38,7 @@ target/appassembler/bin/chainsaw.bat
 [OSX]
 You can use the *nix steps above, or go one extra step for a nicer OSX experience
 
-mvn package osxappbundle:bundle
+mvn package osxappbundle:bundle -DmainClass=org.apache.log4j.chainsaw.LogUI
 
 This will create an OSX distribution, look inside the target folder for the packaged OSX application and .dmg distribution.  You can drag the application to your /Applications folder, or just double click it from the target folder.
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7e8c5835/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index c47c34d..182eab5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -245,7 +245,7 @@
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-assembly-plugin</artifactId>
-        <version>2.2-beta-5</version>
+        <version>2.4</version>
           <executions>
             <execution>
               <id>make-assembly</id>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7e8c5835/src/assembly/bin.xml
----------------------------------------------------------------------
diff --git a/src/assembly/bin.xml b/src/assembly/bin.xml
index 04ece7c..a108121 100644
--- a/src/assembly/bin.xml
+++ b/src/assembly/bin.xml
@@ -20,7 +20,8 @@
 		bin assembly to have any suffix on its name. Other assemblies need their Id suffixed, but this one
 		doesn't 
 		<id>bin</id> -->
-	<formats>
+	<id>bin</id>
+    <formats>
 		<format>zip</format>
 		<format>tar.gz</format>
 	</formats>


[04/50] [abbrv] logging-chainsaw git commit: improve reselection of currently selected row after a refilter

Posted by rg...@apache.org.
improve reselection of currently selected row after a refilter


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/5343147f
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/5343147f
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/5343147f

Branch: refs/heads/master
Commit: 5343147f8ca4316d7d59a44f985c9f9086089c06
Parents: 0dcec14
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Oct 23 04:40:15 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Oct 23 04:40:15 2010 +0000

----------------------------------------------------------------------
 .../apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java    | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/5343147f/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
index c11c565..ad51455 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
@@ -194,8 +194,8 @@ class ChainsawCyclicBufferTableModel extends AbstractTableModel
       				fireTableDataChanged();
       			}
 	      	notifyCountListeners();
-            //post refilter with newValue of FALSE (filtering is complete) (enqueue on EDT, don't run now)
-            EventQueue.invokeLater(new Runnable() {
+            //post refilter with newValue of FALSE (filtering is complete)
+            SwingHelper.invokeOnEDT(new Runnable() {
                 public void run() {
                     propertySupport.firePropertyChange("refilter", Boolean.TRUE, Boolean.FALSE);
                 }


[31/50] [abbrv] logging-chainsaw git commit: Added persistent "always display" expression support (button below the logger tree). The 'always display' expression overrides hidden loggers and the hidden expression but not the refine focus filtering mecha

Posted by rg...@apache.org.
Added persistent "always display" expression support (button below the logger tree).  The 'always display' expression overrides hidden loggers and the hidden expression but not the refine focus filtering mechanism.  Often used with expressions like 'exception exists || level > warn' to ensure errors and exceptions are not filtered out due to the hidden expression or hidden logger mechanism.


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/decd6ab8
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/decd6ab8
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/decd6ab8

Branch: refs/heads/master
Commit: decd6ab883ad9783b10f2daf8ca90e5c503cb11b
Parents: 11e4448
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Oct 3 05:38:28 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Oct 3 05:38:28 2011 +0000

----------------------------------------------------------------------
 .../org/apache/log4j/chainsaw/LogPanel.java     |   2 +
 .../log4j/chainsaw/LogPanelPreferenceModel.java |  12 ++
 .../log4j/chainsaw/LoggerNameTreePanel.java     | 111 +++++++++++++++++--
 .../log4j/chainsaw/help/release-notes.html      |   4 +
 4 files changed, 118 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/decd6ab8/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index aef99d7..6fe2a8b 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -2335,6 +2335,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     searchModel.setCyclic(preferenceModel.isCyclic());
     logTreePanel.ignore(preferenceModel.getHiddenLoggers());
     logTreePanel.setHiddenExpression(preferenceModel.getHiddenExpression());
+    logTreePanel.setAlwaysDisplayExpression(preferenceModel.getAlwaysDisplayExpression());
     if (preferenceModel.getClearTableExpression() != null) {
         try {
             clearTableExpressionRule = ExpressionRule.getRule(preferenceModel.getClearTableExpression());
@@ -2366,6 +2367,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     preferenceModel.setHiddenLoggers(new HashSet(logTreePanel.getHiddenSet()));
     preferenceModel.setHiddenExpression(logTreePanel.getHiddenExpression());
+    preferenceModel.setAlwaysDisplayExpression(logTreePanel.getAlwaysDisplayExpression());
     List visibleOrder = new ArrayList();
     Enumeration cols = table.getColumnModel().getColumns();
     while (cols.hasMoreElements()) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/decd6ab8/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
index 8634055..a1fdec6 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
@@ -84,6 +84,7 @@ public class LogPanelPreferenceModel implements Serializable{
   private boolean wrapMsg = true;
   private boolean highlightSearchMatchText;
   private String hiddenExpression;
+  private String alwaysDisplayExpression;
   private String clearTableExpression;
   //default to cyclic mode off
   private boolean cyclic = false;
@@ -254,6 +255,7 @@ public class LogPanelPreferenceModel implements Serializable{
     setVisibleColumns(model.getVisibleColumns());
     setHiddenLoggers(model.getHiddenLoggers());
     setHiddenExpression(model.getHiddenExpression());
+    setAlwaysDisplayExpression(model.getAlwaysDisplayExpression());
     setShowMillisDeltaAsGap(model.isShowMillisDeltaAsGap());
     setClearTableExpression(model.getClearTableExpression());
   }
@@ -506,6 +508,16 @@ public class LogPanelPreferenceModel implements Serializable{
     return hiddenExpression;
   }
 
+  public void setAlwaysDisplayExpression(String alwaysDisplayExpression) {
+    Object oldValue = this.hiddenExpression;
+    this.alwaysDisplayExpression = alwaysDisplayExpression;
+    propertySupport.firePropertyChange("alwaysDisplayExpression", oldValue, this.alwaysDisplayExpression);
+  }
+
+  public String getAlwaysDisplayExpression() {
+    return alwaysDisplayExpression;
+  }
+
   public void setClearTableExpression(String clearTableExpression) {
     Object oldValue = this.clearTableExpression;
     this.clearTableExpression = clearTableExpression;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/decd6ab8/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
index b451709..57f4ed9 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
@@ -137,11 +137,14 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
 
   private final JList ignoreList = new JList();
   private final JEditorPane ignoreExpressionEntryField = new JEditorPane();
+  private final JEditorPane alwaysDisplayExpressionEntryField = new JEditorPane();
   private final JScrollPane ignoreListScroll = new JScrollPane(ignoreList);
   private final JDialog ignoreDialog = new JDialog();
   private final JDialog ignoreExpressionDialog = new JDialog();
+  private final JDialog alwaysDisplayExpressionDialog = new JDialog();
   private final JLabel ignoreSummary = new JLabel("0 hidden loggers");
   private final JLabel ignoreExpressionSummary = new JLabel("Ignore expression");
+  private final JLabel alwaysDisplayExpressionSummary = new JLabel("Always displayed expression");
   private final SmallToggleButton ignoreLoggerButton = new SmallToggleButton();
   private final EventListenerList listenerList = new EventListenerList();
   private final JTree logTree;
@@ -159,6 +162,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
   private final LogPanel logPanel;
   private final RuleColorizer colorizer;
   private Rule ignoreExpressionRule;
+  private Rule alwaysDisplayExpressionRule;
   private boolean expandRootLatch = false;
   private String currentlySelectedLoggerName;
 
@@ -179,12 +183,13 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
 
     setLayout(new BorderLayout());
     ignoreExpressionEntryField.setPreferredSize(new Dimension(300, 150));
-
+    alwaysDisplayExpressionEntryField.setPreferredSize(new Dimension(300, 150));
+    alwaysDisplayExpressionSummary.setMinimumSize(new Dimension(10, alwaysDisplayExpressionSummary.getHeight()));
     ignoreExpressionSummary.setMinimumSize(new Dimension(10, ignoreExpressionSummary.getHeight()));
     ignoreSummary.setMinimumSize(new Dimension(10, ignoreSummary.getHeight()));
 
     JTextComponentFormatter.applySystemFontAndSize(ignoreExpressionEntryField);
-
+    JTextComponentFormatter.applySystemFontAndSize(alwaysDisplayExpressionEntryField);
 
     visibilityRuleDelegate = new VisibilityRuleDelegate();
     colorRuleDelegate = 
@@ -194,7 +199,8 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
           {
             boolean hiddenLogger = e.getLoggerName() != null && isHiddenLogger(e.getLoggerName());
             boolean hiddenExpression = (ignoreExpressionRule != null && ignoreExpressionRule.evaluate(e, null));
-            boolean hidden = hiddenLogger || hiddenExpression;
+            boolean alwaysDisplayExpression = (alwaysDisplayExpressionRule != null && alwaysDisplayExpressionRule.evaluate(e, null));
+            boolean hidden = (!alwaysDisplayExpression) && (hiddenLogger || hiddenExpression);
             String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
 
             if (!isFocusOnSelected() && !hidden && currentlySelectedLoggerName != null && !"".equals(currentlySelectedLoggerName))
@@ -298,6 +304,9 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     ignoreExpressionDialog.setTitle("Hidden/Ignored Expression");
     ignoreExpressionDialog.setModal(true);
 
+    alwaysDisplayExpressionDialog.setTitle("Always displayed Expression");
+    alwaysDisplayExpressionDialog.setModal(true);
+
     JPanel ignorePanel = new JPanel();
     ignorePanel.setLayout(new BoxLayout(ignorePanel, BoxLayout.Y_AXIS));
     JPanel ignoreSummaryPanel = new JPanel();
@@ -315,6 +324,14 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
           LogPanel.centerAndSetVisible(ignoreExpressionDialog);
       }
     };
+
+
+    Action showAlwaysDisplayExpressionDialogAction = new AbstractAction("...") {
+      public void actionPerformed(ActionEvent e) {
+          LogPanel.centerAndSetVisible(alwaysDisplayExpressionDialog);
+      }
+    };
+
     showIgnoreDialogAction.putValue(Action.SHORT_DESCRIPTION, "Click to view and manage your hidden/ignored loggers");
     JButton btnShowIgnoreDialog = new SmallButton(showIgnoreDialogAction);
     
@@ -329,6 +346,16 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     ignoreExpressionPanel.add(btnShowIgnoreExpressionDialog);
 
     ignorePanel.add(ignoreExpressionPanel);
+
+    JPanel alwaysDisplayExpressionPanel = new JPanel();
+    alwaysDisplayExpressionPanel.setLayout(new BoxLayout(alwaysDisplayExpressionPanel, BoxLayout.X_AXIS));
+    alwaysDisplayExpressionPanel.add(alwaysDisplayExpressionSummary);
+    showAlwaysDisplayExpressionDialogAction.putValue(Action.SHORT_DESCRIPTION, "Click to view and manage your always-displayed expression");
+    JButton btnShowAlwaysDisplayExpressionDialog = new SmallButton(showAlwaysDisplayExpressionDialogAction);
+    alwaysDisplayExpressionPanel.add(btnShowAlwaysDisplayExpressionDialog);
+
+    ignorePanel.add(alwaysDisplayExpressionPanel);
+
     add(ignorePanel, BorderLayout.SOUTH);
 
     ignoreList.setModel(new DefaultListModel());
@@ -376,9 +403,29 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
                 ignoreExpressionDialog.setVisible(false);
               }
           }});
-    JPanel closePanel = new JPanel();
-    closePanel.add(ignoreExpressionCloseButton);
-    ignoreExpressionDialogPanel.add(closePanel, BorderLayout.SOUTH);
+
+
+    JPanel alwaysDisplayExpressionDialogPanel = new JPanel(new BorderLayout());
+    alwaysDisplayExpressionEntryField.addKeyListener(new ExpressionRuleContext(filterModel, alwaysDisplayExpressionEntryField));
+
+    alwaysDisplayExpressionDialogPanel.add(new JScrollPane(alwaysDisplayExpressionEntryField), BorderLayout.CENTER);
+    JButton alwaysDisplayExpressionCloseButton = new JButton(new AbstractAction(" Close ") {
+          public void actionPerformed(ActionEvent e)
+          {
+              String alwaysDisplayText = alwaysDisplayExpressionEntryField.getText();
+
+              if (updateAlwaysDisplayExpression(alwaysDisplayText)) {
+                alwaysDisplayExpressionDialog.setVisible(false);
+              }
+          }});
+
+    JPanel closeAlwaysDisplayExpressionPanel = new JPanel();
+    closeAlwaysDisplayExpressionPanel.add(alwaysDisplayExpressionCloseButton);
+    alwaysDisplayExpressionDialogPanel.add(closeAlwaysDisplayExpressionPanel, BorderLayout.SOUTH);
+
+    JPanel closeIgnoreExpressionPanel = new JPanel();
+    closeIgnoreExpressionPanel.add(ignoreExpressionCloseButton);
+    ignoreExpressionDialogPanel.add(closeIgnoreExpressionPanel, BorderLayout.SOUTH);
 
     Box ignoreListButtonPanel = Box.createHorizontalBox();
     
@@ -415,6 +462,9 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
 
     ignoreExpressionDialog.getContentPane().add(ignoreExpressionDialogPanel);
     ignoreExpressionDialog.pack();
+
+    alwaysDisplayExpressionDialog.getContentPane().add(alwaysDisplayExpressionDialogPanel);
+    alwaysDisplayExpressionDialog.pack();
   }
 
     private boolean updateIgnoreExpression(String ignoreText)
@@ -427,7 +477,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
             }
             visibilityRuleDelegate.firePropertyChange("hiddenSet", null, null);
 
-            updateAllIgnoreStuff();
+            updateDisplay();
             ignoreExpressionEntryField.setBackground(UIManager.getColor("TextField.background"));
             return true;
         } catch (IllegalArgumentException iae) {
@@ -437,6 +487,26 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
         }
     }
 
+    private boolean updateAlwaysDisplayExpression(String alwaysDisplayText)
+    {
+        try {
+            if (alwaysDisplayText != null && !alwaysDisplayText.trim().equals("")) {
+                alwaysDisplayExpressionRule = ExpressionRule.getRule(alwaysDisplayText);
+            } else {
+                alwaysDisplayExpressionRule = null;
+            }
+            visibilityRuleDelegate.firePropertyChange("alwaysDisplayedSet", null, null);
+
+            updateDisplay();
+            alwaysDisplayExpressionEntryField.setBackground(UIManager.getColor("TextField.background"));
+            return true;
+        } catch (IllegalArgumentException iae) {
+            alwaysDisplayExpressionEntryField.setToolTipText(iae.getMessage());
+            alwaysDisplayExpressionEntryField.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
+            return false;
+        }
+    }
+
     //~ Methods =================================================================
 
   /**
@@ -1426,7 +1496,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
         public void stateChanged(ChangeEvent evt)
         {
           visibilityRuleDelegate.firePropertyChange("rule", null, null);
-          updateAllIgnoreStuff();
+          updateDisplay();
         }
       });
 
@@ -1435,16 +1505,17 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
         public void propertyChange(PropertyChangeEvent event)
         {
           if (event.getPropertyName().equals("hiddenSet")) {
-            updateAllIgnoreStuff();
+            updateDisplay();
           }
         }
       });
   }
 
-  private void updateAllIgnoreStuff() {
+  private void updateDisplay() {
       updateHiddenSetModels();
       updateIgnoreSummary();
       updateIgnoreExpressionSummary();
+      updateAlwaysDisplayExpressionSummary();
   }
   
   private void updateHiddenSetModels() {
@@ -1470,6 +1541,10 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     ignoreExpressionSummary.setText(ignoreExpressionRule != null?"Ignore (set)":"Ignore (unset)");
   }
   
+  private void updateAlwaysDisplayExpressionSummary() {
+    alwaysDisplayExpressionSummary.setText(alwaysDisplayExpressionRule != null?"Always displayed (set)":"Always displayed (unset)");
+  }
+
   private void toggleFocusOnState()
   {
     setFocusOnSelected(!isFocusOnSelected());
@@ -1493,6 +1568,19 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
         updateIgnoreExpression(hiddenExpression);
     }
 
+    public String getAlwaysDisplayExpression() {
+        String text = alwaysDisplayExpressionEntryField.getText();
+        if (text == null || text.trim().equals("")) {
+            return null;
+        }
+        return text.trim();
+    }
+
+    public void setAlwaysDisplayExpression(String alwaysDisplayExpression) {
+        alwaysDisplayExpressionEntryField.setText(alwaysDisplayExpression);
+        updateAlwaysDisplayExpression(alwaysDisplayExpression);
+    }
+
     public void loggerNameAdded(String loggerName)
     {
         //no-op
@@ -1810,7 +1898,8 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
           String currentlySelectedLoggerName = getCurrentlySelectedLoggerName();
           boolean hiddenLogger = e.getLoggerName() != null && isHiddenLogger(e.getLoggerName());
           boolean hiddenExpression = (ignoreExpressionRule != null && ignoreExpressionRule.evaluate(e, null));
-          boolean hidden = hiddenLogger || hiddenExpression;
+          boolean alwaysDisplayExpression = (alwaysDisplayExpressionRule != null && alwaysDisplayExpressionRule.evaluate(e, null));
+          boolean hidden = (!alwaysDisplayExpression) && (hiddenLogger || hiddenExpression);
           if (currentlySelectedLoggerName == null) {
           	//if there is no selected logger, pass if not hidden
           	return !hidden;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/decd6ab8/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index cf5e053..98e26df 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,6 +10,10 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>2 Oct 2011</h2>
+<ul>
+<li>Added persistent "always display" expression support (button below the logger tree).  The 'always display' expression overrides hidden loggers and the hidden expression but not the refine focus filtering mechanism.  Often used with expressions like 'exception exists || level > warn' to ensure errors and exceptions are not filtered out due to the hidden expression or hidden logger mechanism. </li>
+</ul>
 <h2>11 Nov 2010</h2>
 <ul>
 <li>Added per-tab preference to not use a search match color in the primary table</li>


[21/50] [abbrv] logging-chainsaw git commit: Added multi-select capability to event table and 'copy selection' context menu item (multi-select by holding down alt key while selecting rows) New 'add to find field' context menu option Simplified context me

Posted by rg...@apache.org.
Added multi-select capability to event table and 'copy selection' context menu item (multi-select by holding down alt key while selecting rows)
New 'add to find field' context menu option
Simplified context menu (removed scroll to bottom/top, moved dock option to bottom)
Updated logic determining value for a specific cell


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/9f01847a
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/9f01847a
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/9f01847a

Branch: refs/heads/master
Commit: 9f01847ae19f6ae850b6c7f4baf5a71c9dcd8361
Parents: cf258ed
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Nov 6 23:42:31 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Nov 6 23:42:31 2010 +0000

----------------------------------------------------------------------
 .../org/apache/log4j/chainsaw/LogPanel.java     | 399 ++++++++++---------
 .../log4j/chainsaw/LoggerNameTreePanel.java     |  55 ++-
 .../log4j/chainsaw/TableColorizingRenderer.java |   5 +-
 .../apache/log4j/chainsaw/color/ColorPanel.java |  16 +-
 .../log4j/chainsaw/help/release-notes.html      |   1 +
 5 files changed, 267 insertions(+), 209 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9f01847a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index edeec44..70d54da 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -40,6 +40,7 @@ import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionAdapter;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
@@ -57,9 +58,9 @@ import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.text.DateFormat;
 import java.text.NumberFormat;
-import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.Enumeration;
 import java.util.EventObject;
 import java.util.HashMap;
@@ -79,7 +80,6 @@ import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.ComboBoxEditor;
-import javax.swing.ComboBoxModel;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JCheckBoxMenuItem;
@@ -206,6 +206,7 @@ import com.thoughtworks.xstream.io.xml.DomDriver;
  *
  */
 public class LogPanel extends DockablePanel implements EventBatchListener, Profileable {
+  private static final DateFormat TIMESTAMP_DATE_FORMAT = new SimpleDateFormat(Constants.TIMESTAMP_RULE_FORMAT);
   private static final double DEFAULT_DETAIL_SPLIT_LOCATION = 0.71d;
   private static final double DEFAULT_LOG_TREE_SPLIT_LOCATION = 0.2d;
   private final String identifier;
@@ -247,7 +248,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   static final String COLORS_EXTENSION = ".colors";
   private static final int LOG_PANEL_SERIALIZATION_VERSION_NUMBER = 2; //increment when format changes
   private int previousLastIndex = -1;
-  private final DateFormat timestampExpressionFormat = new SimpleDateFormat(Constants.TIMESTAMP_RULE_FORMAT);
   private final Logger logger = LogManager.getLogger(LogPanel.class);
   private AutoFilterComboBox filterCombo;
   private AutoFilterComboBox findCombo;
@@ -408,27 +408,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       });
     menuItemLoggerTree.setIcon(new ImageIcon(ChainsawIcons.WINDOW_ICON));
 
-    final JMenuItem menuItemScrollToTop = new JMenuItem("Scroll to top");
-    menuItemScrollToTop.addActionListener(
-      new ActionListener() {
-          public void actionPerformed(ActionEvent evt)
-          {
-              scrollToTop();
-          }
-      });
-    final JCheckBoxMenuItem menuItemScrollBottom =
-      new JCheckBoxMenuItem("Scroll to bottom");
-    menuItemScrollBottom.addActionListener(
-      new ActionListener() {
-        public void actionPerformed(ActionEvent evt) {
-          preferenceModel.setScrollToBottom(menuItemScrollBottom.isSelected());
-        }
-      });
-    menuItemScrollBottom.setSelected(isScrollToBottom());
-
-    menuItemScrollBottom.setIcon(
-      new ImageIcon(ChainsawIcons.SCROLL_TO_BOTTOM));
-
     final JCheckBoxMenuItem menuItemToggleDetails =
       new JCheckBoxMenuItem("Show Detail Pane");
     menuItemToggleDetails.addActionListener(
@@ -644,18 +623,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       });
 
     preferenceModel.addPropertyChangeListener(
-      "scrollToBottom",
-      new PropertyChangeListener() {
-        public void propertyChange(PropertyChangeEvent evt) {
-          boolean value = ((Boolean) evt.getNewValue()).booleanValue();
-          menuItemScrollBottom.setSelected(value);
-          if (value) {
-            scrollToBottom();
-          }
-        }
-      });
-
-    preferenceModel.addPropertyChangeListener(
       "detailPaneVisible",
       new PropertyChangeListener() {
         public void propertyChange(PropertyChangeEvent evt) {
@@ -1562,26 +1529,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
             int column = currentTable.columnAtPoint(currentPoint);
             int row = currentTable.rowAtPoint(currentPoint);
             String colName = currentTable.getColumnName(column).toUpperCase();
-            String value = "";
-
-            if (colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
-              try {
-                value = timestampExpressionFormat.parse(currentTable.getValueAt(row, column).toString()).toString();
-              } catch (ParseException e) {
-                e.printStackTrace();
-              }
-            } else {
-              Object o = table.getValueAt(row, column);
-
-              if (o != null) {
-                if (o instanceof String[] && ((String[])o).length > 0) {
-                  value = ((String[]) o)[0];
-                  operator = "~=";
-                } else {
-                  value = o.toString();
-                }
-              }
-            }
+            String value = getValueOf(row, column);
 
             if (columnNameKeywordMap.containsKey(colName)) {
               filterText.setText(
@@ -1604,32 +1552,41 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
             String operator = "==";
             int column = currentTable.columnAtPoint(currentPoint);
             int row = currentTable.rowAtPoint(currentPoint);
+            String value = getValueOf(row, column);
             String colName = currentTable.getColumnName(column).toUpperCase();
-            String value = "";
 
-            if (colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
-              JComponent comp =
-                (JComponent) currentTable.getCellRenderer(row, column);
+            if (columnNameKeywordMap.containsKey(colName)) {
+              filterText.setText(
+                filterText.getText() + " && "
+                + columnNameKeywordMap.get(colName).toString() + " "
+                + operator + " '" + value + "'");
+            }
 
-              if (comp instanceof JLabel) {
-                value = ((JLabel) comp).getText();
-              }
-            } else {
-              Object o = currentTable.getValueAt(row, column);
+          }
+        }
+      });
+      }
+    }
 
-              if (o instanceof String[] && ((String[])o).length > 0) {
-                value = ((String[]) o)[0];
-                operator = "~=";
-              } else {
-                value = o.toString();
-              }
-            }
+        class DefineAddCustomFind extends JMenuItem {
+      public DefineAddCustomFind() {
+        super("Add value under pointer to 'find' field");
+  addActionListener(
+      new ActionListener() {
+        public void actionPerformed(ActionEvent evt) {
+          if (currentPoint != null) {
+            String operator = "==";
+            int column = currentTable.columnAtPoint(currentPoint);
+            int row = currentTable.rowAtPoint(currentPoint);
+            String value = getValueOf(row, column);
+            String colName = currentTable.getColumnName(column).toUpperCase();
 
             if (columnNameKeywordMap.containsKey(colName)) {
-              filterText.setText(
-                filterText.getText() + " && "
+              findCombo.setSelectedItem(
+                findText.getText() + " && "
                 + columnNameKeywordMap.get(colName).toString() + " "
                 + operator + " '" + value + "'");
+              findNext();
             }
           }
         }
@@ -1648,24 +1605,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
             int column = currentTable.columnAtPoint(currentPoint);
             int row = currentTable.rowAtPoint(currentPoint);
             String colName = currentTable.getColumnName(column).toUpperCase();
-            String value = "";
-
-            if (colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
-              JComponent comp =
-                (JComponent) currentTable.getCellRenderer(row, column);
-
-              if (comp instanceof JLabel) {
-                value = ((JLabel) comp).getText();
-              }
-            } else {
-              Object o = currentTable.getValueAt(row, column);
-
-              if (o instanceof String[] && ((String[])o).length > 0) {
-                value = ((String[]) o)[0];
-              } else {
-                value = o.toString();
-              }
-            }
+            String value = getValueOf(row, column);
 
             if (columnNameKeywordMap.containsKey(colName)) {
                 Color c = JColorChooser.showDialog(getRootPane(), "Choose a color", Color.red);
@@ -1695,49 +1635,49 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         }
       }
 
-    class Copy extends AbstractAction {
-      public Copy() {
+    class CopySelection extends AbstractAction {
+      public CopySelection() {
+        super("Copy selection to clipboard");
+      }
+
+        public void actionPerformed(ActionEvent e) {
+          if (currentTable == null) {
+            return;
+          }
+          int start = currentTable.getSelectionModel().getMinSelectionIndex();
+          int end = currentTable.getSelectionModel().getMaxSelectionIndex();
+          StringBuffer result = new StringBuffer();
+          for (int row=start;row<end+1;row++) {
+            for (int column=0;column<currentTable.getColumnCount();column++) {
+              result.append(getValueOf(row, column));
+              if (column != (currentTable.getColumnCount() - 1)) {
+                result.append(" - ");
+              }
+            }
+            result.append(System.getProperty("line.separator"));
+          }
+          StringSelection selection = new StringSelection(result.toString());
+          Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+          clipboard.setContents(selection, null);
+      }
+    }
+
+    class CopyField extends AbstractAction {
+      public CopyField() {
         super("Copy value under pointer to clipboard");
       }
 
         public void actionPerformed(ActionEvent e) {
-          if (currentPoint != null) {
+          if (currentPoint != null && currentTable != null) {
             int column = currentTable.columnAtPoint(currentPoint);
             int row = currentTable.rowAtPoint(currentPoint);
-            String colName = currentTable.getColumnName(column).toUpperCase();
-            String value = "";
-
-            if (colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
-              JComponent comp =
-                (JComponent) currentTable.getCellRenderer(row, column);
-
-              if (comp instanceof JLabel) {
-                value = ((JLabel) comp).getText();
-              }
-            } else {
-              Object o = currentTable.getValueAt(row, column);
-              //exception - build message + throwable
-              if (o != null) {
-                  if (o instanceof String[]) {
-                      String[] ti = (String[])o;
-                      if (ti.length > 0 && (!(ti.length == 1 && ti[0].equals("")))) {
-                        LoggingEventWrapper loggingEventWrapper = ((ChainsawCyclicBufferTableModel)(currentTable.getModel())).getRow(row);
-                        value = loggingEventWrapper.getLoggingEvent().getMessage().toString();
-                        for (int i=0;i<((String[])o).length;i++) {
-                            value = value + "\n" + ((String[]) o)[i];
-                        }
-                      }
-                  } else {
-                    value = o.toString();
-                  }
-              }
-            }
+            String value = getValueOf(row, column);
             StringSelection selection = new StringSelection(value);
             Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
             clipboard.setContents(selection, null);
         }
       }
-      }
+    }
     final JMenuItem menuItemToggleDock = new JMenuItem("Undock/dock");
 
     dockingAction =
@@ -1769,36 +1709,17 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     class Search extends JMenuItem {
       public Search() {
-        super("Search for value under pointer");
+        super("Find value under pointer");
 
     addActionListener(
       new ActionListener() {
         public void actionPerformed(ActionEvent evt) {
           if (currentPoint != null) {
-            String operator = "~=";
+            String operator = "==";
             int column = currentTable.columnAtPoint(currentPoint);
             int row = currentTable.rowAtPoint(currentPoint);
             String colName = currentTable.getColumnName(column).toUpperCase();
-            String value = "";
-
-            if (colName.equalsIgnoreCase(ChainsawConstants.TIMESTAMP_COL_NAME)) {
-              try {
-                value = timestampExpressionFormat.parse(currentTable.getValueAt(row, column).toString()).toString();
-              } catch (ParseException e) {
-                e.printStackTrace();
-              }
-            } else {
-              Object o = currentTable.getValueAt(row, column);
-
-              if (o != null) {
-                if (o instanceof String[] && ((String[])o).length > 0) {
-                  value = ((String[]) o)[0];
-                } else {
-                  value = o.toString();
-                }
-              }
-            }
-
+            String value = getValueOf(row, column);
             if (columnNameKeywordMap.containsKey(colName)) {
               findCombo.setSelectedItem(
                 columnNameKeywordMap.get(colName).toString() + " " + operator
@@ -1823,18 +1744,14 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     mainPopup.add(new Search());
     searchPopup.add(new Search());
+    mainPopup.add(new DefineAddCustomFind());
+    searchPopup.add(new DefineAddCustomFind());
     mainPopup.add(new ClearSearch());
     searchPopup.add(new ClearSearch());
 
     mainPopup.add(new JSeparator());
     searchPopup.add(new JSeparator());
 
-    mainPopup.add(new BestFit());
-    searchPopup.add(new BestFit());
-
-    mainPopup.add(new JSeparator());
-    searchPopup.add(new JSeparator());
-
     class DisplayNormalTimes extends JMenuItem {
       public DisplayNormalTimes() {
         super("Hide relative times");
@@ -1900,8 +1817,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     mainPopup.add(new BuildColorRule());
     searchPopup.add(new BuildColorRule());
-    mainPopup.add(new Copy());
-    searchPopup.add(new Copy());
+    mainPopup.add(new JSeparator());
+    searchPopup.add(new JSeparator());
+    mainPopup.add(new CopyField());
+    mainPopup.add(new CopySelection());
+    searchPopup.add(new CopyField());
+    searchPopup.add(new CopySelection());
     mainPopup.add(new JSeparator());
     searchPopup.add(new JSeparator());
 
@@ -1913,14 +1834,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     searchPopup.add(searchToggleToolTips);
 
     mainPopup.add(new JSeparator());
-    searchPopup.add(new JSeparator());
-
-    mainPopup.add(menuItemScrollToTop);
-    mainPopup.add(menuItemScrollBottom);
-    mainPopup.add(new JSeparator());
 
     mainPopup.add(menuItemToggleDock);
 
+    mainPopup.add(new BestFit());
+    searchPopup.add(new BestFit());
+
     mainPopup.add(new JSeparator());
 
     mainPopup.add(new ColorPanel());
@@ -1932,11 +1851,108 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     eventsPane.addMouseListener(mainTablePopupListener);
     table.addMouseListener(mainTablePopupListener);
 
+    table.addMouseListener(new MouseListener(){
+      public void mouseClicked(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mousePressed(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseReleased(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseEntered(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseExited(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      private void checkMultiSelect(MouseEvent mouseEvent) {
+        if (mouseEvent.isAltDown()) {
+          table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        } else {
+          table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        }
+      }
+    });
+
+
+    searchTable.addMouseListener(new MouseListener(){
+      public void mouseClicked(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mousePressed(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseReleased(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseEntered(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      public void mouseExited(MouseEvent mouseEvent) {
+        checkMultiSelect(mouseEvent);
+      }
+
+      private void checkMultiSelect(MouseEvent mouseEvent) {
+        if (mouseEvent.isAltDown()) {
+          searchTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
+        } else {
+          searchTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        }
+      }
+    });
+
+
     final PopupListener searchTablePopupListener = new PopupListener(searchPopup);
     searchPane.addMouseListener(searchTablePopupListener);
     searchTable.addMouseListener(searchTablePopupListener);
   }
 
+       private String getValueOf(int row, int column) {
+         if (currentTable == null) {
+           return "";
+         }
+
+         Object o = currentTable.getValueAt(row, column);
+
+         if (o instanceof Date) {
+           return TIMESTAMP_DATE_FORMAT.format((Date)o);
+         }
+
+         if (o instanceof String) {
+           return (String)o;
+         }
+
+         if (o instanceof Level) {
+           return o.toString();
+         }
+
+         if (o instanceof String[]) {
+           String value = "";
+          //exception - build message + throwable
+          String[] ti = (String[])o;
+            if (ti.length > 0 && (!(ti.length == 1 && ti[0].equals("")))) {
+              LoggingEventWrapper loggingEventWrapper = ((ChainsawCyclicBufferTableModel)(currentTable.getModel())).getRow(row);
+              value = loggingEventWrapper.getLoggingEvent().getMessage().toString();
+              for (int i=0;i<((String[])o).length;i++) {
+                  value = value + "\n" + ((String[]) o)[i];
+              }
+            }
+           return value;
+         }
+         return "";
+      }
+
     private Action getFindNextAction() {
     final Action action =
       new AbstractAction("Find next") {
@@ -1988,7 +2004,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     if (isFiltering) {
       filterText.getDocument().addDocumentListener(new DelayedTextDocumentListener(filterText));
     }
-    filterText.setToolTipText("Enter an expression, press enter to add to list");
+    filterText.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
     filterText.addKeyListener(new ExpressionRuleContext(filterModel, filterText));
 
     if (combo.getEditor().getEditorComponent() instanceof JTextField) {
@@ -2604,7 +2620,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       //reset background color in case we were previously an invalid expression
       findCombo.setBackground(UIManager.getColor("TextField.background"));
       findCombo.setToolTipText(
-        "Enter expression - right click or ctrl-space for menu");
+        "Enter an expression - right click or ctrl-space for menu - press enter to add to list");
       currentSearchMatchCount = 0;
       currentFindRuleText = null;
       statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
@@ -2621,8 +2637,9 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       }
       currentFindRuleText = ruleText;
       try {
-        findCombo.setToolTipText(
-          "Enter expression - right click or ctrl-space for menu");
+        final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
+        findText.setToolTipText(
+          "Enter an expression - right click or ctrl-space for menu - press enter to add to list");
         findRule = ExpressionRule.getRule(ruleText);
         currentSearchMatchCount = tableModel.updateEventsWithFindRule(findRule);
         searchModel.updateEventsWithFindRule(findRule);
@@ -2630,15 +2647,16 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         tableRuleMediator.setFindRule(findRule);
         searchRuleMediator.setFindRule(findRule);
         //valid expression, reset background color in case we were previously an invalid expression
-        findCombo.setBackground(UIManager.getColor("TextField.background"));
+        findText.setBackground(UIManager.getColor("TextField.background"));
         statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
         if (isSearchResultsVisible()) {
           showSearchResults();
         }
       } catch (IllegalArgumentException re) {
         findRule = null;
-        findCombo.setToolTipText(re.getMessage());
-        findCombo.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
+        final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
+        findText.setToolTipText(re.getMessage());
+        findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
         colorizer.setFindRule(null);
         tableRuleMediator.setFindRule(null);
         searchRuleMediator.setFindRule(null);
@@ -3012,6 +3030,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     if (findRule != null) {
         EventQueue.invokeLater(new Runnable() {
             public void run() {
+              final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
                 try {
                   int filteredEventsSize = getFilteredEvents().size();
                   int startRow = table.getSelectedRow() + 1;
@@ -3023,10 +3042,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
                   if (nextRow > -1) {
                     table.scrollToRow(nextRow);
-                    findCombo.setToolTipText("Enter an expression");
+                    findText.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
                   }
+                  findText.setBackground(UIManager.getColor("TextField.background"));
                 } catch (IllegalArgumentException iae) {
-                  findCombo.setToolTipText(iae.getMessage());
+                  findText.setToolTipText(iae.getMessage());
+                  findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
                   colorizer.setFindRule(null);
                   tableRuleMediator.setFindRule(null);
                   searchRuleMediator.setFindRule(null);
@@ -3048,6 +3069,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     if (findRule != null) {
         EventQueue.invokeLater(new Runnable() {
             public void run() {
+              final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
                 try {
                     int startRow = table.getSelectedRow() - 1;
                     int filteredEventsSize = getFilteredEvents().size();
@@ -3058,10 +3080,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
                     if (previousRow > -1) {
                         table.scrollToRow(previousRow);
-                        findCombo.setToolTipText("Enter an expression");
+                        findCombo.setToolTipText("Enter an expression - right click or ctrl-space for menu - press enter to add to list");
                     }
+                  findText.setBackground(UIManager.getColor("TextField.background"));
                 } catch (IllegalArgumentException iae) {
-                  findCombo.setToolTipText(iae.getMessage());
+                  findText.setToolTipText(iae.getMessage());
+                  findText.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
                 }
             }
         });
@@ -3296,6 +3320,19 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         }
     }
 
+  public void setFindText(String findText) {
+    findCombo.setSelectedItem(findText);
+    findNext();
+  }
+
+  public String getFindText() {
+    Object selectedItem = findCombo.getSelectedItem();
+    if (selectedItem == null) {
+      return "";
+    }
+    return selectedItem.toString();
+  }
+
   /**
    * This class receives notification when the Refine focus or find field is
    * updated, where a background thread periodically wakes up and checks if
@@ -3419,28 +3456,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         }
       }
     }
-
-    private void setFind() {
-      if (textField.getText().trim().equals("")) {
-        //reset background color in case we were previously an invalid expression
-        textField.setBackground(UIManager.getColor("TextField.background"));
-        tableRuleMediator.setFindRule(null);
-        searchRuleMediator.setFindRule(null);
-        textField.setToolTipText(defaultToolTip);
-      } else {
-        try {
-          tableRuleMediator.setFindRule(ExpressionRule.getRule(textField.getText()));
-          searchRuleMediator.setFindRule(ExpressionRule.getRule(textField.getText()));
-          textField.setToolTipText(defaultToolTip);
-          //valid expression, reset background color in case we were previously an invalid expression
-          textField.setBackground(UIManager.getColor("TextField.background"));
-        } catch (IllegalArgumentException iae) {
-          //invalid expression, change background of the field
-          textField.setToolTipText(iae.getMessage());
-          textField.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
-        }
-      }
-    }
   }
 
   private final class TableMarkerListener extends MouseAdapter {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9f01847a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
index f5ac429..ff01eed 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
@@ -24,7 +24,6 @@ import java.awt.Component;
 import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.EventQueue;
-import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.Point;
 import java.awt.Toolkit;
@@ -120,11 +119,12 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
   private final Action editLoggerAction;
   private final JButton editLoggerButton = new SmallButton();
   private final Action expandAction;
-  private final Action findNextAction;
+  private final Action findAction;
   private final Action clearFindNextAction;
   private final Action defineColorRuleForLoggerAction;
   private final Action setRefineFocusAction;
   private final Action updateRefineFocusAction;
+  private final Action updateFindAction;
   private final JButton expandButton = new SmallButton();
   private final Action focusOnAction;
   private final Action clearRefineFocusAction;
@@ -270,12 +270,13 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     toolbar.setLayout(new BoxLayout(toolbar, BoxLayout.X_AXIS));
 
     expandAction = createExpandAction();
-    findNextAction = createFindNextAction();
+    findAction = createFindNextAction();
     clearFindNextAction = createClearFindNextAction();
     defineColorRuleForLoggerAction = createDefineColorRuleForLoggerAction();
     clearRefineFocusAction = createClearRefineFocusAction();
     setRefineFocusAction = createSetRefineFocusAction();
     updateRefineFocusAction = createUpdateRefineFocusAction();
+    updateFindAction = createUpdateFindAction();
     editLoggerAction = createEditLoggerAction();
     closeAction = createCloseAction();
     collapseAction = createCollapseAction();
@@ -873,6 +874,38 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
       return action;
     }
 
+  private Action createUpdateFindAction()
+  {
+    Action action = new AbstractAction()
+      {
+        public void actionPerformed(ActionEvent e)
+        {
+          updateFindUsingCurrentlySelectedNode();
+        }
+      };
+
+    action.putValue(Action.NAME, "Update 'find' to include selected logger");
+    action.putValue(
+      Action.SHORT_DESCRIPTION,
+      "Add selected node to 'find' field");
+    action.setEnabled(false);
+
+    return action;
+  }
+
+  private void updateFindUsingCurrentlySelectedNode()
+  {
+      String selectedLogger = getCurrentlySelectedLoggerName();
+      TreePath[] paths = logTree.getSelectionPaths();
+
+      if (paths == null)
+      {
+        return;
+      }
+      String currentFindText = logPanel.getFindText();
+      logPanel.setFindText(currentFindText + " || logger ~= " + selectedLogger);
+  }
+
     private void updateRefineFocusUsingCurrentlySelectedNode()
     {
         String selectedLogger = getCurrentlySelectedLoggerName();
@@ -1116,12 +1149,12 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
       {
         return;
       }
-      visibilityRuleDelegate.firePropertyChange("searchExpression", null, "logger like '^" + selectedLogger + ".*'");
+      logPanel.setFindText("logger like '^" + selectedLogger + ".*'");
   }
 
   private void clearFindNext()
   {
-      visibilityRuleDelegate.firePropertyChange("searchExpression", null, "");
+      logPanel.setFindText("");
   }
 
   private void clearRefineFocus()
@@ -1238,18 +1271,20 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     {
       focusOnAction.putValue(Action.NAME, "Focus On...");
       hideAction.putValue(Action.NAME, "Ignore...");
-      findNextAction.putValue(Action.NAME, "Find...");
+      findAction.putValue(Action.NAME, "Find...");
       setRefineFocusAction.putValue(Action.NAME, "Set refine focus field");
       updateRefineFocusAction.putValue(Action.NAME, "Add to refine focus field");
+      updateFindAction.putValue(Action.NAME, "Add to find field");
       defineColorRuleForLoggerAction.putValue(Action.NAME, "Define color rule");
     }
     else
     {
       focusOnAction.putValue(Action.NAME, "Focus On '" + logger + "'");
       hideAction.putValue(Action.NAME, "Ignore '" + logger + "'");
-      findNextAction.putValue(Action.NAME, "Find '" + logger + "'");
+      findAction.putValue(Action.NAME, "Find '" + logger + "'");
       setRefineFocusAction.putValue(Action.NAME, "Set refine focus field to '" + logger + "'");
       updateRefineFocusAction.putValue(Action.NAME, "Add '" + logger + "' to 'refine focus' field");
+      updateFindAction.putValue(Action.NAME, "Add '" + logger + "' to 'find' field");
       defineColorRuleForLoggerAction.putValue(Action.NAME, "Define color rule for '" + logger + "'");
     }
 
@@ -1298,11 +1333,12 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
           }
 
           expandAction.setEnabled(path != null);
-          findNextAction.setEnabled(path != null);
+          findAction.setEnabled(path != null);
           clearFindNextAction.setEnabled(true);
           defineColorRuleForLoggerAction.setEnabled(path != null);
           setRefineFocusAction.setEnabled(path != null);
           updateRefineFocusAction.setEnabled(path != null);
+          updateFindAction.setEnabled(path != null);
           clearRefineFocusAction.setEnabled(true);
 
           if (currentlySelectedLoggerName != null)
@@ -1632,7 +1668,8 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
       add(updateRefineFocusAction);
       add(clearRefineFocusAction);
       addSeparator();
-      add(findNextAction);
+      add(findAction);
+      add(updateFindAction);
       add(clearFindNextAction);
 
       addSeparator();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9f01847a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index 209204d..983db9a 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -179,7 +179,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     int row, int col) {
     EventContainer container = (EventContainer) table.getModel();
     LoggingEventWrapper loggingEventWrapper = container.getRow(row);
-    value = formatField(value, row, loggingEventWrapper);
+    value = formatField(value, loggingEventWrapper);
     TableColumn tableColumn = table.getColumnModel().getColumn(col);
     int width = tableColumn.getWidth();
     JLabel label = (JLabel)super.getTableCellRendererComponent(table, value,
@@ -569,10 +569,9 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
    *
    * @param field object
    *
-   * @param renderingRow
    * @return formatted object
    */
-  private Object formatField(Object field, int renderingRow, LoggingEventWrapper loggingEventWrapper) {
+  private Object formatField(Object field, LoggingEventWrapper loggingEventWrapper) {
     if (!(field instanceof Date)) {
       return (field == null ? "" : field);
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9f01847a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
index 6234680..dcc4621 100644
--- a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
@@ -265,16 +265,22 @@ public class ColorPanel extends JPanel
         public void actionPerformed(ActionEvent e)
           {
               tableModel.getDataVector().clear();
-              RuleColorizer sourceColorizer = (RuleColorizer) allLogPanelColorizers.get(loadPanelColorizersComboBox.getSelectedItem().toString());
-              colorizer.setRules(sourceColorizer.getRules());
-              updateColors();
+              Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
+              if (selectedItem != null) {
+                RuleColorizer sourceColorizer = (RuleColorizer) allLogPanelColorizers.get(selectedItem.toString());
+                colorizer.setRules(sourceColorizer.getRules());
+                updateColors();
+              }
           }
       };
         
       loadPanelColorizersComboBox.addActionListener(new ActionListener() {
           public void actionPerformed(ActionEvent e) {
-              String selectedColorizerName = loadPanelColorizersComboBox.getSelectedItem().toString();
-              copyRulesAction.setEnabled(!(noTab.equals(selectedColorizerName)));
+              Object selectedItem = loadPanelColorizersComboBox.getSelectedItem();
+              if (selectedItem != null) {
+                String selectedColorizerName = selectedItem.toString();
+                copyRulesAction.setEnabled(!(noTab.equals(selectedColorizerName)));
+              }
           }
       });
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9f01847a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 59a0fb5..c9799bc 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -13,6 +13,7 @@
 <h2>6 Nov 2010</h2>
 <ul>
 <li>Log file receiver configurations can now be loaded from both log4j.xml and log4j.properties configuration fileappender entries</li>
+<li>Added multi-select capability to event table and 'copy selection' context menu item (multi-select by holding down alt key while selecting rows)</li>
 </ul>
 <h2>5 Nov 2010</h2>
 <ul>


[10/50] [abbrv] logging-chainsaw git commit: Update Chainsaw pom to reference extras 1.1

Posted by rg...@apache.org.
Update Chainsaw pom to reference extras 1.1


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/51e80e40
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/51e80e40
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/51e80e40

Branch: refs/heads/master
Commit: 51e80e40f1faf706dab77ff6bd1bc4c93c3e74fd
Parents: d5c24ec
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Oct 29 07:41:26 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Oct 29 07:41:26 2010 +0000

----------------------------------------------------------------------
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/51e80e40/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7e93683..f434fcd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -382,7 +382,7 @@
     <dependency>
       <groupId>log4j</groupId>
       <artifactId>apache-log4j-extras</artifactId>
-      <version>1.1-SNAPSHOT</version>
+      <version>1.1</version>
     </dependency>
     <dependency>
       <groupId>log4j</groupId>


[17/50] [abbrv] logging-chainsaw git commit: Minor UI cleanup

Posted by rg...@apache.org.
Minor UI cleanup


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/4caf2826
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/4caf2826
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/4caf2826

Branch: refs/heads/master
Commit: 4caf2826ee8ced88887f51b07244ab2298ca65e3
Parents: f95619e
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Nov 5 05:32:56 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Nov 5 05:32:56 2010 +0000

----------------------------------------------------------------------
 .../ApplicationPreferenceModelPanel.java        | 57 +++++++++-----------
 .../log4j/chainsaw/LogPanelPreferencePanel.java |  3 +-
 .../chainsaw/ReceiverConfigurationPanel.java    | 14 ++---
 3 files changed, 34 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/4caf2826/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index c1460e0..b96d052 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -170,11 +170,11 @@ public static void main(String[] args) {
   }
 
     public class VisualsPrefPanel extends BasicPrefPanel {
-    private final JRadioButton topPlacement = new JRadioButton("Top");
-    private final JRadioButton bottomPlacement = new JRadioButton("Bottom");
-    private final JCheckBox statusBar = new JCheckBox("Show Status bar");
-    private final JCheckBox toolBar = new JCheckBox("Show Toolbar");
-    private final JCheckBox receivers = new JCheckBox("Show Receivers");
+    private final JRadioButton topPlacement = new JRadioButton(" Top         ");
+    private final JRadioButton bottomPlacement = new JRadioButton(" Bottom         ");
+    private final JCheckBox statusBar = new JCheckBox(" Show Status bar ");
+    private final JCheckBox toolBar = new JCheckBox(" Show Toolbar ");
+    private final JCheckBox receivers = new JCheckBox(" Show Receivers ");
     private UIManager.LookAndFeelInfo[] lookAndFeels = UIManager.getInstalledLookAndFeels();
     private final ButtonGroup lookAndFeelGroup = new ButtonGroup();
 
@@ -306,12 +306,9 @@ public static void main(String[] args) {
       setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
 
       JPanel tabPlacementBox = new JPanel();
-      tabPlacementBox.setLayout(
-        new BoxLayout(tabPlacementBox, BoxLayout.Y_AXIS));
+      tabPlacementBox.setLayout(new BoxLayout(tabPlacementBox, BoxLayout.Y_AXIS));
 
-      tabPlacementBox.setBorder(
-        BorderFactory.createTitledBorder(
-          BorderFactory.createEtchedBorder(), "Tab Placement"));
+      tabPlacementBox.setBorder(BorderFactory.createTitledBorder(" Tab Placement "));
 
       ButtonGroup tabPlacementGroup = new ButtonGroup();
 
@@ -337,13 +334,11 @@ public static void main(String[] args) {
 
       JPanel lfPanel = new JPanel();
       lfPanel.setLayout(new BoxLayout(lfPanel, BoxLayout.Y_AXIS));
-      lfPanel.setBorder(
-        BorderFactory.createTitledBorder(
-          BorderFactory.createEtchedBorder(), "Look & Feel"));
+      lfPanel.setBorder(BorderFactory.createTitledBorder(" Look & Feel "));
 
       for (int i = 0; i < lookAndFeels.length; i++) {
         final UIManager.LookAndFeelInfo lfInfo = lookAndFeels[i];
-        final JRadioButton lfItem = new JRadioButton(lfInfo.getName());
+        final JRadioButton lfItem = new JRadioButton(" " + lfInfo.getName() + " ");
         lfItem.setName(lfInfo.getClassName());
         lfItem.addActionListener(
           new ActionListener() {
@@ -359,7 +354,7 @@ public static void main(String[] args) {
       try {
         final Class gtkLF =
           Class.forName("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
-        final JRadioButton lfIGTK = new JRadioButton("GTK+ 2.0");
+        final JRadioButton lfIGTK = new JRadioButton(" GTK+ 2.0 ");
         lfIGTK.addActionListener(
           new ActionListener() {
             public void actionPerformed(ActionEvent e) {
@@ -418,14 +413,14 @@ public static void main(String[] args) {
    */
   public class GeneralAllPrefPanel extends BasicPrefPanel {
     private final JCheckBox showNoReceiverWarning =
-      new JCheckBox("Prompt me on startup if there are no Receivers defined");
-    private final JCheckBox showSplash = new JCheckBox("Show Splash screen at startup");
+      new JCheckBox(" Prompt me on startup if there are no Receivers defined ");
+    private final JCheckBox showSplash = new JCheckBox(" Show Splash screen at startup ");
     private final JSlider responsiveSlider =
       new JSlider(SwingConstants.HORIZONTAL, 1, 4, 2);
-    private final JCheckBox confirmExit = new JCheckBox("Confirm Exit");
+    private final JCheckBox confirmExit = new JCheckBox(" Confirm Exit ");
     Dictionary sliderLabelMap = new Hashtable();
     
-    private final JCheckBox okToRemoveSecurityManager = new JCheckBox("Ok to remove SecurityManager");
+    private final JCheckBox okToRemoveSecurityManager = new JCheckBox(" Ok to remove SecurityManager ");
 
     public GeneralAllPrefPanel() {
       super("General");
@@ -449,7 +444,7 @@ public static void main(String[] args) {
       p.add(showNoReceiverWarning);
       p.add(Box.createHorizontalGlue());
 
-      confirmExit.setToolTipText("Is set, you will be prompted to confirm the exit Chainsaw");
+      confirmExit.setToolTipText("If set, you prompt to confirm Chainsaw exit");
       okToRemoveSecurityManager.setToolTipText("You will need to tick this to be able to load Receivers/Plugins that require external dependancies.");
       setupInitialValues();
       setupListeners();
@@ -459,7 +454,7 @@ public static void main(String[] args) {
 
       JPanel p1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
 
-      p1.add(new JLabel("Tab name/event routing expression"));
+      p1.add(new JLabel(" Tab name/event routing expression "));
       p1.add(Box.createHorizontalStrut(5));
       p1.add(identifierExpression);
       add(p1);
@@ -483,24 +478,24 @@ public static void main(String[] args) {
 
       JPanel p4 = new JPanel(new FlowLayout(FlowLayout.LEFT));
 
-      p4.add(new JLabel("ToolTip Display (millis)"));
+      p4.add(new JLabel(" ToolTip Display (millis) "));
       p4.add(Box.createHorizontalStrut(5));
       p4.add(toolTipDisplayMillis);
       add(p4);
 
       JPanel p5 = new JPanel(new FlowLayout(FlowLayout.LEFT));
 
-      p5.add(new JLabel("Cyclic buffer size"));
+      p5.add(new JLabel(" Cyclic buffer size "));
       p5.add(Box.createHorizontalStrut(5));
       p5.add(cyclicBufferSize);
       p5.add(Box.createHorizontalStrut(5));
-      p5.add(new JLabel("Cyclic buffer size change will take effect on Chainsaw restart"));
+      p5.add(new JLabel(" (effective on restart) "));
       add(p5);
 
       Box p6 = new Box(BoxLayout.Y_AXIS);
 
       Box configURLPanel = new Box(BoxLayout.X_AXIS);
-      JLabel configLabel = new JLabel("Auto Config URL");
+      JLabel configLabel = new JLabel(" Auto Config URL ");
       configURLPanel.add(configLabel);
       configURLPanel.add(Box.createHorizontalStrut(5));
 
@@ -585,9 +580,7 @@ public static void main(String[] args) {
       responsiveSlider.setPaintLabels(true);
       responsiveSlider.setPaintTrack(true);
 
-      responsiveSlider.setBorder(
-        BorderFactory.createTitledBorder(
-          BorderFactory.createEtchedBorder(), "Responsiveness"));
+      responsiveSlider.setBorder(BorderFactory.createTitledBorder(" Responsiveness "));
 
       //            responsiveSlider.setAlignmentY(0);
       //            responsiveSlider.setAlignmentX(0);
@@ -740,10 +733,10 @@ public static void main(String[] args) {
     }
 
     private void setupInitialValues() {
-      sliderLabelMap.put(new Integer(1), new JLabel("Fastest"));
-      sliderLabelMap.put(new Integer(2), new JLabel("Fast"));
-      sliderLabelMap.put(new Integer(3), new JLabel("Medium"));
-      sliderLabelMap.put(new Integer(4), new JLabel("Slow"));
+      sliderLabelMap.put(new Integer(1), new JLabel(" Fastest "));
+      sliderLabelMap.put(new Integer(2), new JLabel(" Fast "));
+      sliderLabelMap.put(new Integer(3), new JLabel(" Medium "));
+      sliderLabelMap.put(new Integer(4), new JLabel(" Slow "));
 
       //          
       showNoReceiverWarning.setSelected(

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/4caf2826/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
index 5cd7550..2beba05 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
@@ -233,6 +233,7 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
       });
       columnList.setCellRenderer(cellRenderer);
       columnBox.add(new JScrollPane(columnList));
+      columnBox.add(Box.createVerticalStrut(5));
       columnBox.add(setAsDefaultsButton);
       add(columnBox);
       add(Box.createVerticalGlue());
@@ -553,7 +554,7 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
     private final JCheckBox scrollToBottom =
       new JCheckBox("Scroll to bottom (view tracks with new events)");
     private final JCheckBox showMillisDeltaAsGap =
-      new JCheckBox("Display timestamp delta between displayed events as space between rows");
+      new JCheckBox("Display timestamp delta between events as row gap");
     private final JCheckBox toolTips =
       new JCheckBox("Show Event Detail Tooltips");
     private final JCheckBox thumbnailBarToolTips =

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/4caf2826/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index d04a8e1..adbe826 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -133,7 +133,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        logFileReceiverRadioButton = new JRadioButton("Load and tail events from a regular text log file");
+        logFileReceiverRadioButton = new JRadioButton(" Load and tail events from a regular text log file ");
         buttonGroup.add(logFileReceiverRadioButton);
         add(logFileReceiverRadioButton, c);
 
@@ -141,7 +141,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        networkReceiverRadioButton = new JRadioButton("Receive events from the network");
+        networkReceiverRadioButton = new JRadioButton(" Receive events from the network ");
         buttonGroup.add(networkReceiverRadioButton);
         add(networkReceiverRadioButton, c);
 
@@ -149,7 +149,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        useExistingConfigurationRadioButton = new JRadioButton("Use an existing Chainsaw configuration file...");
+        useExistingConfigurationRadioButton = new JRadioButton(" Use an existing Chainsaw configuration file ");
         buttonGroup.add(useExistingConfigurationRadioButton);
         add(useExistingConfigurationRadioButton, c);
 
@@ -158,7 +158,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
         c.insets = new Insets(0, 0, 0, 0);
-        useAutoSavedConfigRadioButton = new JRadioButton("Use auto-saved configuration from $HOME/.chainsaw/receiver-config.xml");
+        useAutoSavedConfigRadioButton = new JRadioButton(" Use auto-saved configuration from $HOME/.chainsaw/receiver-config.xml ");
         buttonGroup.add(useAutoSavedConfigRadioButton);
         add(useAutoSavedConfigRadioButton, c);
 
@@ -211,7 +211,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridy = 0;
         c.weightx = 1.0;
         c.anchor = GridBagConstraints.LINE_START;
-        dontwarnIfNoReceiver = new JCheckBox("Always start Chainsaw with this configuration");
+        dontwarnIfNoReceiver = new JCheckBox(" Always start Chainsaw with this configuration ");
         panel.add(dontwarnIfNoReceiver, c);
 
         saveButton = new JButton(" Save configuration as... ");
@@ -287,7 +287,7 @@ class ReceiverConfigurationPanel extends JPanel {
         StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
         doc.setParagraphAttributes(0, doc.getLength(), center, false);
 
-        descriptionTextPane.setText("An example configuration file is available from the Welcome tab");
+        descriptionTextPane.setText(" An example configuration file is available from the Welcome tab ");
         descriptionTextPane.setEditable(false);
         descriptionTextPane.setOpaque(false);
         descriptionTextPane.setFont(getFont());
@@ -455,7 +455,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = 5;
         c.gridwidth=5;
-        c.insets = new Insets(5, 5, 0, 5);
+        c.insets = new Insets(15, 5, 0, 5);
         panel.add(new JLabel("<html> See PatternLayout or LogFilePatternReceiver JavaDoc for details </html>"), c);
         return panel;
     }


[29/50] [abbrv] logging-chainsaw git commit: Fix case sensitivity in configuration parsing Fix VFS tailing, particularly with sftp (the filesystem needed to be closed)

Posted by rg...@apache.org.
Fix case sensitivity in configuration parsing
Fix VFS tailing, particularly with sftp (the filesystem needed to be closed)


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/7329254a
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/7329254a
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/7329254a

Branch: refs/heads/master
Commit: 7329254a317c7a06232149904dc8a5c1a6ae2850
Parents: 8fcf375
Author: Scott Deboy <sd...@apache.org>
Authored: Wed Aug 17 07:13:43 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Wed Aug 17 07:13:43 2011 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/LogFilePatternLayoutBuilder.java    |  8 +++++---
 src/main/java/org/apache/log4j/chainsaw/LogUI.java     |  2 +-
 .../log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java  | 13 ++-----------
 3 files changed, 8 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7329254a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
index 7c8bc26..cd5a016 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
@@ -32,6 +32,7 @@ import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
+import org.apache.log4j.chainsaw.messages.MessageCenter;
 import org.apache.log4j.helpers.OptionConverter;
 import org.apache.log4j.pattern.ClassNamePatternConverter;
 import org.apache.log4j.pattern.DatePatternConverter;
@@ -255,14 +256,14 @@ public class LogFilePatternLayoutBuilder
               Node appenderChild = appenderChildren.item(j);
               if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
                 Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
-                if (fileNameNode != null && fileNameNode.getNodeValue().equals("file")) {
+                if (fileNameNode != null && fileNameNode.getNodeValue().toLowerCase().equals("file")) {
                   Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
                   if (fileValueNode != null) {
                     entry.put("file", fileValueNode.getNodeValue());
                   }
                 }
               }
-              if (appenderChild.getNodeName().equals("layout") && appenderChild.hasAttributes()) {
+              if (appenderChild.getNodeName().toLowerCase().equals("layout") && appenderChild.hasAttributes()) {
                 NamedNodeMap layoutAttributes = appenderChild.getAttributes();
                 Node layoutNode = layoutAttributes.getNamedItem("class");
                 if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
@@ -271,7 +272,7 @@ public class LogFilePatternLayoutBuilder
                     Node layoutChild = layoutChildren.item(k);
                     if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
                       Node layoutName = layoutChild.getAttributes().getNamedItem("name");
-                      if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equals("ConversionPattern")) {
+                      if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().toLowerCase().equals("conversionpattern")) {
                         Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
                         if (conversionValue != null) {
                           entry.put("conversion", conversionValue.getNodeValue());
@@ -289,6 +290,7 @@ public class LogFilePatternLayoutBuilder
     } finally {
       stream.close();
     }
+    MessageCenter.getInstance().getLogger().info("getXMLFileAppenderConfiguration for file: " + file + ", result: " + result);
     return result;
   }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7329254a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index e1a71f5..c62efe0 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1427,7 +1427,7 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
   }
 
   /**
-   * Displays a dialog which will provide options for selecting a configuratino
+   * Displays a dialog which will provide options for selecting a configuration
    */
   private void showReceiverConfigurationPanel() {
     SwingUtilities.invokeLater(

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/7329254a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
index fadc480..29dc146 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
@@ -314,9 +314,8 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
           }
           vfsReader = new VFSReader();
           new Thread(vfsReader).start();
-        }
+        } else if (oldURL != null && oldURL.indexOf("://") > -1) {
         //starts with protocol://
-        if (oldURL != null && oldURL.indexOf("://") > -1) {
             int index = oldURL.indexOf("://");
             String lastPart = oldURL.substring(index + "://".length());
             int passEndIndex = lastPart.indexOf("@");
@@ -403,6 +402,7 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
 
                         //fileobject was created above, release it and construct a new one
                         if (fileObject != null) {
+                            fileObject.getFileSystem().getFileSystemManager().closeFileSystem(fileObject.getFileSystem());
                             fileObject.close();
                             fileObject = null;
                         }
@@ -435,15 +435,6 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                                 rac.close();
                             }
                             try {
-                                //release file so it can be externally deleted/renamed if necessary
-                                fileObject.close();
-                                fileObject = null;
-                            }
-                            catch (IOException e)
-                            {
-                                getLogger().debug(getPath() + " - unable to close fileobject", e);
-                            }
-                            try {
                                 if (reader != null) {
                                     reader.close();
                                     reader = null;


[15/50] [abbrv] logging-chainsaw git commit: Added ability to define which columns are displayed by default when a new tab is created by clicking the 'Use selected columns as default visible columns' button on the logpanel preferences column selection sc

Posted by rg...@apache.org.
Added ability to define which columns are displayed by default when a new tab is created by clicking the 'Use selected columns as default visible columns' button on the logpanel preferences column selection screen
Also updated Welcome panel to make the keyboard shortcut table 100% width


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/345dc273
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/345dc273
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/345dc273

Branch: refs/heads/master
Commit: 345dc273ad479534315523a9af79db697ba2c869
Parents: 1d47127
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Nov 4 07:14:03 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Nov 4 07:14:03 2010 +0000

----------------------------------------------------------------------
 .../chainsaw/ApplicationPreferenceModel.java    | 23 ++++++++++++++++-
 .../org/apache/log4j/chainsaw/LogPanel.java     | 25 +++++++++++-------
 .../log4j/chainsaw/LogPanelPreferencePanel.java | 23 ++++++++++++++---
 .../org/apache/log4j/chainsaw/WelcomePanel.html | 27 +-------------------
 .../log4j/chainsaw/help/release-notes.html      |  4 +++
 5 files changed, 63 insertions(+), 39 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/345dc273/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
index 68e0795..721e634 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModel.java
@@ -19,6 +19,8 @@ package org.apache.log4j.chainsaw;
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Vector;
 
 import javax.swing.UIManager;
@@ -71,8 +73,10 @@ public class ApplicationPreferenceModel {
      */
     private boolean okToRemoveSecurityManager = false;
     private static final int CONFIGURATION_URL_ENTRY_COUNT = 10;
+    private List defaultColumnNames = new ArrayList();
+    private boolean defaultColumnsSet;
 
-    /**
+  /**
      * @param listener
      */
     public void addPropertyChangeListener(PropertyChangeListener listener) {
@@ -227,6 +231,9 @@ public class ApplicationPreferenceModel {
         setAlternatingBackgroundColor(alternatingBackground);
         setAlternatingForegroundColor(alternatingForeground);
       }
+      if (model.isDefaultColumnsSet()) {
+        setDefaultColumnNames(model.getDefaultColumnNames());
+      }
     }
 
     //use a lighter version of search color as the delta color
@@ -497,4 +504,18 @@ public class ApplicationPreferenceModel {
         this.okToRemoveSecurityManager = okToRemoveSecurityManager;
         firePropertyChange("okToRemoveSecurityManager", oldValue, this.okToRemoveSecurityManager);
 	}
+
+  public void setDefaultColumnNames(List defaultColumnNames) {
+    defaultColumnsSet = true;
+    this.defaultColumnNames.clear();
+    this.defaultColumnNames.addAll(defaultColumnNames);
+  }
+
+  public boolean isDefaultColumnsSet() {
+    return defaultColumnsSet;
+  }
+
+  public List getDefaultColumnNames() {
+    return defaultColumnNames;
+  }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/345dc273/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 2ff874d..edeec44 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -227,7 +227,8 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   private final JSplitPane nameTreeAndMainPanelSplit;
   private final LoggerNameTreePanel logTreePanel;
   private final LogPanelPreferenceModel preferenceModel = new LogPanelPreferenceModel();
-  private final LogPanelPreferencePanel logPanelPreferencesPanel = new LogPanelPreferencePanel(preferenceModel);
+  private ApplicationPreferenceModel applicationPreferenceModel;
+  private final LogPanelPreferencePanel logPanelPreferencesPanel;
   private final FilterModel filterModel = new FilterModel();
   private final RuleColorizer colorizer = new RuleColorizer();
   private final RuleMediator tableRuleMediator = new RuleMediator(false);
@@ -252,7 +253,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   private AutoFilterComboBox findCombo;
   private JScrollPane eventsPane;
   private int currentSearchMatchCount;
-  private ApplicationPreferenceModel applicationPreferenceModel;
   private Rule clearTableExpressionRule;
   private int lowerPanelDividerLocation;
   private EventContainer searchModel;
@@ -278,10 +278,11 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
    * @param identifier used to load and save settings
    */
   public LogPanel(final ChainsawStatusBar statusBar, final String identifier, int cyclicBufferSize,
-                  Map allColorizers, ApplicationPreferenceModel applicationPreferenceModel) {
+                  Map allColorizers, final ApplicationPreferenceModel applicationPreferenceModel) {
     this.identifier = identifier;
     this.statusBar = statusBar;
     this.applicationPreferenceModel = applicationPreferenceModel;
+    this.logPanelPreferencesPanel = new LogPanelPreferencePanel(preferenceModel, applicationPreferenceModel);
     logger.debug("creating logpanel for " + identifier);
 
     setLayout(new BorderLayout());
@@ -1034,9 +1035,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
           col.setHeaderValue(e.getKey());
 
           if (preferenceModel.addColumn(col)) {
-        	  table.addColumn(col);
-              searchTable.addColumn(col);
-        	  preferenceModel.setColumnVisible(e.getKey().toString(), true);
+            if (preferenceModel.isColumnVisible(col) || !applicationPreferenceModel.isDefaultColumnsSet() || applicationPreferenceModel.isDefaultColumnsSet() &&
+                applicationPreferenceModel.getDefaultColumnNames().contains(col.getHeaderValue())) {
+              table.addColumn(col);
+                searchTable.addColumn(col);
+          	  preferenceModel.setColumnVisible(e.getKey().toString(), true);
+            }
           }
         		}
         	});
@@ -3138,9 +3142,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     for (Iterator iter = sortedColumnList.iterator(); iter.hasNext();) {
       TableColumn element = (TableColumn) iter.next();
       if (preferenceModel.addColumn(element)) {
-          table.addColumn(element);
-          searchTable.addColumn(element);
-    	  preferenceModel.setColumnVisible(element.getHeaderValue().toString(), true);
+          if (!applicationPreferenceModel.isDefaultColumnsSet() || applicationPreferenceModel.isDefaultColumnsSet() &&
+              applicationPreferenceModel.getDefaultColumnNames().contains(element.getHeaderValue())) {
+            table.addColumn(element);
+            searchTable.addColumn(element);
+            preferenceModel.setColumnVisible(element.getHeaderValue().toString(), true);
+          }
       }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/345dc273/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
index 6967785..5cd7550 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
@@ -25,6 +25,7 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.Iterator;
 import java.util.List;
@@ -33,6 +34,7 @@ import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
+import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JEditorPane;
 import javax.swing.JFrame;
@@ -64,12 +66,14 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
   private final LogPanelPreferenceModel preferenceModel;
   private final ModifiableListModel columnListModel = new ModifiableListModel();
   private static final Logger logger = LogManager.getLogger(LogPanelPreferencePanel.class);
+  private ApplicationPreferenceModel appPreferenceModel;
 
   //~ Constructors ============================================================
 
-  public LogPanelPreferencePanel(LogPanelPreferenceModel model)
+  public LogPanelPreferencePanel(LogPanelPreferenceModel model, ApplicationPreferenceModel appModel)
   {
     preferenceModel = model;
+    appPreferenceModel = appModel;
     initComponents();
 
     getOkButton().addActionListener(new ActionListener()
@@ -100,7 +104,8 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
   {
     JFrame f = new JFrame("Preferences Panel Test Bed");
     LogPanelPreferenceModel model = new LogPanelPreferenceModel();
-    LogPanelPreferencePanel panel = new LogPanelPreferencePanel(model);
+    ApplicationPreferenceModel appModel = new ApplicationPreferenceModel();
+    LogPanelPreferencePanel panel = new LogPanelPreferencePanel(model, appModel);
     f.getContentPane().add(panel);
 
     model.addPropertyChangeListener(new PropertyChangeListener()
@@ -214,9 +219,21 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
               }
           }
         });
+      JButton setAsDefaultsButton = new JButton("Use selected columns as default visible columns");
+      setAsDefaultsButton.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent actionEvent) {
+          List selectedColumns = new ArrayList();
+          for (int i = 0;i<columnListModel.getSize();i++) {
+            if (preferenceModel.isColumnVisible((TableColumn) columnListModel.get(i))) {
+              selectedColumns.add(((TableColumn)columnListModel.get(i)).getHeaderValue());
+            }
+          }
+          appPreferenceModel.setDefaultColumnNames(selectedColumns);
+        }
+      });
       columnList.setCellRenderer(cellRenderer);
       columnBox.add(new JScrollPane(columnList));
-
+      columnBox.add(setAsDefaultsButton);
       add(columnBox);
       add(Box.createVerticalGlue());
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/345dc273/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html b/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
index eafcb52..5ec4933 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
@@ -41,107 +41,82 @@
 <tr><td><a href="#FilteringColouring">Filtering and Colouring</a></td></tr>
 </table>
 -->
-<p><table border="0" cellspacing="2" cellpadding="2" >
+<p><table border="0" cellspacing="2" cellpadding="2" width=100%>
 <tr><td colspan="6" class="TableTitle" bgcolor="#000089"><font color="white">Hot Keys</font></td></tr>
 <tr valign="top">
 	<td nowrap class="HotKey">CMD-LEFT</td>
-	<td width="50" align="center">-</td>
 	<td>Activate a tab to the left</td>
     <td nowrap class="HotKey">CTRL-RIGHT</td>
-    <td width="50" align="center">-</td>
     <td>Activate a tab to the right</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">F3</td>
-    <td width="50" align="center">-</td>
     <td>Find Next</td>
     <td nowrap class="HotKey">SHIFT-F3</td>
-    <td width="50" align="center">-</td>
     <td>Find previous</td>
 </tr>
 <tr valign="top">
     <td nowrap class="HotKey">CMD-A</td>
-    <td width="50" align="center">-</td>
     <td>Scroll to top</td>
     <td nowrap class="HotKey">CMD-B</td>
-    <td width="50" align="center">-</td>
     <td>Scroll to bottom</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">CMD-F2 or double-click on a row</td>
-    <td width="50" align="center">-</td>
     <td>Define a 'marker' (add a note to a row)</td>
     <td nowrap class="HotKey">CMD-SHIFT-F2</td>
-    <td width="50" align="center">-</td>
     <td>Clear all markers</td>
 </tr>
 <tr valign="top">
     <td nowrap class="HotKey">F2</td>
-    <td width="50" align="center">-</td>
     <td>Find next marker</td>
     <td nowrap class="HotKey">SHIFT-F2</td>
-    <td width="50" align="center">-</td>
     <td>Find previous marker</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">CMD-F</td>
-    <td width="50" align="center">-</td>
     <td>Set focus in 'find' field</td>
     <td nowrap class="HotKey">CMD-R</td>
-    <td width="50" align="center">-</td>
     <td>Set focus in 'refine focus' field</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">CMD--SHIFT-F</td>
-    <td width="50" align="center">-</td>
     <td>Clear 'find' field</td>
     <td nowrap class="HotKey">CMD-SHIFT-R</td>
-    <td width="50" align="center">-</td>
     <td>Clear 'refine focus' field</td>
 </tr>
 <tr valign="top" >
 	<td nowrap class="HotKey">CMD-S</td>
-	<td width="50" align="center">-</td>
 	<td>Save displayed events</td>
     <td nowrap class="HotKey">CMD-O</td>
-    <td width="50" align="center">-</td>
     <td>Load file of XML events</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">CMD-BACKSPACE</td>
-    <td width="50" align="center">-</td>
     <td>Purges current panels events</td>
 	<td nowrap class="HotKey">F12</td>
-	<td width="50" align="center">-</td>
 	<td>Pause display</td>
 </tr>
 <tr valign="top">
 	<td nowrap class="HotKey">CMD-D</td>
-	<td width="50" align="center">-</td>
 	<td>Show/Hide the Detail pane</td>
 	<td nowrap class="HotKey">CMD-T</td>
-	<td width="50" align="center">-</td>
 	<td>Show/Hide the Logger Tree pane</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">F1</td>
-    <td width="50" align="center">-</td>
     <td>Hide/Show Welcome Panel/Help page</td>
     <td nowrap class="HotKey">F6</td>
-    <td width="50" align="center">-</td>
     <td>Show Receivers Dialog</td>
 </tr>
 <tr valign="top">
     <td nowrap class="HotKey">CMD-N</td>
-    <td width="50" align="center">-</td>
     <td>Go to next colored row</td>
     <td nowrap class="HotKey">CMD-P</td>
-    <td width="50" align="center">-</td>
     <td>Go to previous colored row</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
     <td nowrap class="HotKey">CMD-G</td>
-    <td width="50" align="center">-</td>
     <td>Go to line</td>
 	<td></td>
 	<td></td>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/345dc273/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index ed61f2c..3068296 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,6 +10,10 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>4 Nov 2010</h2>
+<ul>
+<li>Added ability to define which columns are displayed by default when a new tab is created by clicking the 'Use selected columns as default visible columns' button on the logpanel preferences column selection screen</li>
+</ul>
 <h2>22 Oct 2010</h2>
 <ul>
 <li>Updated keyboard shortcuts to use system-specific option (Apple command key, Windows control key)</li>


[02/50] [abbrv] logging-chainsaw git commit: Minor button layout updates, changes to support third party look & feels (copy jars to $USERHOME/.chainsaw/plugins and update fully-qualified-class-name in $USERH

Posted by rg...@apache.org.
Minor button layout updates, changes to support third party look & feels (copy jars to $USERHOME/.chainsaw/plugins and update   <lookAndFeelClassName>fully-qualified-class-name</lookAndFeelClassName> in $USERHOME/.chainsaw/chainsaw.settings.xml
Also updated the TableCellRenderer to use a basic JLabel renderer if highlighted search, wrap and time delta rendering aren't enabled (still supports border display & color rules)



Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/66805db7
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/66805db7
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/66805db7

Branch: refs/heads/master
Commit: 66805db79b459e159c01375645cc481bd6d61c63
Parents: f543275
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Oct 22 07:36:35 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Oct 22 07:36:35 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/AbstractPreferencePanel.java |   2 +-
 .../java/org/apache/log4j/chainsaw/LogUI.java   |  23 ++-
 .../chainsaw/ReceiverConfigurationPanel.java    |   1 +
 .../log4j/chainsaw/TableColorizingRenderer.java | 197 +++++++++++++++----
 .../plugins/PluginClassLoaderFactory.java       |  14 +-
 5 files changed, 181 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/66805db7/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java b/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
index f7f1226..50adbc6 100644
--- a/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
@@ -112,7 +112,7 @@ public abstract class AbstractPreferencePanel extends JPanel
     Box buttonBox = Box.createHorizontalBox();
     buttonBox.add(Box.createHorizontalGlue());
     buttonBox.add(okButton);
-    buttonBox.add(Box.createHorizontalStrut(5));
+    buttonBox.add(Box.createHorizontalStrut(10));
     buttonBox.add(cancelButton);
   
     add(buttonBox, BorderLayout.SOUTH);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/66805db7/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 20c79f7..30a0abf 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -282,11 +282,11 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
         model.setBypassConfigurationURL(configurationURLAppArg);
     }
 
-    applyLookAndFeel(model.getLookAndFeelClassName());
     EventQueue.invokeLater(new Runnable()
     {
         public void run()
         {
+            loadLookAndFeelUsingPluginClassLoader(model.getLookAndFeelClassName());
             createChainsawGUI(model, null);
         }
     });
@@ -484,7 +484,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     SettingsManager.getInstance().configure(new ApplicationPreferenceModelSaver(model));
 
     cyclicBufferSize = model.getCyclicBufferSize();
-    applyLookAndFeel(model.getLookAndFeelClassName());
 
     handler = new ChainsawAppenderHandler(appender);
     handler.addEventBatchListener(new NewTabEventBatchReceiver());
@@ -501,12 +500,11 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
 
     SettingsManager.getInstance().configure(new ApplicationPreferenceModelSaver(model));
 
-    applyLookAndFeel(model.getLookAndFeelClassName());
-
     EventQueue.invokeLater(new Runnable()
     {
         public void run()
         {
+            loadLookAndFeelUsingPluginClassLoader(model.getLookAndFeelClassName());
             createChainsawGUI(model, null);
             getApplicationPreferenceModel().apply(model);
             activateViewer();
@@ -1853,6 +1851,7 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
       UIManager.setLookAndFeel(lookAndFeelClassName);
 
     } catch (Exception e) {
+      e.printStackTrace();
     }
   }
 
@@ -2148,6 +2147,22 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
         ensureChainsawAppenderHandlerAdded();
     }
 
+  private static void loadLookAndFeelUsingPluginClassLoader(String lookAndFeelClassName) {
+      ClassLoader classLoader = PluginClassLoaderFactory.getInstance().getClassLoader();
+      ClassLoader previousTCCL = Thread.currentThread().getContextClassLoader();
+          try {
+            // we temporarily swap the TCCL so that plugins can find resources
+            Thread.currentThread().setContextClassLoader(classLoader);
+            UIManager.setLookAndFeel(lookAndFeelClassName);
+            UIManager.getLookAndFeelDefaults().put("ClassLoader", classLoader);
+          } catch (Exception e) {
+            e.printStackTrace();
+          } finally{
+              // now switch it back...
+              Thread.currentThread().setContextClassLoader(previousTCCL);
+          }
+  }
+
     /**
      * Makes sure that the LoggerRepository has the ChainsawAppenderHandler
      * added to the root logger so Chainsaw can receive all the events.  

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/66805db7/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index 50c5934..fbd4c22 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -214,6 +214,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.fill = GridBagConstraints.HORIZONTAL;
         c.gridx = 1;
         c.gridy = 0;
+        c.insets = new Insets(0, 0, 0, 10);
         okButton = new JButton(" OK ");
         panel.add(okButton, c);
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/66805db7/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index 209204d..33d74d1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -188,8 +188,16 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     int colIndex = tableColumn.getModelIndex() + 1;
 
     //no event, use default renderer
-    if (loggingEventWrapper == null) {
-        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
+
+    JLabel basicComponent = null;
+    boolean basic = (!wrap && !highlightSearchMatchText && !logPanelPreferenceModel.isShowMillisDeltaAsGap());
+    if (basic || loggingEventWrapper == null) {
+      Component rendererComponent = super.getTableCellRendererComponent(table, value, false, false, row, col);
+      if (!(rendererComponent instanceof JLabel) || loggingEventWrapper == null) {
+        return rendererComponent;
+      }
+      basicComponent = (JLabel)rendererComponent;
+      setBasicComponentBorder(basicComponent, isSelected, table, col);
     }
     long delta = 0;
     if (row > 0) {
@@ -203,6 +211,9 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     switch (colIndex) {
     case ChainsawColumns.INDEX_THROWABLE_COL_NAME:
       if (value instanceof String[] && ((String[])value).length > 0){
+        if (basic) {
+          basicComponent.setText(((String[])value)[0]);
+        } else {
           Style tabStyle = singleLineTextPane.getLogicalStyle();
           StyleConstants.setTabSet(tabStyle, tabs);
           //set the 1st tab at position 3
@@ -215,11 +226,20 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
           } else {
               singleLineTextPane.setText(((String[])value)[0]);
           }
+        }
       } else {
-        singleLineTextPane.setText("");
+        if (basic) {
+          basicComponent.setText("");
+        } else {
+          singleLineTextPane.setText("");
+        }
+      }
+      if (basic) {
+        component = basicComponent;
+      } else {
+        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
+        component = generalPanel;
       }
-      layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
-      component = generalPanel;
       break;
     case ChainsawColumns.INDEX_LOGGER_COL_NAME:
       String logger = value.toString();
@@ -231,49 +251,88 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
           break;
         }
       }
+      if (basic) {
+        basicComponent.setText(logger.substring(startPos + 1));
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(logger.substring(startPos + 1));
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LOGGER_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
       break;
     case ChainsawColumns.INDEX_ID_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.PROP_FIELD + "LOG4JID"), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.CLASS_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_FILE_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.FILE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_LINE_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LINE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_NDC_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.NDC_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_THREAD_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.THREAD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_TIMESTAMP_COL_NAME:
         //timestamp matches contain the millis..not the display text..just highlight if we have a match for the timestamp field
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         Set timestampMatches = (Set)matches.get(LoggingEventFieldResolver.TIMESTAMP_FIELD);
         if (timestampMatches != null && timestampMatches.size() > 0) {
             singleLineTextPane.setText(value.toString());
@@ -283,16 +342,26 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
+      if (basic) {
+        basicComponent.setText(value.toString());
+        component = basicComponent;
+      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.METHOD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     case ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME:
     case ChainsawColumns.INDEX_MESSAGE_COL_NAME:
         String thisString = value.toString().trim();
+      if (basic) {
+        basicComponent.setText(thisString);
+        component = basicComponent;
+      } else {
         JTextPane textPane = wrap ? multiLineTextPane : singleLineTextPane;
         JComponent textPaneContainer = wrap ? multiLinePanel : generalPanel;
         textPane.setText(thisString);
@@ -313,23 +382,6 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
         textPaneContainer.add(textPane, BorderLayout.SOUTH);
 
-        if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
-          if (col == 0) {
-            textPane.setBorder(getLeftBorder(isSelected, delta));
-          } else if (col == table.getColumnCount() - 1) {
-            textPane.setBorder(getRightBorder(isSelected, delta));
-          } else {
-            textPane.setBorder(getMiddleBorder(isSelected, delta));
-          }
-        } else {
-            if (col == 0) {
-              textPane.setBorder(getLeftBorder(isSelected, 0));
-            } else if (col == table.getColumnCount() - 1) {
-              textPane.setBorder(getRightBorder(isSelected, 0));
-            } else {
-              textPane.setBorder(getMiddleBorder(isSelected, 0));
-            }
-        }
         int currentMarkerHeight = loggingEventWrapper.getMarkerHeight();
         int currentMsgHeight = loggingEventWrapper.getMsgHeight();
         int newRowHeight = ChainsawConstants.DEFAULT_ROW_HEIGHT;
@@ -373,28 +425,54 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
 
         component = textPaneContainer;
+        setComponentBorder(component, isSelected, table, col, delta);
+      }
         break;
     case ChainsawColumns.INDEX_LEVEL_COL_NAME:
       if (levelUseIcons) {
-        levelTextPane.setText("");
-        levelTextPane.insertIcon((Icon) iconMap.get(value.toString()));
-        if (!toolTipsVisible) {
-          levelTextPane.setToolTipText(value.toString());
+        if (basic) {
+          basicComponent.setText("");
+          if (!toolTipsVisible) {
+            basicComponent.setToolTipText(value.toString());
+          }
+        } else {
+          levelTextPane.setText("");
+          levelTextPane.insertIcon((Icon) iconMap.get(value.toString()));
+          if (!toolTipsVisible) {
+            levelTextPane.setToolTipText(value.toString());
+          }
         }
       } else {
-        levelTextPane.setText(value.toString());
-        setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LEVEL_FIELD), (StyledDocument) levelTextPane.getDocument());
-        if (!toolTipsVisible) {
-            levelTextPane.setToolTipText(null);
+        if (basic) {
+          basicComponent.setText(value.toString());
+          if (!toolTipsVisible) {
+              basicComponent.setToolTipText(null);
+          }
+        } else {
+          levelTextPane.setText(value.toString());
+          setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LEVEL_FIELD), (StyledDocument) levelTextPane.getDocument());
+          if (!toolTipsVisible) {
+              levelTextPane.setToolTipText(null);
+          }
         }
       }
       if (toolTipsVisible) {
+        if (basic) {
+          basicComponent.setToolTipText(label.getToolTipText());
+        } else {
           levelTextPane.setToolTipText(label.getToolTipText());
+        }
+      }
+      if (basic) {
+        basicComponent.setForeground(label.getForeground());
+        basicComponent.setBackground(label.getBackground());
+        component = basicComponent;
+      } else {
+        levelTextPane.setForeground(label.getForeground());
+        levelTextPane.setBackground(label.getBackground());
+        layoutRenderingPanel(levelPanel, levelTextPane, delta, isSelected, width, col, table);
+        component = levelPanel;
       }
-      levelTextPane.setForeground(label.getForeground());
-      levelTextPane.setBackground(label.getBackground());
-      layoutRenderingPanel(levelPanel, levelTextPane, delta, isSelected, width, col, table);
-      component = levelPanel;
       break;
 
     //remaining entries are properties
@@ -413,13 +491,26 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         if (thisProp != null) {
             String propKey = LoggingEventFieldResolver.PROP_FIELD + thisProp.toUpperCase();
             Set propKeyMatches = (Set)matches.get(propKey);
-            singleLineTextPane.setText(loggingEventWrapper.getLoggingEvent().getProperty(thisProp));
+            String propertyValue = loggingEventWrapper.getLoggingEvent().getProperty(thisProp);
+          if (basic) {
+            basicComponent.setText(propertyValue);
+          } else {
+            singleLineTextPane.setText(propertyValue);
             setHighlightAttributesInternal(propKeyMatches, (StyledDocument) singleLineTextPane.getDocument());
+          }
         } else {
+          if (basic) {
+            basicComponent.setText("");
+          } else {
             singleLineTextPane.setText("");
+          }
         }
+      if (basic) {
+        component = basicComponent;
+      } else {
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
+      }
         break;
     }
 
@@ -454,16 +545,40 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     component.setForeground(foreground);
 
     //update the background & foreground of the jtextpane using styles
-    if (multiLineTextPane != null)
-    {
-        updateColors(multiLineTextPane, background, foreground);
+    if (!basic) {
+      if (multiLineTextPane != null)
+      {
+          updateColors(multiLineTextPane, background, foreground);
+      }
+      updateColors(levelTextPane, background, foreground);
+      updateColors(singleLineTextPane, background, foreground);
     }
-    updateColors(levelTextPane, background, foreground);
-    updateColors(singleLineTextPane, background, foreground);
-
     return component;
   }
 
+  private void setBasicComponentBorder(JComponent component, boolean isSelected, JTable table, int col) {
+    setComponentBorder(component, isSelected, table, col, 0);
+  }
+
+  private void setComponentBorder(JComponent component, boolean isSelected, JTable table, int col, long delta) {
+    if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+      if (col == 0) {
+        component.setBorder(getLeftBorder(isSelected, delta));
+      } else if (col == table.getColumnCount() - 1) {
+        component.setBorder(getRightBorder(isSelected, delta));
+      } else {
+        component.setBorder(getMiddleBorder(isSelected, delta));
+      }
+    } else {
+        if (col == 0) {
+          component.setBorder(getLeftBorder(isSelected, 0));
+        } else if (col == table.getColumnCount() - 1) {
+          component.setBorder(getRightBorder(isSelected, 0));
+        } else {
+          component.setBorder(getMiddleBorder(isSelected, 0));
+        }
+      }
+  }
     private void layoutRenderingPanel(JComponent container, JComponent bottomComponent, long delta, boolean isSelected,
                                       int width, int col, JTable table) {
         container.removeAll();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/66805db7/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java b/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
index 813e3a2..2ef492e 100644
--- a/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
+++ b/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
@@ -23,8 +23,6 @@ import java.net.URLClassLoader;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
 
 /**
@@ -40,13 +38,9 @@ import org.apache.log4j.chainsaw.prefs.SettingsManager;
  */
 public class PluginClassLoaderFactory {
 	private final ClassLoader pluginClassLoader;
-	private static final Logger logger = LogManager.getLogger(PluginClassLoaderFactory.class);
-    
+
     private static final PluginClassLoaderFactory instance = new PluginClassLoaderFactory();
     
-	/**
-	 * @param urls
-	 */
 	private PluginClassLoaderFactory() {
         this.pluginClassLoader= PluginClassLoaderFactory.create(new File(SettingsManager.getInstance().getSettingsDirectory() + File.separator + "plugins"));
 
@@ -73,7 +67,7 @@ public class PluginClassLoaderFactory {
      */
     private static final ClassLoader create(File pluginDirectory) {
         if(pluginDirectory == null || !pluginDirectory.exists() || !pluginDirectory.canRead()) {
-         logger.error("pluginDirectory cannot be null, and it must exist and must be readable, using the normal Classloader");
+         System.err.println("pluginDirectory cannot be null, and it must exist and must be readable, using the normal Classloader");
          return PluginClassLoaderFactory.class.getClassLoader();
         }
         
@@ -97,10 +91,10 @@ public class PluginClassLoaderFactory {
 				File file = new File(pluginDirectory, name);
 				try {
 					list.add(file.toURI().toURL());
-					logger.info("Added " + file.getAbsolutePath()
+					System.out.println("Added " + file.getAbsolutePath()
 							+ " to Plugin class loader list");
 				} catch (Exception e) {
-					logger.error("Failed to retrieve the URL for file: "
+					System.err.println("Failed to retrieve the URL for file: "
 							+ file.getAbsolutePath());
 					throw new RuntimeException(e.getMessage());
 				}


[37/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DBReceiverJob.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DBReceiverJob.java b/src/main/java/org/apache/log4j/db/DBReceiverJob.java
new file mode 100644
index 0000000..1e29663
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DBReceiverJob.java
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.scheduler.Job;
+import org.apache.log4j.spi.ComponentBase;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * Actual retrieval of data is made by the instance of DBReceiverJob associated
+ * with DBReceiver.
+ * 
+ * @author Ceki G&uuml;lc&uuml;
+ */
+class DBReceiverJob extends ComponentBase implements Job {
+
+  String sqlException = "SELECT trace_line FROM logging_event_exception where event_id=? ORDER by i ASC";
+  String sqlProperties = "SELECT mapped_key, mapped_value FROM logging_event_property WHERE event_id=?";
+  String sqlSelect = 
+    "SELECT " +
+    "sequence_number, timestamp, rendered_message, logger_name, " +
+    "level_string, ndc, thread_name, reference_flag, " +
+    "caller_filename, caller_class, caller_method, caller_line, " +
+    "event_id " +
+    "FROM logging_event " +
+    "WHERE event_id > ?  ORDER BY event_id ASC";
+
+
+  long lastId = Short.MIN_VALUE;
+
+  DBReceiver parentDBReceiver;
+
+  DBReceiverJob(DBReceiver parent) {
+    parentDBReceiver = parent;
+  }
+
+  public void execute() {
+    getLogger().debug("DBReceiverJob.execute() called");
+
+    Connection connection = null;
+
+    try {
+      connection = parentDBReceiver.connectionSource.getConnection();
+      PreparedStatement statement = connection.prepareStatement(sqlSelect);
+      statement.setLong(1, lastId);
+      ResultSet rs = statement.executeQuery();
+      //rs.beforeFirst();
+
+      while (rs.next()) {
+	    Logger logger = null;
+	    long timeStamp = 0L;
+	    String level = null;
+	    String threadName = null;
+	    Object message = null;
+	    String ndc = null;
+	    String className = null;
+	    String methodName = null;
+	    String fileName = null;
+	    String lineNumber = null;
+	    Hashtable properties = new Hashtable();
+	
+
+        //event.setSequenceNumber(rs.getLong(1));
+        timeStamp = rs.getLong(2);
+        message = rs.getString(3);
+		logger = Logger.getLogger(rs.getString(4));
+        level = rs.getString(5);
+		Level levelImpl = Level.toLevel(level.trim());
+
+        ndc = rs.getString(6);
+        threadName = rs.getString(7);
+
+        short mask = rs.getShort(8);
+
+        fileName = rs.getString(9);
+        className = rs.getString(10);
+        methodName = rs.getString(11);
+        lineNumber = rs.getString(12).trim();
+
+		LocationInfo locationInfo = null;
+        if (fileName.equals(LocationInfo.NA)) {
+          locationInfo = LocationInfo.NA_LOCATION_INFO;
+        } else {
+          locationInfo = new LocationInfo(fileName, className,
+              methodName, lineNumber);
+        }
+
+        long id = rs.getLong(13);
+        //LogLog.info("Received event with id=" + id);
+        lastId = id;
+
+		ThrowableInformation throwableInfo = null;
+        if ((mask & DBHelper.EXCEPTION_EXISTS) != 0) {
+          throwableInfo = getException(connection, id);
+        }
+
+	    LoggingEvent event = new LoggingEvent(logger.getName(),
+	            logger, timeStamp, levelImpl, message,
+	            threadName,
+	            throwableInfo,
+	            ndc,
+	            locationInfo,
+	            properties);
+
+
+        // Scott asked for this info to be
+        event.setProperty("log4jid", Long.toString(id));
+
+        if ((mask & DBHelper.PROPERTIES_EXIST) != 0) {
+          getProperties(connection, id, event);
+        }
+
+
+
+
+        if (!parentDBReceiver.isPaused()) {
+          parentDBReceiver.doPost(event);
+        }
+      } // while
+      statement.close();
+      statement = null;
+    } catch (SQLException sqle) {
+      getLogger().error("Problem receiving events", sqle);
+    } finally {
+      closeConnection(connection);
+    }
+  }
+
+  void closeConnection(Connection connection) {
+    if (connection != null) {
+      try {
+        //LogLog.warn("closing the connection. ", new Exception("x"));
+        connection.close();
+      } catch (SQLException sqle) {
+        // nothing we can do here
+      }
+    }
+  }
+
+  /**
+   * Retrieve the event properties from the logging_event_property table.
+   * 
+   * @param connection
+   * @param id
+   * @param event
+   * @throws SQLException
+   */
+  void getProperties(Connection connection, long id, LoggingEvent event)
+      throws SQLException {
+
+    PreparedStatement statement = connection.prepareStatement(sqlProperties);
+    try {
+      statement.setLong(1, id);
+      ResultSet rs = statement.executeQuery();
+
+      while (rs.next()) {
+        String key = rs.getString(1);
+        String value = rs.getString(2);
+        event.setProperty(key, value);
+      }
+    } finally {
+      statement.close();
+    }
+  }
+
+  /**
+   * Retrieve the exception string representation from the
+   * logging_event_exception table.
+   * 
+   * @param connection
+   * @param id
+   * @throws SQLException
+   */
+  ThrowableInformation getException(Connection connection, long id)
+      throws SQLException {
+
+    PreparedStatement statement = null;
+
+    try {
+      statement = connection.prepareStatement(sqlException);
+      statement.setLong(1, id);
+      ResultSet rs = statement.executeQuery();
+
+      Vector v = new Vector();
+
+      while (rs.next()) {
+        //int i = rs.getShort(1);
+        v.add(rs.getString(1));
+      }
+
+      int len = v.size();
+      String[] strRep = new String[len];
+      for (int i = 0; i < len; i++) {
+        strRep[i] = (String) v.get(i);
+      }
+      // we've filled strRep, we now attach it to the event
+      return new ThrowableInformation(strRep);
+    } finally {
+      if (statement != null) {
+        statement.close();
+      }
+    }
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java b/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java
new file mode 100644
index 0000000..d5975ee
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DataSourceConnectionSource.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+
+/**
+ *  The DataSourceConnectionSource is an implementation of {@link ConnectionSource}
+ *  that obtains the Connection in the recommended JDBC manner based on
+ *  a {@link javax.sql.DataSource DataSource}.
+ *  <p>
+ *
+ *  @author Ray DeCampo
+ *  @author Ceki G&uuml;lc&uuml;
+ */
+public class DataSourceConnectionSource extends ConnectionSourceSkeleton
+        implements UnrecognizedElementHandler {
+
+  private DataSource dataSource;
+
+  
+  public void activateOptions() {
+    //LogLog.debug("**********DataSourceConnectionSource.activateOptions called");
+    if (dataSource == null) {
+      getLogger().warn("WARNING: No data source specified");
+    } else {
+      Connection connection = null;
+      try {
+        connection = getConnection();
+      } catch(SQLException se) {
+        getLogger().warn("Could not get a connection to discover the dialect to use.", se);
+      }
+      if(connection != null) {
+        discoverConnnectionProperties();
+      } 
+      if(!supportsGetGeneratedKeys() && getSQLDialectCode() == ConnectionSource.UNKNOWN_DIALECT) {
+        getLogger().warn("Connection does not support GetGeneratedKey method and could not discover the dialect.");
+      }
+    }
+  }
+
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection() throws SQLException {
+    if (dataSource == null) {
+      getLogger().error("WARNING: No data source specified");
+      return null;
+    }
+
+    if (getUser() == null) {
+      return dataSource.getConnection();
+    } else {
+      return dataSource.getConnection(getUser(), getPassword());
+    }
+  }
+
+  public DataSource getDataSource() {
+    return dataSource;
+  }
+
+  public void setDataSource(DataSource dataSource) {
+    this.dataSource = dataSource;
+  }
+
+    /**
+     * @{inheritDoc}
+     */
+  public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+        if ("dataSource".equals(element.getNodeName())) {
+            Object instance =
+                    DOMConfigurator.parseElement(element, props, DataSource.class);
+            if (instance instanceof DataSource) {
+               setDataSource((DataSource) instance);
+            }
+            return true;
+        }
+        return false;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java b/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java
new file mode 100644
index 0000000..9bfdf65
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DriverManagerConnectionSource.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+
+/**
+ *  The DriverManagerConnectionSource is an implementation of {@link ConnectionSource}
+ *  that obtains the Connection in the traditional JDBC manner based on the
+ *  connection URL.
+ *  <p>
+ *  Note that this class will establish a new Connection for each call to
+ *  {@link #getConnection()}.  It is recommended that you either use a JDBC
+ *  driver that natively supported Connection pooling or that you create
+ *  your own implementation of {@link ConnectionSource} that taps into whatever
+ *  pooling mechanism you are already using.  (If you have access to a JNDI
+ *  implementation that supports {@link javax.sql.DataSource}s, e.g. within
+ *  a J2EE application server, see {@link JNDIConnectionSource}).  See
+ *  <a href="#dbcp">below</a> for a configuration example that uses the
+ *  <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ *  package from Apache.
+ *  <p>
+ *  Sample configuration:<br>
+ *  <pre>
+ *     &lt;connectionSource class="org.apache.log4j.jdbc.DriverManagerConnectionSource"&gt;
+ *        &lt;param name="driver" value="com.mysql.jdbc.Driver" /&gt;
+ *        &lt;param name="url" value="jdbc:mysql://localhost:3306/mydb" /&gt;
+ *        &lt;param name="username" value="myUser" /&gt;
+ *        &lt;param name="password" value="myPassword" /&gt;
+ *     &lt;/connectionSource&gt;
+ *  </pre>
+ *  <p>
+ *  <a name="dbcp">If</a> you do not have another connection pooling mechanism
+ *  built into your application, you can use  the
+ *  <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ *  package from Apache:<br>
+ *  <pre>
+ *     &lt;connectionSource class="org.apache.log4j.jdbc.DriverManagerConnectionSource"&gt;
+ *        &lt;param name="driver" value="org.apache.commons.dbcp.PoolingDriver" /&gt;
+ *        &lt;param name="url" value="jdbc:apache:commons:dbcp:/myPoolingDriver" /&gt;
+ *     &lt;/connectionSource&gt;
+ *  </pre>
+ *  Then the configuration information for the commons-dbcp package goes into
+ *  the file myPoolingDriver.jocl and is placed in the classpath.  See the
+ *  <a href="http://jakarta.apache.org/commons/dbcp/index.html">commons-dbcp</a>
+ *  documentation for details.
+ *
+ *  @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
+ */
+public class DriverManagerConnectionSource extends ConnectionSourceSkeleton {
+  private String driverClass = null;
+  private String url = null;
+
+  public void activateOptions() {
+    try {
+      if (driverClass != null) {
+        Class.forName(driverClass);
+        discoverConnnectionProperties();
+      } else {
+        getLogger().error(
+          "WARNING: No JDBC driver specified for log4j DriverManagerConnectionSource.");
+      }
+    } catch (final ClassNotFoundException cnfe) {
+     getLogger().error("Could not load JDBC driver class: " + driverClass, cnfe);
+    }
+  }
+
+
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection() throws SQLException {
+    if (getUser() == null) {
+      return DriverManager.getConnection(url);
+    } else {
+      return DriverManager.getConnection(url, getUser(), getPassword());
+    }
+  }
+
+
+  /**
+   * Returns the url.
+   * @return String
+   */
+  public String getUrl() {
+    return url;
+  }
+
+
+  /**
+   * Sets the url.
+   * @param url The url to set
+   */
+  public void setUrl(String url) {
+    this.url = url;
+  }
+
+
+  /**
+   * Returns the name of the driver class.
+   * @return String
+   */
+  public String getDriverClass() {
+    return driverClass;
+  }
+
+
+  /**
+   * Sets the driver class.
+   * @param driverClass The driver class to set
+   */
+  public void setDriverClass(String driverClass) {
+    this.driverClass = driverClass;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java b/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java
new file mode 100644
index 0000000..7073738
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/JNDIConnectionSource.java
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+// PortableRemoteObject was introduced in JDK 1.3. We won't use it.
+// import javax.rmi.PortableRemoteObject;
+import javax.sql.DataSource;
+
+
+/**
+ *  The <id>JNDIConnectionSource</id> is an implementation of
+ *  {@link ConnectionSource} that obtains a {@link javax.sql.DataSource} from a
+ *  JNDI provider and uses it to obtain a {@link java.sql.Connection}.  It is
+ *  primarily designed to be used inside of J2EE application servers or
+ *  application server clients, assuming the application server supports remote
+ *  access of {@link javax.sql.DataSource}s.  In this way one can take
+ *  advantage of  connection pooling and whatever other goodies the application
+ *  server provides.
+ *  <p>
+ *  Sample configuration:<br>
+ *  <pre>
+ *    &lt;connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"&gt;
+ *        &lt;param name="jndiLocation" value="jdbc/MySQLDS" /&gt;
+ *    &lt;/connectionSource&gt;
+ *  </pre>
+ *  <p>
+ *  Sample configuration (with username and password):<br>
+ *  <pre>
+ *    &lt;connectionSource class="org.apache.log4j.jdbc.JNDIConnectionSource"&gt;
+ *        &lt;param name="jndiLocation" value="jdbc/MySQLDS" /&gt;
+ *        &lt;param name="username" value="myUser" /&gt;
+ *        &lt;param name="password" value="myPassword" /&gt;
+ *    &lt;/connectionSource&gt;
+ *  </pre>
+ *  <p>
+ *  Note that this class will obtain an {@link javax.naming.InitialContext}
+ *  using the no-argument constructor.  This will usually work when executing
+ *  within a J2EE environment.  When outside the J2EE environment, make sure
+ *  that you provide a jndi.properties file as described by your JNDI
+ *  provider's documentation.
+ *
+ *  @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
+ */
+public class JNDIConnectionSource
+       extends ConnectionSourceSkeleton {
+  private String jndiLocation = null;
+  private DataSource dataSource = null;
+
+  /**
+   * @see org.apache.log4j.spi.OptionHandler#activateOptions()
+   */
+  public void activateOptions() {
+    if (jndiLocation == null) {
+      getLogger().error("No JNDI location specified for JNDIConnectionSource.");
+    }
+    
+    discoverConnnectionProperties();
+
+  }
+  
+  /**
+   * @see org.apache.log4j.db.ConnectionSource#getConnection()
+   */
+  public Connection getConnection()
+         throws SQLException {
+    Connection conn = null;
+    try {
+
+      if(dataSource == null) {
+        dataSource = lookupDataSource();
+      }
+      if (getUser() == null) {
+        conn = dataSource.getConnection();
+      } else {
+        conn = dataSource.getConnection(getUser(), getPassword());
+      }
+    } catch (final NamingException ne) {
+         getLogger().error("Error while getting data source", ne);
+      throw new SQLException("NamingException while looking up DataSource: " + ne.getMessage());
+    } catch (final ClassCastException cce) {
+      getLogger().error("ClassCastException while looking up DataSource.", cce);
+      throw new SQLException("ClassCastException while looking up DataSource: " + cce.getMessage());
+    }
+
+    return conn;
+  }
+
+  /**
+   * Returns the jndiLocation.
+   * @return String
+   */
+  public String getJndiLocation() {
+    return jndiLocation;
+  }
+
+
+  /**
+   * Sets the jndiLocation.
+   * @param jndiLocation The jndiLocation to set
+   */
+  public void setJndiLocation(String jndiLocation) {
+    this.jndiLocation = jndiLocation;
+  }
+
+
+  private DataSource lookupDataSource()
+         throws NamingException, SQLException {
+    DataSource ds;
+    Context ctx = new InitialContext();
+    Object obj = ctx.lookup(jndiLocation);
+
+    // PortableRemoteObject was introduced in JDK 1.3. We won't use it.
+    //ds = (DataSource)PortableRemoteObject.narrow(obj, DataSource.class);
+    ds = (DataSource) obj;
+
+    if (ds == null) {
+      throw new SQLException("Failed to obtain data source from JNDI location " + jndiLocation);
+    } else {
+      return ds;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java b/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java
new file mode 100644
index 0000000..164a125
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/HSQLDBDialect.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect; 
+
+/** 
+ * The HSQLDB dialect. 
+ * 
+ * @author <a href="http://www.qos.ch/log4j/">Ceki G&uuml;lc&uuml;</a>
+*/ 
+public class HSQLDBDialect implements SQLDialect { 
+ public static final String SELECT_CURRVAL = "CALL IDENTITY()"; 
+
+ public String getSelectInsertId() { 
+   return SELECT_CURRVAL; 
+ } 
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java
new file mode 100644
index 0000000..08f4fc3
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/MsSQLDialect.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect; 
+
+/** 
+* The MS SQL Server dialect is untested. 
+* 
+* Note that the dialect is not needed if your JDBC driver supports 
+* the getGeneratedKeys method introduced in JDBC 3.0 specification.
+* 
+* @author James Stauffer 
+*/ 
+public class MsSQLDialect implements SQLDialect { 
+ public static final String SELECT_CURRVAL = "SELECT @@identity id"; 
+
+ public String getSelectInsertId() { 
+   return SELECT_CURRVAL; 
+ } 
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java
new file mode 100644
index 0000000..c1a63cd
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/MySQLDialect.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect;
+
+/**
+ * 
+ * 
+ * @author Ceki
+ *
+ */
+public class MySQLDialect implements SQLDialect {
+  public static final String SELECT_LAST_INSERT_ID = "SELECT LAST_INSERT_ID()";
+  
+  public String getSelectInsertId() {
+    return SELECT_LAST_INSERT_ID;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java b/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java
new file mode 100644
index 0000000..1714f1f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/OracleDialect.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect;
+
+/**
+ * The Oracle dialect. Tested successfully on Oracle9i Release 9.2.0.3.0 by 
+ * James Stauffer.
+ * 
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public class OracleDialect implements SQLDialect {
+  public static final String SELECT_CURRVAL = "SELECT logging_event_id_seq.currval from dual";
+
+  public String getSelectInsertId() {
+    return SELECT_CURRVAL;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java
new file mode 100644
index 0000000..dde4ff9
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/PostgreSQLDialect.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect;
+
+
+/**
+ * 
+ * @author ceki
+ *
+ * To change the template for this generated type comment go to
+ * Window>Preferences>Java>Code Generation>Code and Comments
+ */
+public class PostgreSQLDialect
+       implements SQLDialect {
+  public static final String SELECT_CURRVAL = "SELECT currval('logging_event_id_seq')";
+
+  public String getSelectInsertId() {
+    return SELECT_CURRVAL;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java b/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java
new file mode 100644
index 0000000..291283f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/SQLDialect.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.db.dialect;
+
+/**
+ * @author ceki
+ *
+ */
+public interface SQLDialect {
+  
+  public String getSelectInsertId();
+  
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java b/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java
new file mode 100644
index 0000000..44ba75e
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/SybaseDialect.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.log4j.db.dialect; 
+
+/** 
+ * The Sybase dialect. 
+ * 
+*/ 
+public class SybaseDialect implements SQLDialect { 
+ public static final String SELECT_CURRVAL = "select @@identity"; 
+
+ public String getSelectInsertId() { 
+   return SELECT_CURRVAL; 
+ } 
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/Util.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/Util.java b/src/main/java/org/apache/log4j/db/dialect/Util.java
new file mode 100644
index 0000000..5d60b12
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/Util.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db.dialect;
+
+import org.apache.log4j.db.ConnectionSource;
+import org.apache.log4j.spi.ComponentBase;
+
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+
+/**
+ * 
+ * @author Ceki Gulcu
+ *
+ */
+public class Util extends ComponentBase {
+  private static final String POSTGRES_PART = "postgresql";
+  private static final String MYSQL_PART = "mysql";
+  private static final String ORACLE_PART = "oracle";
+  //private static final String MSSQL_PART = "mssqlserver4";
+  private static final String MSSQL_PART = "microsoft";
+  private static final String HSQL_PART = "hsql";
+  
+  public static int discoverSQLDialect(DatabaseMetaData meta) {
+    int dialectCode = 0;
+
+    try {
+
+      String dbName = meta.getDatabaseProductName().toLowerCase();
+
+      if (dbName.indexOf(POSTGRES_PART) != -1) {
+        return ConnectionSource.POSTGRES_DIALECT;
+      } else if (dbName.indexOf(MYSQL_PART) != -1) {
+        return ConnectionSource.MYSQL_DIALECT;
+      } else if (dbName.indexOf(ORACLE_PART) != -1) {
+        return ConnectionSource.ORACLE_DIALECT;
+      } else if (dbName.indexOf(MSSQL_PART) != -1) {
+        return ConnectionSource.MSSQL_DIALECT;
+      } else if (dbName.indexOf(HSQL_PART) != -1) {
+        return ConnectionSource.HSQL_DIALECT;
+      } else {
+        return ConnectionSource.UNKNOWN_DIALECT;
+      }
+    } catch (SQLException sqle) {
+      // we can't do much here
+    }
+
+    return dialectCode;
+  }
+
+  public static SQLDialect getDialectFromCode(int dialectCode) {
+    SQLDialect sqlDialect = null;
+
+    switch (dialectCode) {
+    case ConnectionSource.POSTGRES_DIALECT:
+      sqlDialect = new PostgreSQLDialect();
+
+      break;
+    case ConnectionSource.MYSQL_DIALECT:
+      sqlDialect = new MySQLDialect();
+
+      break;
+    case ConnectionSource.ORACLE_DIALECT:
+      sqlDialect = new OracleDialect();
+
+      break;
+    case ConnectionSource.MSSQL_DIALECT:
+      sqlDialect = new MsSQLDialect();
+
+      break;
+    case ConnectionSource.HSQL_DIALECT:
+      sqlDialect = new HSQLDBDialect();
+
+      break;
+    }
+    return sqlDialect;
+  }
+  
+  /**
+   * This method handles cases where the 
+   * {@link DatabaseMetaData#supportsGetGeneratedKeys} method is missing in the
+   * JDBC driver implementation.
+   */
+  public boolean supportsGetGeneratedKeys(DatabaseMetaData meta) {
+    try {
+      //
+      //   invoking JDK 1.4 method by reflection
+      //
+      return ((Boolean) DatabaseMetaData.class.getMethod("supportsGetGeneratedKeys", null).invoke(meta, null)).booleanValue();
+    } catch(Throwable e) {
+      getLogger().info("Could not call supportsGetGeneratedKeys method. This may be recoverable");
+      return false;
+    }
+  }
+  
+/** 
+  * This method handles cases where the 
+  * {@link DatabaseMetaData#supportsBatchUpdates} method is missing in the
+  * JDBC driver implementation.
+  */
+  public boolean supportsBatchUpdates(DatabaseMetaData meta) {
+    try {
+      return meta.supportsBatchUpdates();
+    } catch(Throwable e) {
+      getLogger().info("Missing DatabaseMetaData.supportsBatchUpdates method.");
+      return false;
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/db2.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/db2.sql b/src/main/java/org/apache/log4j/db/dialect/db2.sql
new file mode 100644
index 0000000..47d2164
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/db2.sql
@@ -0,0 +1,64 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+# 
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for IBM DB2 databases.
+#
+# WARNING  WARNING WARNING  WARNING 
+# =================================
+# This SQL script has not been tested on an actual DB2
+# instance. It may contain errors or even invalid SQL
+# statements.
+
+DROP TABLE  logging_event_property;
+DROP TABLE  logging_event_exception;
+DROP TABLE  logging_event;
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  VARCHAR(4000) NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               VARCHAR(4000),
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INTEGER GENERATED ALWAYS AS IDENTITY (START WITH 1)
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INTEGER NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INTEGER NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/db2l.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/db2l.sql b/src/main/java/org/apache/log4j/db/dialect/db2l.sql
new file mode 100644
index 0000000..0f91315
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/db2l.sql
@@ -0,0 +1,61 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+# 
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for PostgreSQL databases.
+
+DROP TABLE    logging_event_property;
+DROP TABLE    logging_event_exception;
+DROP TABLE    logging_event;
+
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT IDENTITY GENERATED ALWAYS PRIMARY KEY
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql b/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql
new file mode 100644
index 0000000..50f8f78
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/hsqldb.sql
@@ -0,0 +1,60 @@
+//  Licensed to the Apache Software Foundation (ASF) under one or more
+//  contributor license agreements.  See the NOTICE file distributed with
+//  this work for additional information regarding copyright ownership.
+//  The ASF licenses this file to You under the Apache License, Version 2.0
+//  (the "License"); you may not use this file except in compliance with
+//  the License.  You may obtain a copy of the License at
+// 
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+// This SQL script creates the required tables by
+// org.apache.log4j.db.DBAppender and org.apache.log4j.db.DBReceiver.
+//
+// It is intended for HSQLDB. 
+//
+
+DROP TABLE logging_event_exception IF EXISTS;
+DROP TABLE logging_event_property IF EXISTS;
+DROP TABLE logging_event IF EXISTS;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  LONGVARCHAR NOT NULL,
+    logger_name       VARCHAR NOT NULL,
+    level_string      VARCHAR NOT NULL,
+    ndc               LONGVARCHAR,
+    thread_name       VARCHAR,
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR, 
+    caller_class      VARCHAR, 
+    caller_method     VARCHAR, 
+    caller_line       CHAR(4), 
+    event_id          INT NOT NULL IDENTITY
+  );
+
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      LONGVARCHAR,
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/mssql.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/mssql.sql b/src/main/java/org/apache/log4j/db/dialect/mssql.sql
new file mode 100644
index 0000000..d87e0a0
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/mssql.sql
@@ -0,0 +1,61 @@
+--  Licensed to the Apache Software Foundation (ASF) under one or more
+--  contributor license agreements.  See the NOTICE file distributed with
+--  this work for additional information regarding copyright ownership.
+--  The ASF licenses this file to You under the Apache License, Version 2.0
+--  (the "License"); you may not use this file except in compliance with
+--  the License.  You may obtain a copy of the License at
+-- 
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+--
+-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+-- org.apache.log4j.db.DBReceiver. 
+-- 
+-- It is intended for MS SQL Server databases.  This has been tested with version 7.0. 
+
+DROP TABLE logging_event_property 
+DROP TABLE logging_event_exception 
+DROP TABLE logging_event 
+
+CREATE TABLE logging_event 
+  ( 
+    sequence_number   DECIMAL(20) NOT NULL, 
+    timestamp         DECIMAL(20) NOT NULL, 
+    rendered_message  VARCHAR(4000) NOT NULL, 
+    logger_name       VARCHAR(254) NOT NULL, 
+    level_string      VARCHAR(254) NOT NULL, 
+    ndc               VARCHAR(4000), 
+    thread_name       VARCHAR(254), 
+    reference_flag    SMALLINT, 
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT NOT NULL identity, 
+    PRIMARY KEY(event_id) 
+  ) 
+
+CREATE TABLE logging_event_property 
+  ( 
+    event_id          INT NOT NULL, 
+    mapped_key        VARCHAR(254) NOT NULL, 
+    mapped_value      VARCHAR(1024), 
+    PRIMARY KEY(event_id, mapped_key), 
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
+  ) 
+
+CREATE TABLE logging_event_exception 
+  ( 
+    event_id         INT NOT NULL, 
+    i                SMALLINT NOT NULL, 
+    trace_line       VARCHAR(254) NOT NULL, 
+    PRIMARY KEY(event_id, i), 
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id) 
+  ) 
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/mysql.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/mysql.sql b/src/main/java/org/apache/log4j/db/dialect/mysql.sql
new file mode 100644
index 0000000..e3a2be1
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/mysql.sql
@@ -0,0 +1,71 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+# 
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+#
+#
+# This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for MySQL databases. It has been tested on MySQL 4.1.1 with 
+# INNODB tables.
+
+
+BEGIN;
+DROP TABLE IF EXISTS logging_event_property;
+DROP TABLE IF EXISTS logging_event_exception;
+DROP TABLE IF EXISTS logging_event;
+COMMIT;
+
+
+BEGIN;
+CREATE TABLE logging_event 
+  (
+    sequence_number BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT NOT NULL AUTO_INCREMENT PRIMARY KEY
+  );
+COMMIT;
+
+BEGIN;
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      TEXT,
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+COMMIT;
+
+BEGIN;
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+COMMIT;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/oracle.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/oracle.sql b/src/main/java/org/apache/log4j/db/dialect/oracle.sql
new file mode 100644
index 0000000..84bf9e5
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/oracle.sql
@@ -0,0 +1,77 @@
+--  Licensed to the Apache Software Foundation (ASF) under one or more
+--  contributor license agreements.  See the NOTICE file distributed with
+--  this work for additional information regarding copyright ownership.
+--  The ASF licenses this file to You under the Apache License, Version 2.0
+--  (the "License"); you may not use this file except in compliance with
+--  the License.  You may obtain a copy of the License at
+-- 
+--       http://www.apache.org/licenses/LICENSE-2.0
+--
+--  Unless required by applicable law or agreed to in writing, software
+--  distributed under the License is distributed on an "AS IS" BASIS,
+--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+--  See the License for the specific language governing permissions and
+--  limitations under the License.
+--
+--
+-- This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+-- org.apache.log4j.db.DBReceiver.
+--
+-- It is intended for Oracle databases.
+
+-- Tested successfully on Oracle9i Release 9.2.0.3.0 by James Stauffer
+-- Tested successfully on Oracle9i Release by Elias Ross
+
+-- The following lines are useful in cleaning any previous tables 
+
+--drop TRIGGER logging_event_id_seq_trig; 
+--drop SEQUENCE logging_event_id_seq; 
+--drop table logging_event_property; 
+--drop table logging_event_exception; 
+--drop table logging_event; 
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START WITH 1;
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   NUMBER(20) NOT NULL,
+    timestamp         NUMBER(20) NOT NULL,
+    rendered_message  VARCHAR2(4000) NOT NULL,
+    logger_name       VARCHAR2(254) NOT NULL,
+    level_string      VARCHAR2(254) NOT NULL,
+    ndc               VARCHAR2(4000),
+    thread_name       VARCHAR2(254),
+    reference_flag    NUMBER(5),
+    caller_filename   VARCHAR2(254) NOT NULL,
+    caller_class      VARCHAR2(254) NOT NULL,
+    caller_method     VARCHAR2(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          NUMBER(10) PRIMARY KEY
+  );
+
+CREATE OR REPLACE TRIGGER logging_event_id_seq_trig
+BEFORE INSERT ON logging_event
+FOR EACH ROW
+BEGIN
+   SELECT logging_event_id_seq.nextval
+   INTO :new.sequence_number FROM dual;
+END;
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      NUMBER(10) NOT NULL,
+    mapped_key        VARCHAR2(254) NOT NULL,
+    mapped_value      VARCHAR2(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+  
+CREATE TABLE logging_event_exception
+  (
+    event_id         NUMBER(10) NOT NULL,
+    i                NUMBER(5)  NOT NULL,
+    trace_line       VARCHAR2(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+  

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/dialect/postgresql.sql
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/dialect/postgresql.sql b/src/main/java/org/apache/log4j/db/dialect/postgresql.sql
new file mode 100644
index 0000000..c38757b
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/dialect/postgresql.sql
@@ -0,0 +1,63 @@
+#  Licensed to the Apache Software Foundation (ASF) under one or more
+#  contributor license agreements.  See the NOTICE file distributed with
+#  this work for additional information regarding copyright ownership.
+#  The ASF licenses this file to You under the Apache License, Version 2.0
+#  (the "License"); you may not use this file except in compliance with
+#  the License.  You may obtain a copy of the License at
+# 
+#       http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+#
+## This SQL script creates the required tables by org.apache.log4j.db.DBAppender and 
+# org.apache.log4j.db.DBReceiver.
+#
+# It is intended for PostgreSQL databases.
+
+DROP TABLE    logging_event_property;
+DROP TABLE    logging_event_exception;
+DROP SEQUENCE logging_event_id_seq;
+DROP TABLE    logging_event;
+
+
+CREATE SEQUENCE logging_event_id_seq MINVALUE 1 START 1;
+
+
+CREATE TABLE logging_event 
+  (
+    sequence_number   BIGINT NOT NULL,
+    timestamp         BIGINT NOT NULL,
+    rendered_message  TEXT NOT NULL,
+    logger_name       VARCHAR(254) NOT NULL,
+    level_string      VARCHAR(254) NOT NULL,
+    ndc               TEXT,
+    thread_name       VARCHAR(254),
+    reference_flag    SMALLINT,
+    caller_filename   VARCHAR(254) NOT NULL,
+    caller_class      VARCHAR(254) NOT NULL,
+    caller_method     VARCHAR(254) NOT NULL,
+    caller_line       CHAR(4) NOT NULL,
+    event_id          INT DEFAULT nextval('logging_event_id_seq') PRIMARY KEY
+  );
+
+CREATE TABLE logging_event_property
+  (
+    event_id	      INT NOT NULL,
+    mapped_key        VARCHAR(254) NOT NULL,
+    mapped_value      VARCHAR(1024),
+    PRIMARY KEY(event_id, mapped_key),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );
+
+CREATE TABLE logging_event_exception
+  (
+    event_id         INT NOT NULL,
+    i                SMALLINT NOT NULL,
+    trace_line       VARCHAR(254) NOT NULL,
+    PRIMARY KEY(event_id, i),
+    FOREIGN KEY (event_id) REFERENCES logging_event(event_id)
+  );

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/package.html
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/package.html b/src/main/java/org/apache/log4j/db/package.html
new file mode 100644
index 0000000..55652fb
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/package.html
@@ -0,0 +1,36 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+ 
+       http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<html>
+<body>
+
+<p>The org.apache.log4j.db package provides means to append logging events 
+into various databases. The persisted data can be later read back using
+{@link org.apache.log4j.db.DBReceiver}.
+</p>
+
+<p>Most popular database systems, such as PostgreSQL, MySQL, Oracle, DB2 and MsSQL
+are supported.
+</p>
+
+<p>Just as importantly, the way for obtaining JDBC connections is pluggable. Connections can
+be obtained through the tradinal way of DriverManager, or alternatively as a DataSource. 
+A DataSource can be instantiated directly or it can obtained through JNDI.
+</p>
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/Constants.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/helpers/Constants.java b/src/main/java/org/apache/log4j/helpers/Constants.java
new file mode 100644
index 0000000..dbbbe59
--- /dev/null
+++ b/src/main/java/org/apache/log4j/helpers/Constants.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+
+/**
+ * Constants used internally throughout log4j.
+ *
+ */
+public interface Constants {
+
+    /**
+     * log4j package name string literal.
+     */
+  String LOG4J_PACKAGE_NAME = "org.apache.log4j";
+
+  /**
+   *  The name of the default repository is "default" (without the quotes).
+   */
+  String DEFAULT_REPOSITORY_NAME  = "default";
+
+    /**
+     * application string literal.
+     */
+  String APPLICATION_KEY = "application";
+    /**
+     * hostname string literal.
+     */
+  String HOSTNAME_KEY = "hostname";
+    /**
+     * receiver string literal.
+     */
+  String RECEIVER_NAME_KEY = "receiver";
+    /**
+     * log4jid string literal.
+     */
+  String LOG4J_ID_KEY = "log4jid";
+    /**
+     * time stamp pattern string literal.
+     */
+  String TIMESTAMP_RULE_FORMAT = "yyyy/MM/dd HH:mm:ss";
+
+  /**
+   * The default property file name for automatic configuration.
+   */
+  String DEFAULT_CONFIGURATION_FILE = "log4j.properties";
+  /**
+   * The default XML configuration file name for automatic configuration.
+   */
+  String DEFAULT_XML_CONFIGURATION_FILE = "log4j.xml";
+    /**
+     * log4j.configuration string literal.
+     */
+  String DEFAULT_CONFIGURATION_KEY = "log4j.configuration";
+    /**
+     * log4j.configuratorClass string literal.
+     */
+  String CONFIGURATOR_CLASS_KEY = "log4j.configuratorClass";
+
+    /**
+     * JNDI context name string literal.
+     */
+  String JNDI_CONTEXT_NAME = "java:comp/env/log4j/context-name";
+
+    /**
+     * TEMP_LIST_APPENDER string literal.
+     */
+  String TEMP_LIST_APPENDER_NAME = "TEMP_LIST_APPENDER";
+    /**
+     * TEMP_CONSOLE_APPENDER string literal.
+     */
+  String TEMP_CONSOLE_APPENDER_NAME = "TEMP_CONSOLE_APPENDER";
+    /**
+     * Codes URL string literal.
+     */
+  String CODES_HREF =
+          "http://logging.apache.org/log4j/docs/codes.html";
+
+
+    /**
+     * ABSOLUTE string literal.
+     */
+  String ABSOLUTE_FORMAT = "ABSOLUTE";
+    /**
+     * SimpleTimePattern for ABSOLUTE.
+     */
+  String ABSOLUTE_TIME_PATTERN = "HH:mm:ss,SSS";
+
+    /**
+     * SimpleTimePattern for ABSOLUTE.
+     */
+  String SIMPLE_TIME_PATTERN = "HH:mm:ss";
+
+    /**
+     * DATE string literal.
+     */
+  String DATE_AND_TIME_FORMAT = "DATE";
+    /**
+     * SimpleTimePattern for DATE.
+     */
+  String DATE_AND_TIME_PATTERN = "dd MMM yyyy HH:mm:ss,SSS";
+
+    /**
+     * ISO8601 string literal.
+     */
+  String ISO8601_FORMAT = "ISO8601";
+    /**
+     * SimpleTimePattern for ISO8601.
+     */
+  String ISO8601_PATTERN = "yyyy-MM-dd HH:mm:ss,SSS";
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/MessageFormatter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/helpers/MessageFormatter.java b/src/main/java/org/apache/log4j/helpers/MessageFormatter.java
new file mode 100644
index 0000000..8c77da1
--- /dev/null
+++ b/src/main/java/org/apache/log4j/helpers/MessageFormatter.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+
+/**
+ * Formats messages according to very simple rules.
+ * See {@link #format(String,Object)} and
+ * {@link #format(String,Object,Object)} for more details.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public final class MessageFormatter {
+    /**
+     * Private formatter since all methods and members are static.
+     */
+    private MessageFormatter() {
+        super();
+    }
+
+    /**
+     * Start of replacement block.
+     */
+    private static final char DELIM_START = '{';
+    /**
+     * End of replacement block.
+     */
+    private static final char DELIM_STOP = '}';
+
+    /**
+     * Performs single argument substitution for the 'messagePattern' passed as
+     * parameter.
+     * <p/>
+     * For example, <code>MessageFormatter.format("Hi {}.", "there");</code>
+     * will return the string "Hi there.".
+     * <p/>
+     * The {} pair is called the formatting element. It serves to designate the
+     * location where the argument needs to be inserted within the pattern.
+     *
+     * @param messagePattern
+     *     The message pattern which will be parsed and formatted
+     * @param argument
+     *     The argument to be inserted instead of the formatting element
+     * @return The formatted message
+     */
+    public static String format(final String messagePattern,
+                                final Object argument) {
+        int j = messagePattern.indexOf(DELIM_START);
+        int len = messagePattern.length();
+        char escape = 'x';
+
+        // if there are no { characters or { is the last character
+        // then we just return messagePattern
+        if (j == -1 || (j + 1 == len)) {
+            return messagePattern;
+        } else {
+            char delimStop = messagePattern.charAt(j + 1);
+            if (j > 0) {
+                escape = messagePattern.charAt(j - 1);
+            }
+            if ((delimStop != DELIM_STOP) || (escape == '\\')) {
+                // invalid DELIM_START/DELIM_STOP pair or espace character is
+                // present
+                return messagePattern;
+            } else {
+                StringBuffer sbuf = new StringBuffer(len + 20);
+                sbuf.append(messagePattern.substring(0, j));
+                sbuf.append(argument);
+                sbuf.append(messagePattern.substring(j + 2));
+                return sbuf.toString();
+            }
+        }
+    }
+
+    /**
+     * /**
+     * Performs a two argument substitution for the 'messagePattern' passed as
+     * parameter.
+     * <p/>
+     * For example, <code>MessageFormatter.format("Hi {}. My name is {}.",
+     * "there", "David");</code> will return the string
+     * "Hi there. My name is David.".
+     * <p/>
+     * The '{}' pair is called a formatting element. It serves to designate the
+     * location where the arguments need to be inserted within
+     * the message pattern.
+     *
+     * @param messagePattern
+     *     The message pattern which will be parsed and formatted
+     * @param arg1
+     *     The first argument to replace the first formatting element
+     * @param arg2
+     *     The second argument to replace the second formatting element
+     * @return The formatted message
+     */
+    public static String format(final String messagePattern,
+                                final Object arg1,
+                                final Object arg2) {
+        int i = 0;
+        int len = messagePattern.length();
+
+        StringBuffer sbuf = new StringBuffer(messagePattern.length() + 50);
+
+        for (int l = 0; l < 2; l++) {
+            int j = messagePattern.indexOf(DELIM_START, i);
+
+            if (j == -1 || (j + 1 == len)) {
+                // no more variables
+                if (i == 0) { // this is a simple string
+                    return messagePattern;
+                } else {
+                    // add the tail string which contains no variables
+                    // and return the result.
+                    sbuf.append(messagePattern.substring(i,
+                                    messagePattern.length()));
+                    return sbuf.toString();
+                }
+            } else {
+                char delimStop = messagePattern.charAt(j + 1);
+                if ((delimStop != DELIM_STOP)) {
+                    // invalid DELIM_START/DELIM_STOP pair
+                    sbuf.append(messagePattern.substring(i,
+                            messagePattern.length()));
+                    return sbuf.toString();
+                }
+                sbuf.append(messagePattern.substring(i, j));
+                if (l == 0) {
+                    sbuf.append(arg1);
+                } else {
+                    sbuf.append(arg2);
+                }
+                i = j + 2;
+            }
+        }
+        // append the characters following the second {} pair.
+        sbuf.append(messagePattern.substring(i, messagePattern.length()));
+        return sbuf.toString();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java b/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java
new file mode 100644
index 0000000..b15fbca
--- /dev/null
+++ b/src/main/java/org/apache/log4j/helpers/UtilLoggingLevel.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.log4j.Level;
+
+/**
+ * An extension of the Level class that provides support for java.util.logging
+ * Levels.
+ *
+ *
+ * @author Scott Deboy (sdeboy@apache.org)
+ */
+
+public class UtilLoggingLevel extends Level {
+
+    /**
+     * Serialization version id.
+     */
+    private static final long serialVersionUID = 909301162611820211L;
+
+    /**
+     * Numerical value for SEVERE.
+     */
+    public static final int SEVERE_INT = 22000;
+    /**
+     * Numerical value for WARNING.
+     */
+    public static final int WARNING_INT = 21000;
+
+    //INFO level defined in parent as 20000..no need to redefine here
+    
+    /**
+     * Numerical value for CONFIG.
+     */
+    public static final int CONFIG_INT = 14000;
+    /**
+     * Numerical value for FINE.
+     */
+    public static final int FINE_INT = 13000;
+    /**
+     * Numerical value for FINER.
+     */
+    public static final int FINER_INT = 12000;
+    /**
+     * Numerical value for FINEST.
+     */
+    public static final int FINEST_INT = 11000;
+    /**
+     * Numerical value for UNKNOWN.
+     */
+    public static final int UNKNOWN_INT = 10000;
+
+    /**
+     * SEVERE.
+     */
+    public static final UtilLoggingLevel SEVERE =
+            new UtilLoggingLevel(SEVERE_INT, "SEVERE", 0);
+    /**
+     * WARNING.
+     */
+    public static final UtilLoggingLevel WARNING =
+            new UtilLoggingLevel(WARNING_INT, "WARNING", 4);
+    /**
+     * INFO.
+     */
+    //note: we've aligned the int values of the java.util.logging INFO level with log4j's level
+    public static final UtilLoggingLevel INFO =
+            new UtilLoggingLevel(INFO_INT, "INFO", 5);
+    /**
+     * CONFIG.
+     */
+    public static final UtilLoggingLevel CONFIG =
+            new UtilLoggingLevel(CONFIG_INT, "CONFIG", 6);
+    /**
+     * FINE.
+     */
+    public static final UtilLoggingLevel FINE =
+            new UtilLoggingLevel(FINE_INT, "FINE", 7);
+    /**
+     * FINER.
+     */
+    public static final UtilLoggingLevel FINER =
+            new UtilLoggingLevel(FINER_INT, "FINER", 8);
+    /**
+     * FINEST.
+     */
+    public static final UtilLoggingLevel FINEST =
+            new UtilLoggingLevel(FINEST_INT, "FINEST", 9);
+
+    /**
+     * Create new instance.
+     * @param level numeric value for level.
+     * @param levelStr symbolic name for level.
+     * @param syslogEquivalent Equivalent syslog severity.
+     */
+    protected UtilLoggingLevel(final int level,
+                               final String levelStr,
+                               final int syslogEquivalent) {
+        super(level, levelStr, syslogEquivalent);
+    }
+
+    /**
+     * Convert an integer passed as argument to a level. If the
+     * conversion fails, then this method returns the specified default.
+     * @param val numeric value.
+     * @param defaultLevel level to be returned if no level matches
+     * numeric value.
+     * @return matching level or default level.
+     */
+    public static UtilLoggingLevel toLevel(final int val,
+                               final UtilLoggingLevel defaultLevel) {
+        switch (val) {
+            case SEVERE_INT:
+                return SEVERE;
+
+            case WARNING_INT:
+                return WARNING;
+
+            case INFO_INT:
+                return INFO;
+
+            case CONFIG_INT:
+                return CONFIG;
+
+            case FINE_INT:
+                return FINE;
+
+            case FINER_INT:
+                return FINER;
+
+            case FINEST_INT:
+                return FINEST;
+
+            default:
+                return defaultLevel;
+        }
+    }
+
+    /**
+     * Gets level matching numeric value.
+     * @param val numeric value.
+     * @return  matching level or UtilLoggerLevel.FINEST if no match.
+     */
+    public static Level toLevel(final int val) {
+        return toLevel(val, FINEST);
+    }
+
+    /**
+     * Gets list of supported levels.
+     * @return  list of supported levels.
+     */
+    public static List getAllPossibleLevels() {
+        ArrayList list = new ArrayList();
+        list.add(FINE);
+        list.add(FINER);
+        list.add(FINEST);
+        list.add(INFO);
+        list.add(CONFIG);
+        list.add(WARNING);
+        list.add(SEVERE);
+        return list;
+    }
+
+    /**
+     * Get level with specified symbolic name.
+     * @param s symbolic name.
+     * @return matching level or Level.DEBUG if no match.
+     */
+    public static Level toLevel(final String s) {
+        return toLevel(s, Level.DEBUG);
+    }
+
+
+    /**
+     * Get level with specified symbolic name.
+     * @param sArg symbolic name.
+     * @param defaultLevel level to return if no match.
+     * @return matching level or defaultLevel if no match.
+     */
+    public static Level toLevel(final String sArg,
+                                final Level defaultLevel) {
+        if (sArg == null) {
+            return defaultLevel;
+        }
+
+        String s = sArg.toUpperCase();
+
+        if (s.equals("SEVERE")) {
+            return SEVERE;
+        }
+
+        //if(s.equals("FINE")) return Level.FINE;
+        if (s.equals("WARNING")) {
+            return WARNING;
+        }
+
+        if (s.equals("INFO")) {
+            return INFO;
+        }
+
+        if (s.equals("CONFI")) {
+            return CONFIG;
+        }
+
+        if (s.equals("FINE")) {
+            return FINE;
+        }
+
+        if (s.equals("FINER")) {
+            return FINER;
+        }
+
+        if (s.equals("FINEST")) {
+            return FINEST;
+        }
+        return defaultLevel;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/AddressBased.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/AddressBased.java b/src/main/java/org/apache/log4j/net/AddressBased.java
new file mode 100644
index 0000000..ccd2e6a
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/AddressBased.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+
+/**
+ * Net based entities that 'work with' an Address
+ * should consider implementing this
+ * interface so that they can be treated generically.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public interface AddressBased extends NetworkBased {
+  /**
+   * Returns a String representation of the Address this instance
+   * encompasses.
+   * @return String representation of the Address
+   */
+  String getAddress();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/JMSReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/JMSReceiver.java b/src/main/java/org/apache/log4j/net/JMSReceiver.java
new file mode 100644
index 0000000..d22e25c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/JMSReceiver.java
@@ -0,0 +1,301 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.FileInputStream;
+import java.util.Properties;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import javax.jms.TopicConnection;
+import javax.jms.Topic;
+import javax.jms.TopicConnectionFactory;
+import javax.jms.TopicSubscriber;
+import javax.jms.Session;
+import javax.jms.TopicSession;
+import javax.jms.ObjectMessage;
+
+import javax.naming.InitialContext;
+import javax.naming.Context;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
+
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.Receiver;
+
+/**
+  JMSReceiver receives a remote logging event on a configured
+  JSM topic and "posts" it to a LoggerRepository as if the event was 
+  generated locally. This class is designed to receive events from 
+  the JMSAppender class (or classes that send compatible events).
+  
+  <p>Once the event has been "posted", it will be handled by the 
+  appenders currently configured in the LoggerRespository.
+  
+  <p>This implementation borrows heavily from the JMSSink
+  implementation.
+  
+  @author Mark Womack
+  @author Paul Smith
+  @author Stephen Pain
+*/
+public class JMSReceiver extends Receiver implements MessageListener {
+
+  private boolean active = false;
+
+  protected String topicFactoryName;
+  protected String topicName;
+  protected String userId;
+  protected String password;
+  protected TopicConnection topicConnection;
+  protected String jndiPath;
+  
+  private String remoteInfo;
+  private String providerUrl;
+
+  public JMSReceiver() { }
+
+  public JMSReceiver(String _topicFactoryName, String _topicName,
+          String _userId, String _password, String _jndiPath) {      
+      topicFactoryName = _topicFactoryName;
+      topicName = _topicName;
+      userId = _userId;
+      password = _password;
+      jndiPath = _jndiPath;
+  }
+
+  /**
+         * Sets the path to a properties file containing
+         * the initial context and jndi provider url
+         */
+    public void setJndiPath(String _jndiPath) {
+          jndiPath = _jndiPath;
+    }
+  
+     /**
+         * Gets the path to a properties file containing
+         * the initial context and jndi provider url
+         */
+     public String getJndiPath() {
+          return jndiPath;
+     }
+  
+  /**
+    Sets the JMS topic factory name to use when creating the 
+    JMS connection. */
+  public void setTopicFactoryName(String _topicFactoryName) {
+    topicFactoryName = _topicFactoryName;
+  }
+  
+  /**
+    Gets the curernt JMS topic factory name property. */
+  public String getTopicFactoryName() {
+    return topicFactoryName;
+  }
+  
+  /**
+   * Sets the JMS topic name to use when creating the
+   * JMS connection.
+   */
+  public void setTopicName(String _topicName) {
+    topicName = _topicName;
+  }
+  
+  /**
+   * Gets the curernt JMS topic name property.
+   */
+  public String getTopicName() {
+    return topicName;
+  }
+
+  /**
+    Sets the user id to use when creating the 
+    JMS connection. */
+  public void setUserId(String _userId) {
+    userId = _userId;
+  }
+  
+  /**
+   * Gets the current user id property.
+   */
+  public String getUserId() {
+    return userId;
+  }
+
+  /**
+   * Sets the password to use when creating the
+   * JMS connection.
+   */
+  public void setPassword(String _password) {
+    password = _password;
+  }
+  
+  /**
+   * Gets the curernt password property.
+   */
+  public String getPassword() {
+    return password;
+  }
+ 
+  /**
+   * Returns true if the receiver is the same class and they are
+   * configured for the same properties, and super class also considers
+   * them to be equivalent. This is used by PluginRegistry when determining
+   * if the a similarly configured receiver is being started.
+   * 
+   * @param testPlugin The plugin to test equivalency against.
+   * @return boolean True if the testPlugin is equivalent to this plugin.
+   */
+  public boolean isEquivalent(Plugin testPlugin) {
+    // only do full check if an instance of this class
+    if (testPlugin instanceof JMSReceiver) {
+ 
+      JMSReceiver receiver = (JMSReceiver)testPlugin;
+      
+      // check for same topic name and super class equivalency
+      return (
+            topicFactoryName.equals(receiver.getTopicFactoryName()) && 
+            (jndiPath == null || jndiPath.equals(receiver.getJndiPath())) && 
+            super.isEquivalent(testPlugin)
+            );
+    }
+    
+    return false;
+  }
+  
+  /**
+    Returns true if this receiver is active. */
+  public synchronized boolean isActive() {
+    return active;
+  }
+  
+  /**
+    Sets the flag to indicate if receiver is active or not. */
+  protected synchronized void setActive(boolean _active) {
+    active = _active;
+  }
+  
+  /**
+    Starts the JMSReceiver with the current options. */
+  public void activateOptions() {
+    if (!isActive()) {
+      try {
+        remoteInfo = topicFactoryName + ":" + topicName;
+
+        Context ctx = null;
+        if (jndiPath == null || jndiPath.equals("")) {
+                ctx = new InitialContext();
+        } else {
+                FileInputStream is = new FileInputStream(jndiPath);
+                Properties p = new Properties();
+                p.load(is);
+                is.close();
+                ctx = new InitialContext(p);
+        }
+
+        // give some more flexibility about the choice of a tab name
+        providerUrl = (String)ctx.getEnvironment().get(Context.PROVIDER_URL);
+        TopicConnectionFactory topicConnectionFactory;
+        topicConnectionFactory = 
+          (TopicConnectionFactory) lookup(ctx, topicFactoryName);
+        
+        if (userId != null && password != null) {
+          topicConnection =
+    	       topicConnectionFactory.createTopicConnection(userId, password);
+        } else {
+          topicConnection =
+    	       topicConnectionFactory.createTopicConnection();
+        }
+  	       
+        TopicSession topicSession =
+          topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
+  
+        Topic topic = (Topic)ctx.lookup(topicName);
+  
+        TopicSubscriber topicSubscriber = topicSession.createSubscriber(topic);
+      
+        topicSubscriber.setMessageListener(this);
+ 
+        topicConnection.start();
+ 
+        setActive(true);
+      } catch(Exception e) {
+        setActive(false);
+        if (topicConnection != null) {
+          try {
+            topicConnection.close();
+          } catch (Exception e2) {
+            // do nothing
+          }
+          topicConnection = null;
+        }
+        getLogger().error("Could not start JMSReceiver.", e);
+      }
+    }
+  }
+  
+  /**
+    Called when the receiver should be stopped. */
+  public synchronized void shutdown() {
+    if (isActive()) {
+      // mark this as no longer running
+      setActive(false);
+    
+      if (topicConnection != null) {
+        try {
+          topicConnection.close();
+        } catch (Exception e) {
+          // do nothing
+        }
+        topicConnection = null;
+      }
+    }
+  }
+
+  public void onMessage(Message message) {
+    try {
+      if(message instanceof  ObjectMessage) {
+        // get the logging event and post it to the repository
+      	ObjectMessage objectMessage = (ObjectMessage) message;
+      	LoggingEvent event = (LoggingEvent) objectMessage.getObject();
+      	
+      	// store the known remote info in an event property
+      	event.setProperty("log4j.remoteSourceInfo", remoteInfo);
+        event.setProperty("log4j.jmsProviderUrl", providerUrl);
+        
+      	doPost(event);
+      } else {
+      	getLogger().warn("Received message is of type "+message.getJMSType()
+		    +", was expecting ObjectMessage.");
+      }      
+    } catch(Exception e) {
+      getLogger().error("Exception thrown while processing incoming message.", e);
+    }
+  }
+
+  protected Object lookup(Context ctx, String name) throws NamingException {
+    try {
+      return ctx.lookup(name);
+    } catch(NameNotFoundException e) {
+      getLogger().error("Could not find name ["+name+"].");
+      throw e;
+    }
+  }
+
+}


[18/50] [abbrv] logging-chainsaw git commit: Removed 'use auto-saved config' from initial receiver config screen, added 'save' button to receiver definition panel Updates to use of receiver configuration (using custom-saved option if available)

Posted by rg...@apache.org.
Removed 'use auto-saved config' from initial receiver config screen, added 'save' button to receiver definition panel
Updates to use of receiver configuration (using custom-saved option if available)


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/e6f85a21
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/e6f85a21
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/e6f85a21

Branch: refs/heads/master
Commit: e6f85a2194b87df1681a6f812f2382b8c2a39d52
Parents: 4caf282
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Nov 5 06:19:59 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Nov 5 06:19:59 2010 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 27 ++++++++--------
 .../chainsaw/ReceiverConfigurationPanel.java    | 17 +---------
 .../chainsaw/receivers/ReceiversPanel.java      | 34 ++++++++++++++++++++
 3 files changed, 49 insertions(+), 29 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e6f85a21/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index dd9775a..da000ca 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1453,23 +1453,14 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                 pluginRegistry.addPlugin(networkReceiver);
                 networkReceiver.activateOptions();
                 receiversPanel.updateReceiverTreeInDispatchThread();
-                //setting config URL here ensures we have the receiver panel auto-saved config loaded
-                if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                    configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-                }
               } catch (Exception e3) {
                 MessageCenter.getInstance().getLogger().error(
                   "Error creating Receiver", e3);
                 MessageCenter.getInstance().getLogger().info(
                   "An error occurred creating your Receiver");
               }
-            } else if (receiverConfigurationPanel.getModel().isLoadConfig() ||
-                    receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
-              if (receiverConfigurationPanel.getModel().isLoadSavedConfigs()) {
-                  configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-              } else {
+            } else if (receiverConfigurationPanel.getModel().isLoadConfig()) {
                   configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
-              }
             } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {
               try {
                   URL fileURL = receiverConfigurationPanel.getModel().getLogFileURL();
@@ -1492,9 +1483,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                       pluginRegistry.addPlugin(fileReceiver);
                       fileReceiver.activateOptions();
                       receiversPanel.updateReceiverTreeInDispatchThread();
-                      if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                          configURL = receiverConfigurationPanel.getModel().getSavedConfigToLoad();
-                      }
                   }
               } catch (Exception e2) {
                   MessageCenter.getInstance().getLogger().error(
@@ -1503,6 +1491,19 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                     "An error occurred creating your Receiver");
               }
             }
+              if (configURL == null && receiverConfigurationPanel.isDontWarnMeAgain()) {
+                //use the saved config file as the config URL if defined
+                if (receiverConfigurationPanel.getModel().getSaveConfigFile() != null) {
+                  try {
+                    configURL = receiverConfigurationPanel.getModel().getSaveConfigFile().toURI().toURL();
+                  } catch (MalformedURLException e1) {
+                    e1.printStackTrace();
+                  }
+                } else {
+                  //no saved config defined but don't warn me is checked - use default config
+                  configURL = receiverConfigurationPanel.getModel().getDefaultConfigFileURL();
+                }
+              }
               if (configURL != null) {
                 MessageCenter.getInstance().getLogger().debug(
                   "Initialiazing Log4j with " + configURL.toExternalForm());

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e6f85a21/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index adbe826..1f94570 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -100,7 +100,6 @@ class ReceiverConfigurationPanel extends JPanel {
     private JRadioButton logFileReceiverRadioButton;
     private JRadioButton networkReceiverRadioButton;
     private JRadioButton useExistingConfigurationRadioButton;
-    private JRadioButton useAutoSavedConfigRadioButton;
     private ButtonGroup buttonGroup;
 
     private JPanel lowerPanel;
@@ -157,15 +156,6 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        c.insets = new Insets(0, 0, 0, 0);
-        useAutoSavedConfigRadioButton = new JRadioButton(" Use auto-saved configuration from $HOME/.chainsaw/receiver-config.xml ");
-        buttonGroup.add(useAutoSavedConfigRadioButton);
-        add(useAutoSavedConfigRadioButton, c);
-
-        c = new GridBagConstraints();
-        c.gridx = 0;
-        c.gridy = yPos++;
-        c.fill = GridBagConstraints.HORIZONTAL;
         c.insets = new Insets(10, 10, 10, 0);
         add(lowerPanel, c);
         
@@ -197,7 +187,6 @@ class ReceiverConfigurationPanel extends JPanel {
         logFileReceiverRadioButton.addActionListener(al);
         networkReceiverRadioButton.addActionListener(al);
         useExistingConfigurationRadioButton.addActionListener(al);
-        useAutoSavedConfigRadioButton.addActionListener(al);
 
         buttonGroup.setSelected(logFileReceiverRadioButton.getModel(), true);
         updateEnabledState(logFileReceiverRadioButton);
@@ -690,10 +679,6 @@ class ReceiverConfigurationPanel extends JPanel {
             return !cancelled && useExistingConfigurationRadioButton.isSelected();
         }
 
-        boolean isLoadSavedConfigs() {
-            return !cancelled && useAutoSavedConfigRadioButton.isSelected();
-        }
-
         boolean isLogFileReceiverConfig() {
             return !cancelled && logFileReceiverRadioButton.isSelected();
         }
@@ -710,7 +695,7 @@ class ReceiverConfigurationPanel extends JPanel {
             }
         }
 
-        URL getSavedConfigToLoad() {
+        URL getDefaultConfigFileURL() {
             try {
                 return file.toURI().toURL();
             } catch (MalformedURLException e) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e6f85a21/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
index 91ba7ca..dfc003b 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
@@ -97,6 +97,7 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
   final Action pauseReceiverButtonAction;
   final Action playReceiverButtonAction;
   final Action shutdownReceiverButtonAction;
+  final Action saveReceiversButtonAction;
   final Action restartReceiverButtonAction;
   private final Action showReceiverHelpAction;
   private final Action startAllAction;
@@ -279,6 +280,25 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
       Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S));
 
     shutdownReceiverButtonAction.setEnabled(false);
+
+    saveReceiversButtonAction =
+      new AbstractAction() {
+          public void actionPerformed(ActionEvent e) {
+            saveReceivers();
+          }
+        };
+
+    saveReceiversButtonAction.putValue(
+      Action.SHORT_DESCRIPTION,
+      "Save the current receiver configuration");
+    saveReceiversButtonAction.putValue(Action.NAME, "Save receivers");
+
+    saveReceiversButtonAction.putValue(
+      Action.SMALL_ICON, new ImageIcon(ChainsawIcons.FILE_SAVE_AS));
+    saveReceiversButtonAction.putValue(
+      Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_V));
+
+
     restartReceiverButtonAction =
         new AbstractAction() {
             public void actionPerformed(ActionEvent e) {
@@ -410,6 +430,13 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
      }
   }
 
+  private void saveReceivers() {
+    File saveConfigFile = SwingHelper.promptForFile(this, null, "Save receiver configuration XML file", false);
+    if (saveConfigFile != null) {
+      ReceiversHelper.getInstance().saveReceiverConfiguration(saveConfigFile);
+    }
+  }
+
   protected ReceiversTreeModel getReceiverTreeModel() {
     return ((ReceiversTreeModel) receiversTree.getModel());
   }
@@ -774,6 +801,8 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
       add(pauseReceiverButtonAction);
       add(restartReceiverButtonAction);
       add(shutdownReceiverButtonAction);
+      add(saveReceiversButtonAction);
+
       addSeparator();
 
       final Receiver r = getCurrentlySelectedReceiver();
@@ -846,6 +875,10 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
         new SmallButton(shutdownReceiverButtonAction);
       shutdownReceiverButton.setText(null);
 
+      SmallButton saveReceiversButton =
+        new SmallButton(saveReceiversButtonAction);
+      saveReceiversButton.setText(null);
+
       SmallButton restartAllButton = new SmallButton(startAllAction);
       restartAllButton.setText(null);
       
@@ -862,6 +895,7 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
 
       add(restartReceiverButton);
       add(shutdownReceiverButton);
+      add(saveReceiversButton);
 
       addSeparator();
 


[50/50] [abbrv] logging-chainsaw git commit: Do not require a dateformat if not needed

Posted by rg...@apache.org.
Do not require a dateformat if not needed


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/025d756a
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/025d756a
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/025d756a

Branch: refs/heads/master
Commit: 025d756a68e29afde367e2139f2c6ce78118b714
Parents: c52dd71
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Nov 20 14:26:16 2014 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Nov 20 14:26:16 2014 +0000

----------------------------------------------------------------------
 .../chainsaw/vfs/VFSLogFilePatternReceiver.java | 37 +++++++++++---------
 .../log4j/varia/LogFilePatternReceiver.java     | 21 ++++++-----
 2 files changed, 33 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/025d756a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
index 1d7acc0..a0fc0d8 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
@@ -355,18 +355,20 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                     	getLogger().warn("JSch not on classpath!", ncdfe);
                     }
 
-                    fileObject = fileSystemManager.resolveFile(getFileURL(), opts);
-                    if (fileObject.exists()) {
-                        reader = new InputStreamReader(fileObject.getContent().getInputStream() , "UTF-8");
-                        //now that we have a reader, remove additional portions of the file url (sftp passwords, etc.)
-                        //check to see if the name is a URLFileName..if so, set file name to not include username/pass
-                        if (fileObject.getName() instanceof URLFileName) {
-                            URLFileName urlFileName = (URLFileName) fileObject.getName();
-                            setHost(urlFileName.getHostName());
-                            setPath(urlFileName.getPath());
+					synchronized(fileSystemManager) {
+                        fileObject = fileSystemManager.resolveFile(getFileURL(), opts);
+                        if (fileObject.exists()) {
+                            reader = new InputStreamReader(fileObject.getContent().getInputStream() , "UTF-8");
+                            //now that we have a reader, remove additional portions of the file url (sftp passwords, etc.)
+                            //check to see if the name is a URLFileName..if so, set file name to not include username/pass
+                            if (fileObject.getName() instanceof URLFileName) {
+                                URLFileName urlFileName = (URLFileName) fileObject.getName();
+                                setHost(urlFileName.getHostName());
+                                setPath(urlFileName.getPath());
+                            }
+                        } else {
+                            getLogger().info(loggableFileURL + " not available - will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis");
                         }
-                    } else {
-                        getLogger().info(loggableFileURL + " not available - will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis");
                     }
                 } catch (FileSystemException fse) {
                     getLogger().info(loggableFileURL + " not available - may be due to incorrect credentials, but will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis", fse);
@@ -404,12 +406,15 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                         }
 
                         //fileobject was created above, release it and construct a new one
-                        if (fileObject != null) {
-                            fileObject.getFileSystem().getFileSystemManager().closeFileSystem(fileObject.getFileSystem());
-                            fileObject.close();
-                            fileObject = null;
+						synchronized(fileSystemManager) {
+	                        if (fileObject != null) {
+	                              fileObject.getFileSystem().getFileSystemManager().closeFileSystem(fileObject.getFileSystem());
+	                              fileObject.close();
+	                              fileObject = null;
+                            }
+                        
+                        	fileObject = fileSystemManager.resolveFile(getFileURL(), opts);
                         }
-                        fileObject = fileSystemManager.resolveFile(getFileURL(), opts);
 
                         //file may not exist..
                         boolean fileLarger = false;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/025d756a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index 3a39508..1c2e30c 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -173,7 +173,7 @@ public class LogFilePatternReceiver extends Receiver {
   private final String[] emptyException = new String[] { "" };
 
   private SimpleDateFormat dateFormat;
-  private String timestampFormat = "yyyy-MM-d HH:mm:ss,SSS";
+  private String timestampFormat;
   private String logFormat;
   private String customLevelDefinitions;
   private String fileURL;
@@ -357,7 +357,7 @@ public class LogFilePatternReceiver extends Receiver {
     /**
    * Accessor
    *
-   * @return timestamp format
+   * @return group
    */
   public String getGroup() { return group; }
     
@@ -481,7 +481,7 @@ public class LogFilePatternReceiver extends Receiver {
     if (currentMap.size() == 0) {
       if (additionalLines.size() > 0) {
         for (Iterator iter = additionalLines.iterator();iter.hasNext();) {
-          getLogger().info("found non-matching line: " + iter.next());
+          getLogger().debug("found non-matching line: " + iter.next());
         }
       }
       additionalLines.clear();
@@ -625,11 +625,14 @@ public class LogFilePatternReceiver extends Receiver {
    */
   private String convertTimestamp() {
     //some locales (for example, French) generate timestamp text with characters not included in \w -
-    // now using \S (all non-whitespace characters) instead of /w 
-    String result = timestampFormat.replaceAll(Pattern.quote("+"), "[+]");
-    result = result.replaceAll(VALID_DATEFORMAT_CHAR_PATTERN, "\\\\S+");
-    //make sure dots in timestamp are escaped
-    result = result.replaceAll(Pattern.quote("."), "\\\\.");
+    // now using \S (all non-whitespace characters) instead of /w
+    String result = "";
+    if (timestampFormat != null) {
+      result = timestampFormat.replaceAll(Pattern.quote("+"), "[+]");
+      result = result.replaceAll(VALID_DATEFORMAT_CHAR_PATTERN, "\\\\S+");
+      //make sure dots in timestamp are escaped
+      result = result.replaceAll(Pattern.quote("."), "\\\\.");
+    }
     return result;
   }
 
@@ -929,7 +932,7 @@ public class LogFilePatternReceiver extends Receiver {
         e.printStackTrace();
       }
     }
-    //use current time if timestamp not parseable
+    //use current time if timestamp not parseable/dateformat not specified
     if (timeStamp == 0L) {
       timeStamp = System.currentTimeMillis();
     }


[34/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Log4JULogger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Log4JULogger.java b/src/main/java/org/apache/log4j/spi/Log4JULogger.java
new file mode 100644
index 0000000..2476810
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Log4JULogger.java
@@ -0,0 +1,229 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.ULogger;
+import org.apache.log4j.helpers.MessageFormatter;
+import org.apache.log4j.Level;
+
+
+/**
+ * An implementation of ULogger on org.apache.log4j.Logger.
+ */
+public final class Log4JULogger implements ULogger {
+
+    /**
+     * Wrapped log4j logger.
+     */
+    private final Logger logger;
+
+    /**
+     * Create a new instance.
+     *
+     * @param l logger, may not be null.
+     */
+    public Log4JULogger(final Logger l) {
+        super();
+        if (l == null) {
+            throw new NullPointerException("l");
+        }
+        logger = l;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDebugEnabled() {
+        return logger.isDebugEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg) {
+        logger.debug(msg);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object parameterizedMsg,
+                      final Object param1) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        if (logger.isDebugEnabled()) {
+            logger.debug(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg,
+                      final Throwable t) {
+        logger.debug(msg, t);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInfoEnabled() {
+        return logger.isInfoEnabled();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg) {
+        logger.info(msg);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object parameterizedMsg,
+                     final Object param1) {
+        if (logger.isInfoEnabled()) {
+            logger.info(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        if (logger.isInfoEnabled()) {
+            logger.info(MessageFormatter.format(
+                    parameterizedMsg.toString(),
+                    param1,
+                    param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg, final Throwable t) {
+        logger.info(msg, t);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isWarnEnabled() {
+        return logger.isEnabledFor(Level.WARN);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg) {
+        logger.warn(msg);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object parameterizedMsg,
+                     final Object param1) {
+        if (logger.isEnabledFor(Level.WARN)) {
+            logger.warn(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        if (logger.isEnabledFor(Level.WARN)) {
+            logger.warn(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg, final Throwable t) {
+        logger.warn(msg, t);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isErrorEnabled() {
+        return logger.isEnabledFor(Level.ERROR);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg) {
+        logger.error(msg);
+    }
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object parameterizedMsg, final Object param1) {
+        if (logger.isEnabledFor(Level.ERROR)) {
+            logger.error(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        if (logger.isEnabledFor(Level.ERROR)) {
+            logger.error(MessageFormatter.format(
+                    parameterizedMsg.toString(), param1, param2));
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg, final Throwable t) {
+        logger.error(msg, t);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/LoggerEventListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/LoggerEventListener.java b/src/main/java/org/apache/log4j/spi/LoggerEventListener.java
new file mode 100644
index 0000000..b39f728
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/LoggerEventListener.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Logger;
+
+
+/**
+  Interface used to listen for Logger related events such as
+  add/remove appender or changing levels.  Clients register an instance of
+  the interface and the instance is called back when the various events occur.
+
+  LoggerRepository provides methods for adding and removing
+  LoggerEventListener instances.
+
+  When implementing the methods of this interface, it is useful to remember
+  that the Logger can access the repository using its getRepository()
+  method.
+
+  @author Ceki G&uuml;lc&uuml;
+  @author Mark Womack
+*/
+public interface LoggerEventListener {
+  /**
+    Called when an appender is added to the logger.
+
+    @param logger The logger to which the appender was added.
+    @param appender The appender added to the logger. */
+  void appenderAddedEvent(Logger logger, Appender appender);
+
+  /**
+    Called when an appender is removed from the logger.
+
+    @param logger The logger from which the appender was removed.
+    @param appender The appender removed from the logger. */
+  void appenderRemovedEvent(Logger logger, Appender appender);
+
+  /**
+    Called when level changed on the logger.
+
+    @param logger The logger that changed levels. */
+  void levelChangedEvent(Logger logger);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java b/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java
new file mode 100644
index 0000000..773a497
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/LoggerRepositoryEventListener.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+
+/**
+  Interface used to listen for LoggerRepository related
+  events such as startup, reset, and shutdown.  Clients register
+  an instance of the interface and the instance is called back
+  when the various events occur.
+
+  LoggerRepository provides methods for adding and removing
+  LoggerRepositoryEventListener instances.
+
+  @author Ceki G&uuml;lc&uuml;
+  @author Mark Womack
+*/
+public interface LoggerRepositoryEventListener {
+  /**
+    Called when the repository configuration is reset.
+   @param repository repository
+   */
+  void configurationResetEvent(LoggerRepository repository);
+
+  /**
+    Called when the repository configuration is changed.
+   @param repository repository
+   */
+  void configurationChangedEvent(LoggerRepository repository);
+
+  /**
+    Called when the repository is shutdown. When this method is
+    invoked, the repository is still valid (ie it has not been
+    shutdown, but will be after this method returns).
+    @param repository repository.
+   */
+  void shutdownEvent(LoggerRepository repository);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java b/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java
new file mode 100644
index 0000000..c079a2c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/LoggerRepositoryEx.java
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.scheduler.Scheduler;
+
+import java.util.List;
+import java.util.Map;
+
+
+/**
+   A <code>LoggerRepository</code> is used to create and retrieve
+   <code>Loggers</code>. The relation between loggers in a repository
+   depends on the repository but typically loggers are arranged in a
+   named hierarchy.
+
+   <p>In addition to the creational methods, a
+   <code>LoggerRepository</code> can be queried for existing loggers,
+   can act as a point of registry for events related to loggers.
+
+   @author Ceki G&uuml;lc&uuml;
+   @author Mark Womack
+   @author Curt Arnold
+   */
+public interface LoggerRepositoryEx extends LoggerRepository {
+  /**
+    Add a {@link LoggerRepositoryEventListener} to the repository. The
+    listener will be called when repository events occur.
+     @param listener event listener, may not be null.
+    */
+  void addLoggerRepositoryEventListener(
+    LoggerRepositoryEventListener listener);
+
+  /**
+    Remove a {@link LoggerRepositoryEventListener} from the repository.
+   @param listener listener.
+    */
+  void removeLoggerRepositoryEventListener(
+    LoggerRepositoryEventListener listener);
+
+  /**
+    Add a {@link LoggerEventListener} to the repository. The  listener
+    will be called when repository events occur.
+   @param listener listener, may not be null.
+    */
+  void addLoggerEventListener(LoggerEventListener listener);
+
+  /**
+    Remove a {@link LoggerEventListener} from the repository.
+   @param listener listener, may not be null.
+    */
+  void removeLoggerEventListener(LoggerEventListener listener);
+
+  /**
+   * Get the name of this logger repository.
+   * @return name, may not be null.
+   */
+  String getName();
+
+  /**
+   * A logger repository is a named entity.
+   * @param repoName new name, may not be null.
+   */
+  void setName(String repoName);
+
+  /**
+   * Is the current configuration of the repository in its original (pristine)
+   * state?
+   * @return true if repository is in original state.
+   *
+   */
+  boolean isPristine();
+
+  /**
+   *  Set the pristine flag.
+   * @param state state
+   *  @see #isPristine
+   */
+  void setPristine(boolean state);
+
+  /**
+    Requests that a appender removed event be sent to any registered
+    {@link LoggerEventListener}.
+    @param logger The logger from which the appender was removed.
+    @param appender The appender removed from the logger.
+    */
+  void fireRemoveAppenderEvent(Category logger, Appender appender);
+
+  /**
+    Requests that a level changed event be sent to any registered
+    {@link LoggerEventListener}.
+    @param logger The logger which changed levels.
+    */
+  void fireLevelChangedEvent(Logger logger);
+
+  /**
+    Requests that a configuration changed event be sent to any registered
+    {@link LoggerRepositoryEventListener}.
+    */
+  void fireConfigurationChangedEvent();
+
+  /**
+   * Return the PluginRegisty for this LoggerRepository.
+   * @return plug in registry.
+   */
+  PluginRegistry getPluginRegistry();
+
+  /**
+   * Return the {@link Scheduler} for this LoggerRepository.
+   * @return scheduler.
+   */
+  Scheduler getScheduler();
+
+  /**
+   * Get the properties specific for this repository.
+   * @return property map.
+   */
+  Map getProperties();
+
+  /**
+   * Get the property of this repository.
+   * @param key property key.
+   * @return key value or null if not set.
+   */
+  String getProperty(String key);
+
+  /**
+   * Set a property of this repository.
+   * @param key key, may not be null.
+   * @param value new value, if null, property will be removed.
+   */
+  void setProperty(String key, String value);
+
+  /**
+   * Errors which cannot be logged, go to the error list.
+   *
+   * @return List
+   */
+  List getErrorList();
+
+  /**
+   * Errors which cannot be logged, go to the error list.
+   *
+   * @param errorItem an ErrorItem to add to the error list
+   */
+  void addErrorItem(ErrorItem errorItem);
+
+  /**
+   * A LoggerRepository can also act as a store for various objects used
+   * by log4j components.
+   *
+   * @param key key, may not be null.
+   * @return The object stored under 'key'.
+   */
+  Object getObject(String key);
+
+  /**
+   * Store an object under 'key'. If no object can be found, null is returned.
+   *
+   * @param key key, may not be null.
+   * @param value value, may be null.
+   */
+  void putObject(String key, Object value);
+
+  /**
+   * Sets the logger factory used by LoggerRepository.getLogger(String).
+   * @param loggerFactory factory to use, may not be null
+   */
+  void setLoggerFactory(LoggerFactory loggerFactory);
+
+  /**
+   * Returns the logger factory used by
+   * LoggerRepository.getLogger(String).
+   *
+   * @return non-null factory
+   */
+  LoggerFactory getLoggerFactory();
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/NOPULogger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/NOPULogger.java b/src/main/java/org/apache/log4j/spi/NOPULogger.java
new file mode 100644
index 0000000..98fe537
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/NOPULogger.java
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.ULogger;
+
+
+/**
+ * A no operation (NOP) implementation of {@link ULogger}.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public final class NOPULogger implements ULogger {
+
+    /**
+     * The unique instance of NOPLogger.
+     */
+    public static final NOPULogger NOP_LOGGER = new NOPULogger();
+
+    /**
+     * There is no point in people creating multiple instances of NullLogger.
+     * Hence, the private access modifier.
+     */
+    private NOPULogger() {
+        super();
+    }
+
+    /**
+     * Get instance.
+     * @param name logger name.
+     * @return logger.
+     */
+    public static NOPULogger getLogger(final String name) {
+        return NOP_LOGGER;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isDebugEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void debug(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isInfoEnabled() {
+        // NOP
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final String parameterizedMsg,
+                     final Object param1, final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void info(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isWarnEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object parameterizedMsg,
+                     final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final String parameterizedMsg,
+                     final Object param1,
+                     final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void warn(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean isErrorEnabled() {
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object parameterizedMsg, final Object param1) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final String parameterizedMsg,
+                      final Object param1,
+                      final Object param2) {
+        // NOP
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void error(final Object msg, final Throwable t) {
+        // NOP
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/SimpleULogger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/SimpleULogger.java b/src/main/java/org/apache/log4j/spi/SimpleULogger.java
new file mode 100644
index 0000000..714a57a
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/SimpleULogger.java
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.ULogger;
+import org.apache.log4j.helpers.MessageFormatter;
+
+
+/**
+ * A simple implementation that logs messages of level INFO or higher on
+ * the console (<code>System.out</code>).
+ * <p>
+ * The output includes the relative time in milliseconds, thread name, level,
+ * logger name, and the message followed by the line separator for the host.
+ * In log4j terms it amounts to the "%r  [%t] %level %logger - %m%n" pattern.
+ * <pre>
+176 [main] INFO examples.Sort - Populating an array of 2 elements in reverse.
+225 [main] INFO examples.SortAlgo - Entered the sort method.
+304 [main] INFO SortAlgo.DUMP - Dump of interger array:
+317 [main] INFO SortAlgo.DUMP - Element [0] = 0
+331 [main] INFO SortAlgo.DUMP - Element [1] = 1
+343 [main] INFO examples.Sort - The next log statement should be an error msg.
+346 [main] ERROR SortAlgo.DUMP - Tried to dump an uninitialized array.
+        at org.log4j.examples.SortAlgo.dump(SortAlgo.java:58)
+        at org.log4j.examples.Sort.main(Sort.java:64)
+467 [main] INFO  examples.Sort - Exiting main method.
+</pre>
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public final class SimpleULogger implements ULogger {
+
+    /**
+     * Logger name.
+     */
+  private final String loggerName;
+
+
+  /**
+   * Mark the time when this class gets loaded into memory.
+   */
+  private static long startTime = System.currentTimeMillis();
+
+    /**
+     * Line separator.
+     */
+  public static final String LINE_SEPARATOR
+            = System.getProperty("line.separator");
+
+    /**
+     * INFO string literal.
+     */
+  private static final String INFO_STR = "INFO";
+    /**
+     * WARN string literal.
+     */
+  private static final String WARN_STR = "WARN";
+    /**
+     * ERROR string literal.
+     */
+  private static final String ERROR_STR = "ERROR";
+
+  /**
+   * Constructor is private to force construction through getLogger.
+   * @param name logger name
+   */
+  private SimpleULogger(final String name) {
+    super();
+    this.loggerName = name;
+  }
+
+  /**
+   * Creates a new instance.
+   *
+   * @param name logger name
+   * @return  logger.
+   */
+  public static SimpleULogger getLogger(final String name) {
+      return new SimpleULogger(name);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isDebugEnabled() {
+    return false;
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void debug(final Object msg) {
+    // NOP
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void debug(final Object parameterizedMsg, final Object param1) {
+    // NOP
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void debug(final String parameterizedMsg,
+                    final Object param1,
+                    final Object param2) {
+    // NOP
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void debug(final Object msg, final Throwable t) {
+    // NOP
+  }
+
+  /**
+   * This is our internal implementation for logging regular (non-parameterized)
+   * log messages.
+   *
+   * @param level level
+   * @param message message
+   * @param t throwable
+   */
+  private void log(final String level,
+                   final String message,
+                   final Throwable t) {
+    StringBuffer buf = new StringBuffer();
+
+    long millis  = System.currentTimeMillis();
+    buf.append(millis - startTime);
+
+    buf.append(" [");
+    buf.append(Thread.currentThread().getName());
+    buf.append("] ");
+
+    buf.append(level);
+    buf.append(" ");
+
+    buf.append(loggerName);
+    buf.append(" - ");
+
+    buf.append(message);
+
+    buf.append(LINE_SEPARATOR);
+
+    System.out.print(buf.toString());
+    if (t != null) {
+      t.printStackTrace(System.out);
+    }
+    System.out.flush();
+  }
+  /**
+   * For parameterized messages, first substitute parameters and then log.
+   *
+   * @param level level
+   * @param parameterizedMsg message pattern
+   * @param param1 param1
+   * @param param2 param2
+   */
+  private void parameterizedLog(final String level,
+                                final Object parameterizedMsg,
+                                final Object param1,
+                                final Object param2) {
+    if (parameterizedMsg instanceof String) {
+      String msgStr = (String) parameterizedMsg;
+      msgStr = MessageFormatter.format(msgStr, param1, param2);
+      log(level, msgStr, null);
+    } else {
+      // To be failsafe, we handle the case where 'messagePattern' is not
+      // a String. Unless the user makes a mistake, this should not happen.
+      log(level, parameterizedMsg.toString(), null);
+    }
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public boolean isInfoEnabled() {
+    return true;
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void info(final Object msg) {
+    log(INFO_STR, msg.toString(), null);
+  }
+
+
+    /**
+     * {@inheritDoc}
+     */
+  public void info(final Object parameterizedMsg, final Object param1) {
+    parameterizedLog(INFO_STR, parameterizedMsg, param1, null);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void info(final String parameterizedMsg,
+                   final Object param1,
+                   final Object param2) {
+    parameterizedLog(INFO_STR, parameterizedMsg, param1, param2);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void info(final Object msg, final Throwable t) {
+    log(INFO_STR, msg.toString(), t);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public boolean isWarnEnabled() {
+    return true;
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void warn(final Object msg) {
+    log(WARN_STR, msg.toString(), null);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void warn(final Object parameterizedMsg, final Object param1) {
+    parameterizedLog(WARN_STR, parameterizedMsg, param1, null);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void warn(final String parameterizedMsg,
+                   final Object param1,
+                   final Object param2) {
+    parameterizedLog(WARN_STR, parameterizedMsg, param1, param2);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void warn(final Object msg, final Throwable t) {
+    log(WARN_STR, msg.toString(), t);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public boolean isErrorEnabled() {
+    return true;
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void error(final Object msg) {
+    log(ERROR_STR, msg.toString(), null);
+  }
+
+
+    /**
+     * {@inheritDoc}
+     */
+  public void error(final Object parameterizedMsg, final Object param1) {
+    parameterizedLog(ERROR_STR, parameterizedMsg, param1, null);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void error(final String parameterizedMsg,
+                    final Object param1,
+                    final Object param2) {
+    parameterizedLog(ERROR_STR, parameterizedMsg, param1, param2);
+  }
+
+    /**
+     * {@inheritDoc}
+     */
+  public void error(final Object msg, final Throwable t) {
+    log(ERROR_STR, msg.toString(), t);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Thresholdable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Thresholdable.java b/src/main/java/org/apache/log4j/spi/Thresholdable.java
new file mode 100644
index 0000000..222345f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Thresholdable.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import org.apache.log4j.Level;
+
+/**
+ * An interface that defines the required methods for supporting the
+ * setting and getting of a level threshold.  Components should implement
+ * this interface if logging events they process should meet a certain
+ * threshold before being processed further.  Examples of this are
+ * Appenders and Receivers which will not process logging events unless
+ * the event level is at or greater than a set threshold level.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ * @author Mark Womack
+ */
+public interface Thresholdable {
+    /**
+     * Sets the component theshold to the given level.
+     *
+     * @param level The threshold level events must equal or be greater
+     *              than before further processing can be done.
+     */
+    void setThreshold(Level level);
+
+    /**
+     * Gets the current threshold setting of the component.
+     *
+     * @return Level The current threshold level of the component.
+     */
+    Level getThreshold();
+
+    /**
+     * Returns true if the given level is equals or greater than the current
+     * threshold value of the component.
+     *
+     * @param level The level to test against the component threshold.
+     * @return boolean True if level is equal or greater than the
+     *         component threshold.
+     */
+    boolean isAsSevereAsThreshold(Level level);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/varia/ListModelAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/ListModelAppender.java b/src/main/java/org/apache/log4j/varia/ListModelAppender.java
new file mode 100644
index 0000000..ccbc9be
--- /dev/null
+++ b/src/main/java/org/apache/log4j/varia/ListModelAppender.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.varia;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.spi.LoggingEvent;
+
+import javax.swing.DefaultListModel;
+import javax.swing.ListModel;
+
+
+/**
+ * A very basic appender that takes the events and stores them in to a
+ * ListModel for late retrieval.
+ *
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public final class ListModelAppender extends AppenderSkeleton {
+    /**
+     * Default list model.
+     */
+  private final DefaultListModel model = new DefaultListModel();
+
+  /**
+   * Constructs a ListModelAppender.
+   */
+  public ListModelAppender() {
+      super(true);
+  }
+  /**
+   * Returns a reference to the ListModel that contains all the LoggingEvents
+   * that have been appended to this class.
+   *
+   * @return the list model
+   */
+  public ListModel getModel() {
+    return model;
+  }
+
+    /** {@inheritDoc} */
+  protected void append(final LoggingEvent event) {
+    model.addElement(event);
+  }
+
+    /** {@inheritDoc} */
+  public void close() {
+    clearModel();
+  }
+
+  /**
+   * Removes all the Events from the model.
+   */
+  public void clearModel() {
+    model.clear();
+  }
+
+    /** {@inheritDoc} */
+  public boolean requiresLayout() {
+      return false;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
new file mode 100644
index 0000000..4430205
--- /dev/null
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -0,0 +1,1043 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.varia;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.regex.MatchResult;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.rule.ExpressionRule;
+import org.apache.log4j.rule.Rule;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+
+/**
+ * LogFilePatternReceiver can parse and tail log files, converting entries into
+ * LoggingEvents.  If the file doesn't exist when the receiver is initialized, the
+ * receiver will look for the file once every 10 seconds.
+ * <p>
+ * This receiver relies on java.util.regex features to perform the parsing of text in the
+ * log file, however the only regular expression field explicitly supported is 
+ * a glob-style wildcard used to ignore fields in the log file if needed.  All other
+ * fields are parsed by using the supplied keywords.
+ * <p>
+ * <b>Features:</b><br>
+ * - specify the URL of the log file to be processed<br>
+ * - specify the timestamp format in the file (if one exists, using patterns from {@link java.text.SimpleDateFormat})<br>
+ * - specify the pattern (logFormat) used in the log file using keywords, a wildcard character (*) and fixed text<br>
+ * - 'tail' the file (allows the contents of the file to be continually read and new events processed)<br>
+ * - supports the parsing of multi-line messages and exceptions
+ * - 'hostname' property set to URL host (or 'file' if not available)
+ * - 'application' property set to URL path (or value of fileURL if not available) 
+ *<p>
+ * <b>Keywords:</b><br>
+ * TIMESTAMP<br>
+ * LOGGER<br>
+ * LEVEL<br>
+ * THREAD<br>
+ * CLASS<br>
+ * FILE<br>
+ * LINE<br>
+ * METHOD<br>
+ * RELATIVETIME<br>
+ * MESSAGE<br>
+ * NDC<br>
+ * PROP(key)<br>
+ * <p>
+ * Use a * to ignore portions of the log format that should be ignored
+ * <p>
+ * Example:<br>
+ * If your file's patternlayout is this:<br>
+ * <b>%d %-5p [%t] %C{2} (%F:%L) - %m%n</b>
+ *<p>
+ * specify this as the log format:<br>
+ * <b>TIMESTAMP LEVEL [THREAD] CLASS (FILE:LINE) - MESSAGE</b>
+ *<p>
+ * To define a PROPERTY field, use PROP(key)
+ * <p>
+ * Example:<br> 
+ * If you used the RELATIVETIME pattern layout character in the file, 
+ * you can use PROP(RELATIVETIME) in the logFormat definition to assign 
+ * the RELATIVETIME field as a property on the event.
+ * <p>
+ * If your file's patternlayout is this:<br>
+ * <b>%r [%t] %-5p %c %x - %m%n</b>
+ *<p>
+ * specify this as the log format:<br>
+ * <b>PROP(RELATIVETIME) [THREAD] LEVEL LOGGER * - MESSAGE</b>
+ * <p>
+ * Note the * - it can be used to ignore a single word or sequence of words in the log file
+ * (in order for the wildcard to ignore a sequence of words, the text being ignored must be
+ *  followed by some delimiter, like '-' or '[') - ndc is being ignored in the following example.
+ * <p>
+ * Assign a filterExpression in order to only process events which match a filter.
+ * If a filterExpression is not assigned, all events are processed.
+ *<p>
+ * <b>Limitations:</b><br>
+ * - no support for the single-line version of throwable supported by patternlayout<br>
+ *   (this version of throwable will be included as the last line of the message)<br>
+ * - the relativetime patternLayout character must be set as a property: PROP(RELATIVETIME)<br>
+ * - messages should appear as the last field of the logFormat because the variability in message content<br>
+ * - exceptions are converted if the exception stack trace (other than the first line of the exception)<br>
+ *   is stored in the log file with a tab followed by the word 'at' as the first characters in the line<br>
+ * - tailing may fail if the file rolls over. 
+ *<p>
+ * <b>Example receiver configuration settings</b> (add these as params, specifying a LogFilePatternReceiver 'plugin'):<br>
+ * param: "timestampFormat" value="yyyy-MM-d HH:mm:ss,SSS"<br>
+ * param: "logFormat" value="PROP(RELATIVETIME) [THREAD] LEVEL LOGGER * - MESSAGE"<br>
+ * param: "fileURL" value="file:///c:/events.log"<br>
+ * param: "tailing" value="true"
+ *<p>
+ * This configuration will be able to process these sample events:<br>
+ * 710    [       Thread-0] DEBUG                   first.logger first - <test>   <test2>something here</test2>   <test3 blah=something/>   <test4>       <test5>something else</test5>   </test4></test><br>
+ * 880    [       Thread-2] DEBUG                   first.logger third - <test>   <test2>something here</test2>   <test3 blah=something/>   <test4>       <test5>something else</test5>   </test4></test><br>
+ * 880    [       Thread-0] INFO                    first.logger first - infomsg-0<br>
+ * java.lang.Exception: someexception-first<br>
+ *     at Generator2.run(Generator2.java:102)<br>
+ *
+ *@author Scott Deboy
+ */
+public class LogFilePatternReceiver extends Receiver {
+  private final List keywords = new ArrayList();
+
+  private static final String PROP_START = "PROP(";
+  private static final String PROP_END = ")";
+
+  private static final String LOGGER = "LOGGER";
+  private static final String MESSAGE = "MESSAGE";
+  private static final String TIMESTAMP = "TIMESTAMP";
+  private static final String NDC = "NDC";
+  private static final String LEVEL = "LEVEL";
+  private static final String THREAD = "THREAD";
+  private static final String CLASS = "CLASS";
+  private static final String FILE = "FILE";
+  private static final String LINE = "LINE";
+  private static final String METHOD = "METHOD";
+  
+  private static final String DEFAULT_HOST = "file";
+  
+  //all lines other than first line of exception begin with tab followed by 'at' followed by text
+  private static final String EXCEPTION_PATTERN = "^\\s+at.*";
+  private static final String REGEXP_DEFAULT_WILDCARD = ".*?";
+  private static final String REGEXP_GREEDY_WILDCARD = ".*";
+  private static final String PATTERN_WILDCARD = "*";
+  private static final String NOSPACE_GROUP = "(\\S*\\s*?)";
+  private static final String DEFAULT_GROUP = "(" + REGEXP_DEFAULT_WILDCARD + ")";
+  private static final String GREEDY_GROUP = "(" + REGEXP_GREEDY_WILDCARD + ")";
+  private static final String MULTIPLE_SPACES_REGEXP = "[ ]+";
+  private final String newLine = System.getProperty("line.separator");
+
+  private final String[] emptyException = new String[] { "" };
+
+  private SimpleDateFormat dateFormat;
+  private String timestampFormat = "yyyy-MM-d HH:mm:ss,SSS";
+  private String logFormat;
+  private String customLevelDefinitions;
+  private String fileURL;
+  private String host;
+  private String path;
+  private boolean tailing;
+  private String filterExpression;
+  private long waitMillis = 2000; //default 2 seconds
+
+  private static final String VALID_DATEFORMAT_CHARS = "GyMwWDdFEaHkKhmsSzZ";
+  private static final String VALID_DATEFORMAT_CHAR_PATTERN = "[" + VALID_DATEFORMAT_CHARS + "]";
+
+  private Rule expressionRule;
+
+  private Map currentMap;
+  private List additionalLines;
+  private List matchingKeywords;
+
+  private String regexp;
+  private Reader reader;
+  private Pattern regexpPattern;
+  private Pattern exceptionPattern;
+  private String timestampPatternText;
+
+  private boolean useCurrentThread;
+  public static final int MISSING_FILE_RETRY_MILLIS = 10000;
+  private boolean appendNonMatches;
+  private final Map customLevelDefinitionMap = new HashMap();
+
+    public LogFilePatternReceiver() {
+    keywords.add(TIMESTAMP);
+    keywords.add(LOGGER);
+    keywords.add(LEVEL);
+    keywords.add(THREAD);
+    keywords.add(CLASS);
+    keywords.add(FILE);
+    keywords.add(LINE);
+    keywords.add(METHOD);
+    keywords.add(MESSAGE);
+    keywords.add(NDC);
+    try {
+        exceptionPattern = Pattern.compile(EXCEPTION_PATTERN);
+    } catch (PatternSyntaxException pse) {
+        //shouldn't happen
+    }
+  }
+
+  /**
+   * Accessor
+   * 
+   * @return file URL
+   */
+  public String getFileURL() {
+    return fileURL;
+  }
+
+  /**
+   * Mutator
+   * 
+   * @param fileURL
+   */
+  public void setFileURL(String fileURL) {
+    this.fileURL = fileURL;
+  }
+
+    /**
+     * If the log file contains non-log4j level strings, they can be mapped to log4j levels using the format (android example):
+     * V=TRACE,D=DEBUG,I=INFO,W=WARN,E=ERROR,F=FATAL,S=OFF
+     *
+     * @param customLevelDefinitions the level definition string
+     */
+  public void setCustomLevelDefinitions(String customLevelDefinitions) {
+    this.customLevelDefinitions = customLevelDefinitions;
+  }
+
+  public String getCustomLevelDefinitions() {
+    return customLevelDefinitions;
+  }
+
+  /**
+   * Accessor
+   * @return append non matches
+   */
+  public boolean isAppendNonMatches() {
+      return appendNonMatches;
+  }
+
+  /**
+   * Mutator
+   * @param appendNonMatches
+   */
+  public void setAppendNonMatches(boolean appendNonMatches) {
+      this.appendNonMatches = appendNonMatches;
+  }
+
+  /**
+   * Accessor
+   * 
+   * @return filter expression
+   */
+  public String getFilterExpression() {
+    return filterExpression;
+  }
+
+  /**
+   * Mutator
+   * 
+   * @param filterExpression
+   */
+  public void setFilterExpression(String filterExpression) {
+    this.filterExpression = filterExpression;
+  }
+
+  /**
+   * Accessor
+   * 
+   * @return tailing
+   */
+  public boolean isTailing() {
+    return tailing;
+  }
+
+  /**
+   * Mutator
+   * 
+   * @param tailing
+   */
+  public void setTailing(boolean tailing) {
+    this.tailing = tailing;
+  }
+
+  /**
+   * When true, this property uses the current Thread to perform the import,
+   * otherwise when false (the default), a new Thread is created and started to manage
+   * the import.
+   * @return
+   */ 
+ public final boolean isUseCurrentThread() {
+     return useCurrentThread;
+ }
+
+ /**
+  * Sets whether the current Thread or a new Thread is created to perform the import,
+  * the default being false (new Thread created).
+  * 
+  * @param useCurrentThread
+  */
+ public final void setUseCurrentThread(boolean useCurrentThread) {
+     this.useCurrentThread = useCurrentThread;
+ }
+
+  /**
+   * Accessor
+   * 
+   * @return log format
+   */
+  public String getLogFormat() {
+    return logFormat;
+  }
+
+    /**
+   * Mutator
+   *
+   * @param logFormat
+   *          the format
+   */
+  public void setLogFormat(String logFormat) {
+    this.logFormat = logFormat;
+  }
+
+    /**
+   * Mutator.  Specify a pattern from {@link java.text.SimpleDateFormat}
+   *
+   * @param timestampFormat
+   */
+  public void setTimestampFormat(String timestampFormat) {
+    this.timestampFormat = timestampFormat;
+  }
+
+    /**
+   * Accessor
+   *
+   * @return timestamp format
+   */
+  public String getTimestampFormat() {
+    return timestampFormat;
+  }
+
+  /**
+   * Accessor
+   * @return millis between retrieves of content
+   */
+  public long getWaitMillis() {
+    return waitMillis;
+  }
+
+  /**
+   * Mutator
+   * @param waitMillis
+   */
+  public void setWaitMillis(long waitMillis) {
+    this.waitMillis = waitMillis;
+  }
+
+    /**
+   * Walk the additionalLines list, looking for the EXCEPTION_PATTERN.
+   * <p>
+   * Return the index of the first matched line
+   * (the match may be the 1st line of an exception)
+   * <p>
+   * Assumptions: <br>
+   * - the additionalLines list may contain both message and exception lines<br>
+   * - message lines are added to the additionalLines list and then
+   * exception lines (all message lines occur in the list prior to all
+   * exception lines)
+   *
+   * @return -1 if no exception line exists, line number otherwise
+   */
+  private int getExceptionLine() {
+    for (int i = 0; i < additionalLines.size(); i++) {
+      Matcher exceptionMatcher = exceptionPattern.matcher((String)additionalLines.get(i));
+      if (exceptionMatcher.matches()) {
+        return i;
+      }
+    }
+    return -1;
+  }
+
+    /**
+   * Combine all message lines occuring in the additionalLines list, adding
+   * a newline character between each line
+   * <p>
+   * the event will already have a message - combine this message
+   * with the message lines in the additionalLines list
+   * (all entries prior to the exceptionLine index)
+   *
+   * @param firstMessageLine primary message line
+   * @param exceptionLine index of first exception line
+   * @return message
+   */
+  private String buildMessage(String firstMessageLine, int exceptionLine) {
+    if (additionalLines.size() == 0) {
+      return firstMessageLine;
+    }
+    StringBuffer message = new StringBuffer();
+    if (firstMessageLine != null) {
+      message.append(firstMessageLine);
+    }
+
+    int linesToProcess = (exceptionLine == -1?additionalLines.size(): exceptionLine);
+
+    for (int i = 0; i < linesToProcess; i++) {
+      message.append(newLine);
+      message.append(additionalLines.get(i));
+    }
+    return message.toString();
+  }
+
+    /**
+   * Combine all exception lines occuring in the additionalLines list into a
+   * String array
+   * <p>
+   * (all entries equal to or greater than the exceptionLine index)
+   *
+   * @param exceptionLine index of first exception line
+   * @return exception
+   */
+  private String[] buildException(int exceptionLine) {
+    if (exceptionLine == -1) {
+      return emptyException;
+    }
+    String[] exception = new String[additionalLines.size() - exceptionLine - 1];
+    for (int i = 0; i < exception.length; i++) {
+      exception[i] = (String) additionalLines.get(i + exceptionLine);
+    }
+    return exception;
+  }
+
+    /**
+   * Construct a logging event from currentMap and additionalLines
+   * (additionalLines contains multiple message lines and any exception lines)
+   * <p>
+   * CurrentMap and additionalLines are cleared in the process
+   *
+   * @return event
+   */
+  private LoggingEvent buildEvent() {
+    if (currentMap.size() == 0) {
+      if (additionalLines.size() > 0) {
+        for (Iterator iter = additionalLines.iterator();iter.hasNext();) {
+          getLogger().info("found non-matching line: " + iter.next());
+        }
+      }
+      additionalLines.clear();
+      return null;
+    }
+    //the current map contains fields - build an event
+    int exceptionLine = getExceptionLine();
+    String[] exception = buildException(exceptionLine);
+
+    //messages are listed before exceptions in additionallines
+    if (additionalLines.size() > 0 && exception.length > 0) {
+      currentMap.put(MESSAGE, buildMessage((String) currentMap.get(MESSAGE),
+          exceptionLine));
+    }
+    LoggingEvent event = convertToEvent(currentMap, exception);
+    currentMap.clear();
+    additionalLines.clear();
+    return event;
+  }
+
+    /**
+   * Read, parse and optionally tail the log file, converting entries into logging events.
+   *
+   * A runtimeException is thrown if the logFormat pattern is malformed.
+   *
+   * @param bufferedReader
+   * @throws IOException
+   */
+  protected void process(BufferedReader bufferedReader) throws IOException {
+        Matcher eventMatcher;
+        Matcher exceptionMatcher;
+        String line;
+        while ((line = bufferedReader.readLine()) != null) {
+            //skip empty line entries
+            eventMatcher = regexpPattern.matcher(line);
+            if (line.trim().equals("")) {continue;}
+            exceptionMatcher = exceptionPattern.matcher(line);
+            if (eventMatcher.matches()) {
+                //build an event from the previous match (held in current map)
+                LoggingEvent event = buildEvent();
+                if (event != null) {
+                    if (passesExpression(event)) {
+                        doPost(event);
+                    }
+                }
+                currentMap.putAll(processEvent(eventMatcher.toMatchResult()));
+            } else if (exceptionMatcher.matches()) {
+                //an exception line
+                additionalLines.add(line);
+            } else {
+                //neither...either post an event with the line or append as additional lines
+                //if this was a logging event with multiple lines, each line will show up as its own event instead of being
+                //appended as multiple lines on the same event..
+                //choice is to have each non-matching line show up as its own line, or append them all to a previous event
+                if (appendNonMatches) {
+                    //hold on to the previous time, so we can do our best to preserve time-based ordering if the event is a non-match
+                    String lastTime = (String)currentMap.get(TIMESTAMP);
+                    //build an event from the previous match (held in current map)
+                    if (currentMap.size() > 0) {
+                        LoggingEvent event = buildEvent();
+                        if (event != null) {
+                            if (passesExpression(event)) {
+                              doPost(event);
+                            }
+                        }
+                    }
+                    if (lastTime != null) {
+                        currentMap.put(TIMESTAMP, lastTime);
+                    }
+                    currentMap.put(MESSAGE, line);
+                } else {
+                    additionalLines.add(line);
+                }
+            }
+        }
+
+        //process last event if one exists
+        LoggingEvent event = buildEvent();
+        if (event != null) {
+            if (passesExpression(event)) {
+                doPost(event);
+            }
+        }
+    }
+
+    protected void createPattern() {
+        regexpPattern = Pattern.compile(regexp);
+    }
+
+    /**
+   * Helper method that supports the evaluation of the expression
+   *
+   * @param event
+   * @return true if expression isn't set, or the result of the evaluation otherwise
+   */
+  private boolean passesExpression(LoggingEvent event) {
+    if (event != null) {
+      if (expressionRule != null) {
+        return (expressionRule.evaluate(event, null));
+      }
+    }
+    return true;
+  }
+
+    /**
+   * Convert the match into a map.
+   * <p>
+   * Relies on the fact that the matchingKeywords list is in the same
+   * order as the groups in the regular expression
+   *
+   * @param result
+   * @return map
+   */
+  private Map processEvent(MatchResult result) {
+    Map map = new HashMap();
+    //group zero is the entire match - process all other groups
+    for (int i = 1; i < result.groupCount() + 1; i++) {
+      Object key = matchingKeywords.get(i - 1);
+      Object value = result.group(i);
+      map.put(key, value);
+
+    }
+    return map;
+  }
+
+    /**
+   * Helper method that will convert timestamp format to a pattern
+   *
+   *
+   * @return string
+   */
+  private String convertTimestamp() {
+    //some locales (for example, French) generate timestamp text with characters not included in \w -
+    // now using \S (all non-whitespace characters) instead of /w 
+    String result = timestampFormat.replaceAll(VALID_DATEFORMAT_CHAR_PATTERN + "+", "\\\\S+");
+    //make sure dots in timestamp are escaped
+    result = result.replaceAll(Pattern.quote("."), "\\\\.");
+    return result;
+  }
+
+    protected void setHost(String host) {
+	  this.host = host;
+  }
+
+    protected void setPath(String path) {
+	  this.path = path;
+  }
+
+  public String getPath() {
+      return path;
+  }
+
+    /**
+   * Build the regular expression needed to parse log entries
+   *
+   */
+  protected void initialize() {
+	if (host == null && path == null) {
+		try {
+			URL url = new URL(fileURL);
+			host = url.getHost();
+			path = url.getPath();
+		} catch (MalformedURLException e1) {
+			// TODO Auto-generated catch block
+			e1.printStackTrace();
+		}
+	}
+	if (host == null || host.trim().equals("")) {
+		host = DEFAULT_HOST;
+	}
+	if (path == null || path.trim().equals("")) {
+		path = fileURL;
+	}
+
+    currentMap = new HashMap();
+    additionalLines = new ArrayList();
+    matchingKeywords = new ArrayList();
+
+    if (timestampFormat != null) {
+      dateFormat = new SimpleDateFormat(quoteTimeStampChars(timestampFormat));
+      timestampPatternText = convertTimestamp();
+    }
+    //if custom level definitions exist, parse them
+    updateCustomLevelDefinitionMap();
+    try {
+      if (filterExpression != null) {
+        expressionRule = ExpressionRule.getRule(filterExpression);
+      }
+    } catch (Exception e) {
+      getLogger().warn("Invalid filter expression: " + filterExpression, e);
+    }
+
+    List buildingKeywords = new ArrayList();
+
+    String newPattern = logFormat;
+
+    int index = 0;
+    String current = newPattern;
+    //build a list of property names and temporarily replace the property with an empty string,
+    //we'll rebuild the pattern later
+    List propertyNames = new ArrayList();
+    while (index > -1) {
+        if (current.indexOf(PROP_START) > -1 && current.indexOf(PROP_END) > -1) {
+            index = current.indexOf(PROP_START);
+            String longPropertyName = current.substring(current.indexOf(PROP_START), current.indexOf(PROP_END) + 1);
+            String shortProp = getShortPropertyName(longPropertyName);
+            buildingKeywords.add(shortProp);
+            propertyNames.add(longPropertyName);
+            current = current.substring(longPropertyName.length() + 1 + index);
+            newPattern = singleReplace(newPattern, longPropertyName, new Integer(buildingKeywords.size() -1).toString());
+        } else {
+            //no properties
+            index = -1;
+        }
+    }
+
+    /*
+     * we're using a treemap, so the index will be used as the key to ensure
+     * keywords are ordered correctly
+     *
+     * examine pattern, adding keywords to an index-based map patterns can
+     * contain only one of these per entry...properties are the only 'keyword'
+     * that can occur multiple times in an entry
+     */
+    Iterator iter = keywords.iterator();
+    while (iter.hasNext()) {
+      String keyword = (String) iter.next();
+      int index2 = newPattern.indexOf(keyword);
+      if (index2 > -1) {
+        buildingKeywords.add(keyword);
+        newPattern = singleReplace(newPattern, keyword, new Integer(buildingKeywords.size() -1).toString());
+      }
+    }
+
+    String buildingInt = "";
+
+    for (int i=0;i<newPattern.length();i++) {
+        String thisValue = String.valueOf(newPattern.substring(i, i+1));
+        if (isInteger(thisValue)) {
+            buildingInt = buildingInt + thisValue;
+        } else {
+            if (isInteger(buildingInt)) {
+                matchingKeywords.add(buildingKeywords.get(Integer.parseInt(buildingInt)));
+            }
+            //reset
+            buildingInt = "";
+        }
+    }
+
+    //if the very last value is an int, make sure to add it
+    if (isInteger(buildingInt)) {
+        matchingKeywords.add(buildingKeywords.get(Integer.parseInt(buildingInt)));
+    }
+
+    newPattern = replaceMetaChars(newPattern);
+
+    //compress one or more spaces in the pattern into the [ ]+ regexp
+    //(supports padding of level in log files)
+    newPattern = newPattern.replaceAll(MULTIPLE_SPACES_REGEXP, MULTIPLE_SPACES_REGEXP);
+    newPattern = newPattern.replaceAll(Pattern.quote(PATTERN_WILDCARD), REGEXP_DEFAULT_WILDCARD);
+    //use buildingKeywords here to ensure correct order
+    for (int i = 0;i<buildingKeywords.size();i++) {
+      String keyword = (String) buildingKeywords.get(i);
+      //make the final keyword greedy (we're assuming it's the message)
+      if (i == (buildingKeywords.size() - 1)) {
+        newPattern = singleReplace(newPattern, String.valueOf(i), GREEDY_GROUP);
+      } else if (TIMESTAMP.equals(keyword)) {
+        newPattern = singleReplace(newPattern, String.valueOf(i), "(" + timestampPatternText + ")");
+      } else if (LOGGER.equals(keyword) || LEVEL.equals(keyword)) {
+        newPattern = singleReplace(newPattern, String.valueOf(i), NOSPACE_GROUP);
+      } else {
+        newPattern = singleReplace(newPattern, String.valueOf(i), DEFAULT_GROUP);
+      }
+    }
+
+    regexp = newPattern;
+    getLogger().debug("regexp is " + regexp);
+  }
+
+    private void updateCustomLevelDefinitionMap() {
+        if (customLevelDefinitions != null) {
+            StringTokenizer entryTokenizer = new StringTokenizer(customLevelDefinitions, ",");
+
+            customLevelDefinitionMap.clear();
+            while (entryTokenizer.hasMoreTokens()) {
+                StringTokenizer innerTokenizer = new StringTokenizer(entryTokenizer.nextToken(), "=");
+                customLevelDefinitionMap.put(innerTokenizer.nextToken(), Level.toLevel(innerTokenizer.nextToken()));
+            }
+        }
+    }
+
+    private boolean isInteger(String value) {
+        try {
+            Integer.parseInt(value);
+            return true;
+        } catch (NumberFormatException nfe) {
+            return false;
+        }
+    }
+
+    private String quoteTimeStampChars(String input) {
+        //put single quotes around text that isn't a supported dateformat char
+        StringBuffer result = new StringBuffer();
+        //ok to default to false because we also check for index zero below
+        boolean lastCharIsDateFormat = false;
+        for (int i = 0;i<input.length();i++) {
+            String thisVal = input.substring(i, i + 1);
+            boolean thisCharIsDateFormat = VALID_DATEFORMAT_CHARS.contains(thisVal);
+            //we have encountered a non-dateformat char
+            if (!thisCharIsDateFormat && (i == 0 || lastCharIsDateFormat)) {
+                result.append("'");
+            }
+            //we have encountered a dateformat char after previously encountering a non-dateformat char
+            if (thisCharIsDateFormat && i > 0 && !lastCharIsDateFormat) {
+                result.append("'");
+            }
+            lastCharIsDateFormat = thisCharIsDateFormat;
+            result.append(thisVal);
+        }
+        //append an end single-quote if we ended with non-dateformat char
+        if (!lastCharIsDateFormat) {
+            result.append("'");
+        }
+        return result.toString();
+    }
+
+    private String singleReplace(String inputString, String oldString, String newString)
+    {
+        int propLength = oldString.length();
+        int startPos = inputString.indexOf(oldString);
+        if (startPos == -1)
+        {
+            getLogger().info("string: " + oldString + " not found in input: " + inputString + " - returning input");
+            return inputString;
+        }
+        if (startPos == 0)
+        {
+            inputString = inputString.substring(propLength);
+            inputString = newString + inputString;
+        } else {
+            inputString = inputString.substring(0, startPos) + newString + inputString.substring(startPos + propLength);
+        }
+        return inputString;
+    }
+
+    private String getShortPropertyName(String longPropertyName)
+  {
+      String currentProp = longPropertyName.substring(longPropertyName.indexOf(PROP_START));
+      String prop = currentProp.substring(0, currentProp.indexOf(PROP_END) + 1);
+      String shortProp = prop.substring(PROP_START.length(), prop.length() - 1);
+      return shortProp;
+  }
+
+    /**
+   * Some perl5 characters may occur in the log file format.
+   * Escape these characters to prevent parsing errors.
+   *
+   * @param input
+   * @return string
+   */
+  private String replaceMetaChars(String input) {
+    //escape backslash first since that character is used to escape the remaining meta chars
+    input = input.replaceAll("\\\\", "\\\\\\");
+
+    //don't escape star - it's used as the wildcard
+    input = input.replaceAll(Pattern.quote("]"), "\\\\]");
+    input = input.replaceAll(Pattern.quote("["), "\\\\[");
+    input = input.replaceAll(Pattern.quote("^"), "\\\\^");
+    input = input.replaceAll(Pattern.quote("$"), "\\\\$");
+    input = input.replaceAll(Pattern.quote("."), "\\\\.");
+    input = input.replaceAll(Pattern.quote("|"), "\\\\|");
+    input = input.replaceAll(Pattern.quote("?"), "\\\\?");
+    input = input.replaceAll(Pattern.quote("+"), "\\\\+");
+    input = input.replaceAll(Pattern.quote("("), "\\\\(");
+    input = input.replaceAll(Pattern.quote(")"), "\\\\)");
+    input = input.replaceAll(Pattern.quote("-"), "\\\\-");
+    input = input.replaceAll(Pattern.quote("{"), "\\\\{");
+    input = input.replaceAll(Pattern.quote("}"), "\\\\}");
+    input = input.replaceAll(Pattern.quote("#"), "\\\\#");
+    return input;
+  }
+
+    /**
+   * Convert a keyword-to-values map to a LoggingEvent
+   *
+   * @param fieldMap
+   * @param exception
+   *
+   * @return logging event
+   */
+  private LoggingEvent convertToEvent(Map fieldMap, String[] exception) {
+    if (fieldMap == null) {
+      return null;
+    }
+
+    //a logger must exist at a minimum for the event to be processed
+    if (!fieldMap.containsKey(LOGGER)) {
+      fieldMap.put(LOGGER, "Unknown");
+    }
+    if (exception == null) {
+      exception = emptyException;
+    }
+
+    Logger logger = null;
+    long timeStamp = 0L;
+    String level = null;
+    String threadName = null;
+    Object message = null;
+    String ndc = null;
+    String className = null;
+    String methodName = null;
+    String eventFileName = null;
+    String lineNumber = null;
+    Hashtable properties = new Hashtable();
+
+    logger = Logger.getLogger((String) fieldMap.remove(LOGGER));
+
+    if ((dateFormat != null) && fieldMap.containsKey(TIMESTAMP)) {
+      try {
+        timeStamp = dateFormat.parse((String) fieldMap.remove(TIMESTAMP))
+            .getTime();
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    //use current time if timestamp not parseable
+    if (timeStamp == 0L) {
+      timeStamp = System.currentTimeMillis();
+    }
+
+    message = fieldMap.remove(MESSAGE);
+    if (message == null) {
+      message = "";
+    }
+
+    level = (String) fieldMap.remove(LEVEL);
+    Level levelImpl;
+    if (level == null) {
+        levelImpl = Level.DEBUG;
+    } else {
+        //first try to resolve against custom level definition map, then fall back to regular levels
+        levelImpl = (Level) customLevelDefinitionMap.get(level);
+        if (levelImpl == null) {
+            levelImpl = Level.toLevel(level.trim());
+            if (!level.equals(levelImpl.toString())) {
+                //check custom level map
+                if (levelImpl == null) {
+                    levelImpl = Level.DEBUG;
+                    getLogger().debug("found unexpected level: " + level + ", logger: " + logger.getName() + ", msg: " + message);
+                    //make sure the text that couldn't match a level is added to the message
+                    message = level + " " + message;
+                }
+            }
+        }
+    }
+
+    threadName = (String) fieldMap.remove(THREAD);
+
+    ndc = (String) fieldMap.remove(NDC);
+
+    className = (String) fieldMap.remove(CLASS);
+
+    methodName = (String) fieldMap.remove(METHOD);
+
+    eventFileName = (String) fieldMap.remove(FILE);
+
+    lineNumber = (String) fieldMap.remove(LINE);
+
+    properties.put(Constants.HOSTNAME_KEY, host);
+    properties.put(Constants.APPLICATION_KEY, path);
+    properties.put(Constants.RECEIVER_NAME_KEY, getName());
+
+    //all remaining entries in fieldmap are properties
+    properties.putAll(fieldMap);
+
+    LocationInfo info = null;
+
+    if ((eventFileName != null) || (className != null) || (methodName != null)
+        || (lineNumber != null)) {
+      info = new LocationInfo(eventFileName, className, methodName, lineNumber);
+    } else {
+      info = LocationInfo.NA_LOCATION_INFO;
+    }
+
+    LoggingEvent event = new LoggingEvent(null,
+            logger, timeStamp, levelImpl, message,
+            threadName,
+            new ThrowableInformation(exception),
+            ndc,
+            info,
+            properties);
+
+    return event;
+  }
+
+//  public static void main(String[] args) {
+//    org.apache.log4j.Logger rootLogger = org.apache.log4j.Logger.getRootLogger();
+//    org.apache.log4j.ConsoleAppender appender = new org.apache.log4j.ConsoleAppender(new org.apache.log4j.SimpleLayout());
+//    appender.setName("console");
+//    rootLogger.addAppender(appender);
+//    LogFilePatternReceiver test = new LogFilePatternReceiver();
+//    org.apache.log4j.spi.LoggerRepository repo = new org.apache.log4j.LoggerRepositoryExImpl(org.apache.log4j.LogManager.getLoggerRepository());
+//    test.setLoggerRepository(repo);
+//    test.setLogFormat("PROP(RELATIVETIME) [THREAD] LEVEL LOGGER * - MESSAGE");
+//    test.setTailing(false);
+//    test.setAppendNonMatches(true);
+//    test.setTimestampFormat("yyyy-MM-d HH:mm:ss,SSS");
+//    test.setFileURL("file:///C:/log/test.log");
+//    test.initialize();
+//    test.activateOptions();
+//  }
+
+    /**
+   * Close the reader.
+   */
+  public void shutdown() {
+    getLogger().info(getPath() + " shutdown");
+    active = false;
+    try {
+      if (reader != null) {
+        reader.close();
+        reader = null;
+      }
+    } catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+  }
+
+    /**
+   * Read and process the log file.
+   */
+  public void activateOptions() {
+    getLogger().info("activateOptions");
+    active = true;
+	Runnable runnable = new Runnable() {
+	  public void run() {
+        initialize();
+            while (reader == null) {
+                getLogger().info("attempting to load file: " + getFileURL());
+                try {
+                    reader = new InputStreamReader(new URL(getFileURL()).openStream());
+                } catch (FileNotFoundException fnfe) {
+                    getLogger().info("file not available - will try again");
+                    synchronized (this) {
+                        try {
+                            wait(MISSING_FILE_RETRY_MILLIS);
+                        } catch (InterruptedException ie) {}
+                    }
+                } catch (IOException ioe) {
+                    getLogger().warn("unable to load file", ioe);
+                    return;
+                }
+            }
+            try {
+                BufferedReader bufferedReader = new BufferedReader(reader);
+                createPattern();
+                do {
+                    process(bufferedReader);
+                    try {
+                        synchronized (this) {
+                            wait(waitMillis);
+                        }
+                    } catch (InterruptedException ie) {}
+                    if (tailing) {
+                      getLogger().debug("tailing file");
+                    }
+                } while (tailing);
+
+            } catch (IOException ioe) {
+                //io exception - probably shut down
+                getLogger().info("stream closed");
+            }
+            getLogger().debug("processing " + path + " complete");
+            shutdown();
+          }
+        };
+        if(useCurrentThread) {
+            runnable.run();
+        }else {
+            new Thread(runnable, "LogFilePatternReceiver-"+getName()).start();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
new file mode 100644
index 0000000..f99f289
--- /dev/null
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.varia;
+
+import java.beans.PropertyDescriptor;
+import java.beans.SimpleBeanInfo;
+
+
+/**
+ * BeanInfo class for the meta-data of the LogFilePatternReceiver.
+ *
+ */
+public class LogFilePatternReceiverBeanInfo extends SimpleBeanInfo {
+  /* (non-Javadoc)
+   * @see java.beans.BeanInfo#getPropertyDescriptors()
+   */
+  public PropertyDescriptor[] getPropertyDescriptors() {
+    try {
+      return new PropertyDescriptor[] {
+        new PropertyDescriptor("fileURL", LogFilePatternReceiver.class),
+        new PropertyDescriptor(
+          "timestampFormat", LogFilePatternReceiver.class),
+        new PropertyDescriptor("logFormat", LogFilePatternReceiver.class),
+        new PropertyDescriptor("name", LogFilePatternReceiver.class),
+        new PropertyDescriptor("tailing", LogFilePatternReceiver.class),
+        new PropertyDescriptor(
+          "filterExpression", LogFilePatternReceiver.class),
+        new PropertyDescriptor("waitMillis", LogFilePatternReceiver.class),
+        new PropertyDescriptor("appendNonMatches", LogFilePatternReceiver.class),
+        new PropertyDescriptor("customLevelDefinitions", LogFilePatternReceiver.class),
+        new PropertyDescriptor("useCurrentThread", LogFilePatternReceiver.class),
+      };
+    } catch (Exception e) {
+    }
+
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java b/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
new file mode 100644
index 0000000..945d4f0
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/LogFileXMLReceiver.java
@@ -0,0 +1,310 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import java.io.BufferedReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Iterator;
+
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.rule.ExpressionRule;
+import org.apache.log4j.rule.Rule;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * LogFileXMLReceiver will read an xml-formated log file and make the events in the log file
+ * available to the log4j framework.
+ * <p>
+ * This receiver supports log files created using log4j's XMLLayout, as well as java.util.logging
+ * XMLFormatter (via the org.apache.log4j.spi.Decoder interface).
+ * <p>
+ * By default, log4j's XMLLayout is supported (no need to specify a decoder in that case).
+ * <p>
+ * To configure this receiver to support java.util.logging's XMLFormatter, specify a 'decoder' param
+ * of org.apache.log4j.xml.UtilLoggingXMLDecoder.
+ * <p>
+ * Tailing -may- work, but not in all cases (try using a file:// URL). If a process has a log file
+ * open, the receiver may be able to read and tail the file. If the process closes the file and
+ * reopens the file, the receiver may not be able to continue tailing the file.
+ * <p>
+ * An expressionFilter may be specified. Only events passing the expression will be forwarded to the
+ * log4j framework.
+ * <p>
+ * Once the event has been "posted", it will be handled by the appenders currently configured in the
+ * LoggerRespository.
+ * 
+ * @author Scott Deboy <sd...@apache.org>
+ * @since 1.3
+ */
+
+public class LogFileXMLReceiver extends Receiver {
+    private String fileURL;
+    private Rule expressionRule;
+    private String filterExpression;
+    private String decoder = "org.apache.log4j.xml.XMLDecoder";
+    private boolean tailing = false;
+
+    private Decoder decoderInstance;
+    private Reader reader;
+    private static final String FILE_KEY = "file";
+    private String host;
+    private String path;
+    private boolean useCurrentThread;
+
+    /**
+     * Accessor
+     * 
+     * @return file URL
+     */
+    public String getFileURL() {
+        return fileURL;
+    }
+
+    /**
+     * Specify the URL of the XML-formatted file to process.
+     * 
+     * @param fileURL
+     */
+    public void setFileURL(String fileURL) {
+        this.fileURL = fileURL;
+    }
+
+    /**
+     * Accessor
+     * 
+     * @return
+     */
+    public String getDecoder() {
+        return decoder;
+    }
+
+    /**
+     * Specify the class name implementing org.apache.log4j.spi.Decoder that can process the file.
+     * 
+     * @param _decoder
+     */
+    public void setDecoder(String _decoder) {
+        decoder = _decoder;
+    }
+
+    /**
+     * Accessor
+     * 
+     * @return filter expression
+     */
+    public String getFilterExpression() {
+        return filterExpression;
+    }
+
+    /**
+     * Accessor
+     * 
+     * @return tailing flag
+     */
+    public boolean isTailing() {
+        return tailing;
+    }
+
+    /**
+     * Set the 'tailing' flag - may only work on file:// URLs and may stop tailing if the writing
+     * process closes the file and reopens.
+     * 
+     * @param tailing
+     */
+    public void setTailing(boolean tailing) {
+        this.tailing = tailing;
+    }
+
+    /**
+     * Set the filter expression that will cause only events which pass the filter to be forwarded
+     * to the log4j framework.
+     * 
+     * @param filterExpression
+     */
+    public void setFilterExpression(String filterExpression) {
+        this.filterExpression = filterExpression;
+    }
+
+    private boolean passesExpression(LoggingEvent event) {
+        if (event != null) {
+            if (expressionRule != null) {
+                return (expressionRule.evaluate(event, null));
+            }
+        }
+        return true;
+    }
+
+    public static void main(String[] args) {
+        /*
+         * LogFileXMLReceiver test = new LogFileXMLReceiver();
+         * test.setFileURL("file:///c:/samplelog.xml"); test.setFilterExpression("level >= TRACE");
+         * test.activateOptions();
+         */
+    }
+
+    /**
+     * Close the receiver, release any resources that are accessing the file.
+     */
+    public void shutdown() {
+        try {
+            if (reader != null) {
+                reader.close();
+                reader = null;
+            }
+        } catch (IOException ioe) {
+            ioe.printStackTrace();
+        }
+    }
+
+    /**
+     * Process the file
+     */
+    public void activateOptions() {
+        Runnable runnable = new Runnable() {
+            public void run() {
+                try {
+                    URL url = new URL(fileURL);
+                    host = url.getHost();
+                    if (host != null && host.equals("")) {
+                        host = FILE_KEY;
+                    }
+                    path = url.getPath();
+                } catch (MalformedURLException e1) {
+                    // TODO Auto-generated catch block
+                    e1.printStackTrace();
+                }
+
+                try {
+                    if (filterExpression != null) {
+                        expressionRule = ExpressionRule.getRule(filterExpression);
+                    }
+                } catch (Exception e) {
+                    getLogger().warn("Invalid filter expression: " + filterExpression, e);
+                }
+
+                Class c;
+                try {
+                    c = Class.forName(decoder);
+                    Object o = c.newInstance();
+                    if (o instanceof Decoder) {
+                        decoderInstance = (Decoder) o;
+                    }
+                } catch (ClassNotFoundException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (InstantiationException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                } catch (IllegalAccessException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+
+                try {
+                    reader = new InputStreamReader(new URL(getFileURL()).openStream());
+                    process(reader);
+                } catch (FileNotFoundException fnfe) {
+                    getLogger().info("file not available");
+                } catch (IOException ioe) {
+                    getLogger().warn("unable to load file", ioe);
+                    return;
+                }
+            }
+        };
+        if (useCurrentThread) {
+            runnable.run();
+        } else {
+            Thread thread = new Thread(runnable, "LogFileXMLReceiver-" + getName());
+
+            thread.start();
+
+        }
+    }
+
+    private void process(Reader unbufferedReader) throws IOException {
+        BufferedReader bufferedReader = new BufferedReader(unbufferedReader);
+        char[] content = new char[10000];
+        getLogger().debug("processing starting: " + fileURL);
+        int length = 0;
+        do {
+            System.out.println("in do loop-about to process");
+            while ((length = bufferedReader.read(content)) > -1) {
+                processEvents(decoderInstance.decodeEvents(String.valueOf(content, 0, length)));
+            }
+            if (tailing) {
+                try {
+                    Thread.sleep(5000);
+                } catch (InterruptedException e) {
+                    // TODO Auto-generated catch block
+                    e.printStackTrace();
+                }
+            }
+        } while (tailing);
+        getLogger().debug("processing complete: " + fileURL);
+
+        shutdown();
+    }
+
+    private void processEvents(Collection c) {
+        if (c == null) {
+            return;
+        }
+
+        for (Iterator iter = c.iterator(); iter.hasNext();) {
+            LoggingEvent evt = (LoggingEvent) iter.next();
+            if (passesExpression(evt)) {
+                if (evt.getProperty(Constants.HOSTNAME_KEY) != null) {
+                    evt.setProperty(Constants.HOSTNAME_KEY, host);
+                }
+                if (evt.getProperty(Constants.APPLICATION_KEY) != null) {
+                    evt.setProperty(Constants.APPLICATION_KEY, path);
+                }
+                doPost(evt);
+            }
+        }
+    }
+
+    /**
+     * When true, this property uses the current Thread to perform the import, otherwise when false
+     * (the default), a new Thread is created and started to manage the import.
+     * 
+     * @return
+     */
+    public final boolean isUseCurrentThread() {
+        return useCurrentThread;
+    }
+
+    /**
+     * Sets whether the current Thread or a new Thread is created to perform the import, the default
+     * being false (new Thread created).
+     * 
+     * @param useCurrentThread
+     */
+    public final void setUseCurrentThread(boolean useCurrentThread) {
+        this.useCurrentThread = useCurrentThread;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/UtilLoggingEntityResolver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/UtilLoggingEntityResolver.java b/src/main/java/org/apache/log4j/xml/UtilLoggingEntityResolver.java
new file mode 100644
index 0000000..71a349c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/UtilLoggingEntityResolver.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+
+import java.io.ByteArrayInputStream;
+
+
+/**
+ * An {@link EntityResolver} specifically designed to return
+ * an empty InputSource for logger.dtd.
+ *
+ */
+public final class UtilLoggingEntityResolver implements EntityResolver {
+
+    /**
+     * Create new instance.
+     */
+    public UtilLoggingEntityResolver() {
+        super();
+    }
+
+
+    /** {@inheritDoc} */
+  public InputSource resolveEntity(final String publicId,
+                                   final String systemId) {
+    if (systemId.endsWith("logger.dtd")) {
+      return new InputSource(new ByteArrayInputStream(new byte[0]));
+    } else {
+      return null;
+    }
+  }
+}


[09/50] [abbrv] logging-chainsaw git commit: Minor UI tweaks - removed unnecessary jseparator from search panel popup - Wrapping creation of colorchoosers in runonEDT calls - removed call to system.err.println

Posted by rg...@apache.org.
Minor UI tweaks
 - removed unnecessary jseparator from search panel popup
 - Wrapping creation of colorchoosers in runonEDT calls
 - removed call to system.err.println


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/d5c24ec8
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/d5c24ec8
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/d5c24ec8

Branch: refs/heads/master
Commit: d5c24ec85f337d2d9a43d2bb0e4b582a7323fbdc
Parents: ab85cf0
Author: Scott Deboy <sd...@apache.org>
Authored: Wed Oct 27 04:46:15 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Wed Oct 27 04:46:15 2010 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogPanel.java     |  1 -
 .../org/apache/log4j/chainsaw/color/ColorPanel.java  | 15 +++++++++++++--
 .../chainsaw/plugins/PluginClassLoaderFactory.java   |  1 -
 3 files changed, 13 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/d5c24ec8/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 189cac4..2ff874d 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -1918,7 +1918,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     mainPopup.add(menuItemToggleDock);
 
     mainPopup.add(new JSeparator());
-    searchPopup.add(new JSeparator());
 
     mainPopup.add(new ColorPanel());
     searchPopup.add(new ColorPanel());

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/d5c24ec8/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
index 7dc0911..6234680 100644
--- a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
@@ -68,6 +68,7 @@ import org.apache.log4j.chainsaw.ApplicationPreferenceModel;
 import org.apache.log4j.chainsaw.ChainsawConstants;
 import org.apache.log4j.chainsaw.ExpressionRuleContext;
 import org.apache.log4j.chainsaw.filter.FilterModel;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
 import org.apache.log4j.rule.ColorRule;
 import org.apache.log4j.rule.ExpressionRule;
@@ -190,14 +191,24 @@ public class ColorPanel extends JPanel
     searchTable.getColumnModel().getColumn(1).setPreferredWidth(80);
     searchTable.getColumnModel().getColumn(0).setMaxWidth(80);
     searchTable.getColumnModel().getColumn(1).setMaxWidth(80);
-    configureSingleEntryColorTable(searchTable);
+    //building color choosers needs to be done on the EDT
+    SwingHelper.invokeOnEDT(new Runnable() {
+      public void run() {
+        configureSingleEntryColorTable(searchTable);
+      }
+    });
 
     alternatingColorTable.sizeColumnsToFit(0);
     alternatingColorTable.getColumnModel().getColumn(0).setPreferredWidth(80);
     alternatingColorTable.getColumnModel().getColumn(1).setPreferredWidth(80);
     alternatingColorTable.getColumnModel().getColumn(0).setMaxWidth(80);
     alternatingColorTable.getColumnModel().getColumn(1).setMaxWidth(80);
-    configureSingleEntryColorTable(alternatingColorTable);
+    //building color choosers needs to be done on the EDT
+    SwingHelper.invokeOnEDT(new Runnable() {
+      public void run() {
+        configureSingleEntryColorTable(alternatingColorTable);
+      }
+    });
 
     configureTable();
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/d5c24ec8/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java b/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
index 2ef492e..b96e7c9 100644
--- a/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
+++ b/src/main/java/org/apache/log4j/chainsaw/plugins/PluginClassLoaderFactory.java
@@ -67,7 +67,6 @@ public class PluginClassLoaderFactory {
      */
     private static final ClassLoader create(File pluginDirectory) {
         if(pluginDirectory == null || !pluginDirectory.exists() || !pluginDirectory.canRead()) {
-         System.err.println("pluginDirectory cannot be null, and it must exist and must be readable, using the normal Classloader");
          return PluginClassLoaderFactory.class.getClassLoader();
         }
         


[16/50] [abbrv] logging-chainsaw git commit: Added ability to save the receiver configuration defined through the initial receiver configuration panel with a user-specified file path and name

Posted by rg...@apache.org.
Added ability to save the receiver configuration defined through the initial receiver configuration panel with a user-specified file path and name


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/f95619e9
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/f95619e9
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/f95619e9

Branch: refs/heads/master
Commit: f95619e914469204882877d812354a4fc74884ee
Parents: 345dc27
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Nov 4 08:12:54 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Nov 4 08:12:54 2010 +0000

----------------------------------------------------------------------
 .../ApplicationPreferenceModelPanel.java        |  2 +-
 .../apache/log4j/chainsaw/FileLoadAction.java   |  2 +-
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 24 +++--
 .../chainsaw/ReceiverConfigurationPanel.java    | 60 +++++++++---
 .../log4j/chainsaw/helper/SwingHelper.java      | 11 ++-
 .../chainsaw/receivers/ReceiversHelper.java     | 99 +++++++++++++++++++-
 .../chainsaw/receivers/ReceiversPanel.java      | 90 +-----------------
 .../log4j/chainsaw/help/release-notes.html      |  1 +
 8 files changed, 175 insertions(+), 114 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index 64cba35..c1460e0 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -560,7 +560,7 @@ public static void main(String[] args) {
                   }
               }
           }
-      File selectedFile = SwingHelper.promptForFile(this, defaultPath, "Select a Chainsaw configuration file");
+      File selectedFile = SwingHelper.promptForFile(this, defaultPath, "Select a Chainsaw configuration file", true);
       if (selectedFile != null) {
               try
               {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java b/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
index 638bc50..44b16cd 100644
--- a/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
+++ b/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
@@ -80,7 +80,7 @@ class FileLoadAction extends AbstractAction {
 
       if (!remoteURL) {
             try {
-              File selectedFile = SwingHelper.promptForFile(parent, null, "Load Events from XML file or zipped XML file...");
+              File selectedFile = SwingHelper.promptForFile(parent, null, "Load Events from XML file or zipped XML file...", true);
               if (selectedFile != null) {
                 url = selectedFile.toURI().toURL();
                 name = selectedFile.getName();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 12502f3..dd9775a 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -106,6 +106,7 @@ import org.apache.log4j.chainsaw.prefs.MRUFileListPreferenceSaver;
 import org.apache.log4j.chainsaw.prefs.SaveSettingsEvent;
 import org.apache.log4j.chainsaw.prefs.SettingsListener;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
+import org.apache.log4j.chainsaw.receivers.ReceiversHelper;
 import org.apache.log4j.chainsaw.receivers.ReceiversPanel;
 import org.apache.log4j.chainsaw.vfs.VFSLogFilePatternReceiver;
 import org.apache.log4j.net.SocketNodeEventListener;
@@ -1418,16 +1419,17 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
               public void actionPerformed(ActionEvent e) {
                 dialog.setVisible(false);
 
+            if (receiverConfigurationPanel.getModel().isCancelled()) {
+              return;
+            }
             applicationPreferenceModel.setShowNoReceiverWarning(!receiverConfigurationPanel.isDontWarnMeAgain());
-            //using this config next time - stop all plugins
-            if (receiverConfigurationPanel.isDontWarnMeAgain()) {
-                List plugins = pluginRegistry.getPlugins();
-                for (Iterator iter = plugins.iterator();iter.hasNext();) {
-                    Plugin plugin = (Plugin)iter.next();
-                    //don't stop ZeroConfPlugin if it is registered
-                    if (!plugin.getName().toLowerCase().contains("zeroconf")) {
-                      pluginRegistry.stopPlugin(plugin.getName());
-                    }
+            //remove existing plugins
+            List plugins = pluginRegistry.getPlugins();
+            for (Iterator iter = plugins.iterator();iter.hasNext();) {
+                Plugin plugin = (Plugin)iter.next();
+                //don't stop ZeroConfPlugin if it is registered
+                if (!plugin.getName().toLowerCase().contains("zeroconf")) {
+                  pluginRegistry.stopPlugin(plugin.getName());
                 }
             }
             URL configURL = null;
@@ -1525,6 +1527,10 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                     }
                   }).start();
               }
+                File saveConfigFile = receiverConfigurationPanel.getModel().getSaveConfigFile();
+                if (saveConfigFile != null) {
+                  ReceiversHelper.getInstance().saveReceiverConfiguration(saveConfigFile);
+                }
           }
         });
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index 8265361..d04a8e1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -46,7 +46,6 @@ import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 import javax.swing.JTextPane;
-import javax.swing.SwingUtilities;
 import javax.swing.text.SimpleAttributeSet;
 import javax.swing.text.StyleConstants;
 import javax.swing.text.StyledDocument;
@@ -93,6 +92,7 @@ class ReceiverConfigurationPanel extends JPanel {
     //don't warn again widgets
     private JCheckBox dontwarnIfNoReceiver;
 
+    private JButton saveButton;
     private JButton okButton;
     private JButton cancelButton;
 
@@ -214,6 +214,14 @@ class ReceiverConfigurationPanel extends JPanel {
         dontwarnIfNoReceiver = new JCheckBox("Always start Chainsaw with this configuration");
         panel.add(dontwarnIfNoReceiver, c);
 
+        saveButton = new JButton(" Save configuration as... ");
+        c = new GridBagConstraints();
+        c.fill = GridBagConstraints.HORIZONTAL;
+        c.gridx = 1;
+        c.gridy = 0;
+        c.insets = new Insets(0, 0, 0, 10);
+        panel.add(saveButton, c);
+
         okButton = new JButton(" OK ");
         cancelButton = new JButton(" Cancel ");
 
@@ -221,14 +229,14 @@ class ReceiverConfigurationPanel extends JPanel {
 
         c = new GridBagConstraints();
         c.fill = GridBagConstraints.HORIZONTAL;
-        c.gridx = 1;
+        c.gridx = 2;
         c.gridy = 0;
         c.insets = new Insets(0, 0, 0, 10);
         panel.add((JButton)okCancelButtons.get(0), c);
 
         c = new GridBagConstraints();
         c.fill = GridBagConstraints.HORIZONTAL;
-        c.gridx = 2;
+        c.gridx = 3;
         c.gridy = 0;
         panel.add((JButton)okCancelButtons.get(1), c);
 
@@ -249,10 +257,27 @@ class ReceiverConfigurationPanel extends JPanel {
                 if (logFileFormatComboBox.getSelectedItem() != null && !(logFileFormatComboBox.getSelectedItem().toString().trim().equals(""))) {
                   panelModel.setLogFormat(logFileFormatComboBox.getSelectedItem().toString());
                 }
-                completionActionListener.actionPerformed(new ActionEvent(this, -1, "cancelled"));
+                completionActionListener.actionPerformed(new ActionEvent(this, -1, "ok"));
             }
         });
-        return panel;
+
+      saveButton.addActionListener(new ActionListener()
+      {
+          public void actionPerformed(ActionEvent e)
+          {
+            try {
+                URL url = browseFile("Choose a path and file name to save", false);
+                if (url != null) {
+                  File file = new File(url.toURI());
+                  panelModel.setSaveConfigFile(file);
+                }
+            } catch (Exception ex) {
+                logger.error(
+                    "Error browsing for log file", ex);
+            }
+          }
+      });
+      return panel;
     }
 
     private JPanel buildBottomDescriptionPanel() {
@@ -323,8 +348,7 @@ class ReceiverConfigurationPanel extends JPanel {
         browseLogFileButton = new JButton(new AbstractAction(" Open File... ") {
             public void actionPerformed(ActionEvent e) {
                 try {
-
-                    URL url = browseLogFile();
+                    URL url = browseFile("Select a log file", true);
                     if (url != null) {
                         String item = url.toURI().toString();
                         logFileURLTextField.setText(item);
@@ -564,7 +588,7 @@ class ReceiverConfigurationPanel extends JPanel {
     private URL browseConfig() throws MalformedURLException {
         //hiding and showing the dialog to avoid focus issues with 2 dialogs
         dialog.setVisible(false);
-        File selectedFile = SwingHelper.promptForFile(dialog, null, "Choose a Chainsaw configuration file");
+        File selectedFile = SwingHelper.promptForFile(dialog, null, "Choose a Chainsaw configuration file", true);
         URL result = null;
         if (selectedFile == null) {
             result = null;
@@ -587,10 +611,10 @@ class ReceiverConfigurationPanel extends JPanel {
      * Returns the URL chosen by the user for a Configuration file
      * or null if they cancelled.
      */
-    private URL browseLogFile() throws MalformedURLException {
+    private URL browseFile(String title, boolean loadDialog) throws MalformedURLException {
         //hiding and showing the dialog to avoid focus issues with 2 dialogs
         dialog.setVisible(false);
-        File selectedFile = SwingHelper.promptForFile(dialog, null, "Select a log file");
+        File selectedFile = SwingHelper.promptForFile(dialog, null, title, loadDialog);
         URL result = null;
         if (selectedFile == null) {
             result = null;
@@ -641,6 +665,7 @@ class ReceiverConfigurationPanel extends JPanel {
     //default to cancelled
     private boolean cancelled = true;
     private String lastLogFormat;
+    private File saveConfigFile;
 
     public PanelModel(){
             file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
@@ -666,7 +691,6 @@ class ReceiverConfigurationPanel extends JPanel {
         }
 
         boolean isLoadSavedConfigs() {
-
             return !cancelled && useAutoSavedConfigRadioButton.isSelected();
         }
 
@@ -695,6 +719,14 @@ class ReceiverConfigurationPanel extends JPanel {
             return null;
         }
 
+        File getSaveConfigFile() {
+          return saveConfigFile;
+        }
+
+        void setSaveConfigFile(File file) {
+          this.saveConfigFile = file;
+        }
+
         URL getLogFileURL() {
             try
             {
@@ -746,5 +778,9 @@ class ReceiverConfigurationPanel extends JPanel {
           logFileFormatComboBoxModel.insertElementAt(lastLogFormat, 0);
           logFileFormatComboBox.setSelectedIndex(0);
         }
-    }
+
+        public boolean isCancelled() {
+          return cancelled;
+        }
+  }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
index 89045a6..239a8bc 100644
--- a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
@@ -107,7 +107,7 @@ public final class SwingHelper {
     return result;
   }
 
-  public static File promptForFile(Container parent, String defaultPath, String title) {
+  public static File promptForFile(Container parent, String defaultPath, String title, boolean loadDialog) {
         if (SwingHelper.isMacOSX()) {
             //use filedialog on mac
             Component root = SwingUtilities.getRoot(parent);
@@ -118,6 +118,7 @@ public final class SwingHelper {
 
             FileDialog fileDialog = new FileDialog(frame, title);
             fileDialog.setModal(true);
+            fileDialog.setMode(loadDialog ? FileDialog.LOAD : FileDialog.SAVE);
             if (defaultPath != null) {
               fileDialog.setDirectory(defaultPath);
             }
@@ -144,7 +145,13 @@ public final class SwingHelper {
 
                 chooser.setAcceptAllFileFilterUsed(true);
 
-                int i = chooser.showOpenDialog(parent);
+                int i;
+                if (loadDialog) {
+                  i = chooser.showOpenDialog(parent);
+                } else {
+                  i = chooser.showSaveDialog(parent);
+                }
+
                 if (i != JFileChooser.APPROVE_OPTION) {
                     return null;
                 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversHelper.java b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversHelper.java
index 2db5d16..1c7a671 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversHelper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversHelper.java
@@ -17,17 +17,39 @@
 package org.apache.log4j.chainsaw.receivers;
 
 
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.LineNumberReader;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.plugins.PluginClassLoaderFactory;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
 
 
 /**
@@ -108,6 +130,81 @@ public class ReceiversHelper {
     public List getKnownReceiverClasses() {
       return Collections.unmodifiableList(receiverClassList);
     }
-    
 
+
+  public void saveReceiverConfiguration(File file) {
+    LoggerRepository repo = LogManager.getLoggerRepository();
+    PluginRegistry pluginRegistry = ((LoggerRepositoryEx) repo).getPluginRegistry();
+    List fullPluginList = pluginRegistry.getPlugins();
+    List pluginList = new ArrayList();
+    for (Iterator iter = fullPluginList.iterator();iter.hasNext();) {
+        Plugin thisPlugin = (Plugin)iter.next();
+        if (thisPlugin instanceof Receiver) {
+            pluginList.add(thisPlugin);
+        }
+    }
+    //remove everything that isn't a receiver..otherwise, we'd create an empty config file
+    try {
+        if (pluginList.size() > 0) {
+            //we programmatically register the ZeroConf plugin in the plugin registry
+            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+            factory.setNamespaceAware(true);
+            DocumentBuilder builder = factory.newDocumentBuilder();
+            Document document = builder.newDocument();
+            Element rootElement = document.createElementNS("http://jakarta.apache.org/log4j/", "configuration");
+            rootElement.setPrefix("log4j");
+            rootElement.setAttribute("xmlns:log4j", "http://jakarta.apache.org/log4j/");
+            rootElement.setAttribute("debug", "true");
+
+            for (int i = 0; i < pluginList.size(); i++) {
+                Receiver receiver;
+
+                if (pluginList.get(i) instanceof Receiver) {
+                    receiver = (Receiver) pluginList.get(i);
+                } else {
+                    continue;
+                }
+
+                Element pluginElement = document.createElement("plugin");
+                pluginElement.setAttribute("name", receiver.getName());
+                pluginElement.setAttribute("class", receiver.getClass().getName());
+
+                BeanInfo beanInfo = Introspector.getBeanInfo(receiver.getClass());
+                List list = new ArrayList(Arrays.asList(beanInfo.getPropertyDescriptors()));
+
+                for (int j = 0; j < list.size(); j++) {
+                    PropertyDescriptor d = (PropertyDescriptor) list.get(j);
+                    //don't serialize the loggerRepository property for subclasses of componentbase..
+                    //easier to change this than tweak componentbase right now..
+                    if (d.getReadMethod().getName().equals("getLoggerRepository")) {
+                        continue;
+                    }
+                    Object o = d.getReadMethod().invoke(receiver, new Object[] {} );
+                    if (o != null) {
+                        Element paramElement = document.createElement("param");
+                        paramElement.setAttribute("name", d.getName());
+                        paramElement.setAttribute("value", o.toString());
+                        pluginElement.appendChild(paramElement);
+                    }
+                }
+
+                rootElement.appendChild(pluginElement);
+
+            }
+
+            TransformerFactory transformerFactory = TransformerFactory.newInstance();
+            Transformer transformer = transformerFactory.newTransformer();
+            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+            DOMSource source = new DOMSource(rootElement);
+            FileOutputStream stream = new FileOutputStream(file);
+            StreamResult result = new StreamResult(stream);
+            transformer.transform(source, result);
+            stream.close();
+        }
+
+    } catch (Exception e) {
+        e.printStackTrace();
+    }
+  }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
index d20037f..91ba7ca 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/ReceiversPanel.java
@@ -22,17 +22,12 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
-import java.beans.BeanInfo;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
 import java.io.File;
-import java.io.FileOutputStream;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -62,13 +57,6 @@ import javax.swing.event.TreeWillExpandListener;
 import javax.swing.tree.DefaultMutableTreeNode;
 import javax.swing.tree.ExpandVetoException;
 import javax.swing.tree.TreePath;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.stream.StreamResult;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.DocumentBuilder;
 
 import org.apache.log4j.Level;
 import org.apache.log4j.LogManager;
@@ -95,8 +83,6 @@ import org.apache.log4j.plugins.PluginRegistry;
 import org.apache.log4j.plugins.Receiver;
 import org.apache.log4j.spi.LoggerRepository;
 import org.apache.log4j.spi.LoggerRepositoryEx;
-import org.w3c.dom.Element;
-import org.w3c.dom.Document;
 
 
 /**
@@ -642,80 +628,8 @@ public class ReceiversPanel extends JPanel implements SettingsListener {
     */
 
   public void saveSettings(SaveSettingsEvent event){
-      List fullPluginList = pluginRegistry.getPlugins();
-      List pluginList = new ArrayList();
-      for (Iterator iter = fullPluginList.iterator();iter.hasNext();) {
-          Plugin thisPlugin = (Plugin)iter.next();
-          if (thisPlugin instanceof Receiver) {
-              pluginList.add(thisPlugin);
-          }
-      }
-      //remove everything that isn't a receiver..otherwise, we'd create an empty config file
-      try {
-          if (pluginList.size() > 0) {
-              //we programmatically register the ZeroConf plugin in the plugin registry
-              File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
-              DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-              factory.setNamespaceAware(true);
-              DocumentBuilder builder = factory.newDocumentBuilder();
-              Document document = builder.newDocument();
-              Element rootElement = document.createElementNS("http://jakarta.apache.org/log4j/", "configuration");
-              rootElement.setPrefix("log4j");
-              rootElement.setAttribute("xmlns:log4j", "http://jakarta.apache.org/log4j/");
-              rootElement.setAttribute("debug", "true");
-
-              for (int i = 0; i < pluginList.size(); i++) {
-                  Receiver receiver;
-
-                  if (pluginList.get(i) instanceof Receiver) {
-                      receiver = (Receiver) pluginList.get(i);
-                  } else {
-                      continue;
-                  }
-
-                  Element pluginElement = document.createElement("plugin");
-                  pluginElement.setAttribute("name", receiver.getName());
-                  pluginElement.setAttribute("class", receiver.getClass().getName());
-
-                  BeanInfo beanInfo = Introspector.getBeanInfo(receiver.getClass());
-                  List list = new ArrayList(Arrays.asList(beanInfo.getPropertyDescriptors()));
-
-                  for (int j = 0; j < list.size(); j++) {
-                      PropertyDescriptor d = (PropertyDescriptor) list.get(j);
-                      //don't serialize the loggerRepository property for subclasses of componentbase..
-                      //easier to change this than tweak componentbase right now..
-                      if (d.getReadMethod().getName().equals("getLoggerRepository")) {
-                          continue;
-                      }
-                      Object o = d.getReadMethod().invoke(receiver, new Object[] {} );
-                      if (o != null) {
-                          Element paramElement = document.createElement("param");
-                          paramElement.setAttribute("name", d.getName());
-                          paramElement.setAttribute("value", o.toString());
-                          pluginElement.appendChild(paramElement);
-                      }
-                  }
-
-                  rootElement.appendChild(pluginElement);
-
-              }
-
-              TransformerFactory transformerFactory = TransformerFactory.newInstance();
-              Transformer transformer = transformerFactory.newTransformer();
-              transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-              transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-              DOMSource source = new DOMSource(rootElement);
-              FileOutputStream stream = new FileOutputStream(file);
-              StreamResult result = new StreamResult(stream);
-              transformer.transform(source, result);
-              stream.close();
-          }
-
-      } catch (Exception e) {
-          e.printStackTrace();
-          logger.error("Error while writing receiver configurations to the configuration file");
-      }
-
+     File file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
+     ReceiversHelper.getInstance().saveReceiverConfiguration(file);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/f95619e9/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 3068296..803563d 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -12,6 +12,7 @@
 <h1>2.1</h1>
 <h2>4 Nov 2010</h2>
 <ul>
+<li>Added ability to save the receiver configuration defined through the initial receiver configuration panel with a user-specified file path and name</li>
 <li>Added ability to define which columns are displayed by default when a new tab is created by clicking the 'Use selected columns as default visible columns' button on the logpanel preferences column selection screen</li>
 </ul>
 <h2>22 Oct 2010</h2>


[40/50] [abbrv] logging-chainsaw git commit: Remove executions from osxappbundle - run manually instead

Posted by rg...@apache.org.
Remove executions from osxappbundle - run manually instead


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/d4214724
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/d4214724
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/d4214724

Branch: refs/heads/master
Commit: d4214724ade191b9cf3489a2e40fc89fe0e2abdb
Parents: 0f4f831
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Oct 3 16:57:30 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Oct 3 16:57:30 2011 +0000

----------------------------------------------------------------------
 pom.xml | 8 --------
 1 file changed, 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/d4214724/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 41b4e46..c47c34d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -323,14 +323,6 @@
           <iconFile>${basedir}/src/main/resources/logo.icns</iconFile>
           <bundleName>Chainsaw</bundleName>
         </configuration>
-        <executions>
-            <execution>
-                <phase>package</phase>
-                <goals>
-                    <goal>bundle</goal>
-                </goals>
-            </execution>
-       </executions>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>


[36/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/JMSReceiverBeanInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/JMSReceiverBeanInfo.java b/src/main/java/org/apache/log4j/net/JMSReceiverBeanInfo.java
new file mode 100644
index 0000000..eec19d3
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/JMSReceiverBeanInfo.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.net;
+
+import java.beans.PropertyDescriptor;
+import java.beans.SimpleBeanInfo;
+
+
+/**
+ * BeanInfo class for the JMSReceiver.
+ *
+ * @author Paul Smith <ps...@apache.org>
+ *
+ */
+public class JMSReceiverBeanInfo extends SimpleBeanInfo {
+
+    /* (non-Javadoc)
+     * @see java.beans.BeanInfo#getPropertyDescriptors()
+     */
+    public PropertyDescriptor[] getPropertyDescriptors() {
+
+        try {
+
+            return new PropertyDescriptor[] {
+                new PropertyDescriptor("name", JMSReceiver.class),
+                new PropertyDescriptor("topicFactoryName", JMSReceiver.class),
+                new PropertyDescriptor("topicName", JMSReceiver.class),
+                new PropertyDescriptor("threshold", JMSReceiver.class),
+                new PropertyDescriptor("jndiPath", JMSReceiver.class),
+                new PropertyDescriptor("userId",
+                        JMSReceiver.class),
+            };
+        } catch (Exception e) {
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/MulticastAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/MulticastAppender.java b/src/main/java/org/apache/log4j/net/MulticastAppender.java
new file mode 100644
index 0000000..de002c5
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/MulticastAppender.java
@@ -0,0 +1,345 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.UnknownHostException;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.xml.XMLLayout;
+
+
+/**
+ *  Multicast-based Appender.  Works in conjunction with the MulticastReceiver, which expects
+ *  a LoggingEvent encoded using XMLLayout. 
+ * 
+ *  Sends log information as a multicast datagrams.
+ *
+ *  <p>Messages are not sent as LoggingEvent objects but as text after
+ *  applying XMLLayout.
+ *
+ *  <p>The port and remoteHost properties can be set in configuration properties.
+ *  By setting the remoteHost to a broadcast address any number of clients can
+ *  listen for log messages.
+ *
+ *  <p>This was inspired and really extended/copied from {@link SocketAppender}.  Please
+ *  see the docs for the proper credit to the authors of that class.
+ *
+ *  @author  <a href="mailto:kbrown@versatilesolutions.com">Kevin Brown</a>
+ *  @author Scott Deboy <sd...@apache.org>
+ * 
+ */
+public class MulticastAppender extends AppenderSkeleton implements PortBased {
+  /**
+     The default port number for the multicast packets. (9991).
+  */
+  static final int DEFAULT_PORT = 9991;
+
+  /**
+   * The MulticastDNS zone advertised by a MulticastAppender
+   * the MulticastAppender also adds a 'multicastAddress' property with the multicast address value as a string
+   */
+  public static final String ZONE = "_log4j_xml_mcast_appender.local.";
+
+  /**
+     We remember host name as String in addition to the resolved
+     InetAddress so that it can be returned via getOption().
+  */
+  String hostname;
+  String remoteHost;
+  String application;
+  int timeToLive;
+  InetAddress address;
+  int port = DEFAULT_PORT;
+  MulticastSocket outSocket;
+  private String encoding;
+
+  private boolean locationInfo = false;
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+  public MulticastAppender() {
+     super(false);
+  }
+
+  /**
+     Open the multicast sender for the <b>RemoteHost</b> and <b>Port</b>.
+  */
+  public void activateOptions() {
+    try {
+      hostname = InetAddress.getLocalHost().getHostName();
+    } catch (UnknownHostException uhe) {
+      try {
+        hostname = InetAddress.getLocalHost().getHostAddress();
+      } catch (UnknownHostException uhe2) {
+        hostname = "unknown";
+      }
+    }
+
+    //allow system property of application to be primary
+    if (application == null) {
+      application = System.getProperty(Constants.APPLICATION_KEY);
+    } else {
+      if (System.getProperty(Constants.APPLICATION_KEY) != null) {
+        application = application + "-" + System.getProperty(Constants.APPLICATION_KEY);
+      }
+    }
+
+    if(remoteHost != null) {
+      address = getAddressByName(remoteHost);
+    } else {
+      String err = "The RemoteHost property is required for MulticastAppender named "+ name;
+      LogLog.error(err);
+      throw new IllegalStateException(err);
+    }
+
+    if (layout == null) {
+        layout = new XMLLayout();
+    }
+      
+    if (advertiseViaMulticastDNS) {
+        Map properties = new HashMap();
+        properties.put("multicastAddress", remoteHost);
+        zeroConf = new ZeroConfSupport(ZONE, port, getName(), properties);
+        zeroConf.advertise();
+    }
+    connect();
+    super.activateOptions();
+  }
+
+  /**
+     Close this appender.
+     <p>This will mark the appender as closed and
+     call then {@link #cleanUp} method.
+  */
+  public synchronized void close() {
+    if (closed) {
+      return;
+    }
+
+    this.closed = true;
+    if (advertiseViaMulticastDNS) {
+        zeroConf.unadvertise();
+    }
+    cleanUp();
+  }
+
+  /**
+     Close the Socket and release the underlying
+     connector thread if it has been created
+   */
+  public void cleanUp() {
+    if (outSocket != null) {
+      try {
+        outSocket.close();
+      } catch (Exception e) {
+        LogLog.error("Could not close outSocket.", e);
+      }
+
+      outSocket = null;
+    }
+  }
+
+  void connect() {
+    if (this.address == null) {
+      return;
+    }
+
+    try {
+      // First, close the previous connection if any.
+      cleanUp();
+      outSocket = new MulticastSocket();
+      outSocket.setTimeToLive(timeToLive);
+    } catch (IOException e) {
+      LogLog.error("Error in connect method of MulticastAppender named "+name, e);
+    }
+  }
+
+  public void append(LoggingEvent event) {
+    if (event == null) {
+      return;
+    }
+
+    if(locationInfo) {
+	   event.getLocationInformation();
+	}
+
+    if (outSocket != null) {
+        event.setProperty(Constants.HOSTNAME_KEY, hostname);
+
+        if (application != null) {
+          event.setProperty(Constants.APPLICATION_KEY, application);
+        }
+      
+		if(locationInfo) {
+		   event.getLocationInformation();
+		}
+
+
+      try {
+        StringBuffer buf = new StringBuffer(layout.format(event));
+
+        byte[] payload;
+        if(encoding == null) {
+          payload = buf.toString().getBytes();
+        } else {
+          payload = buf.toString().getBytes(encoding);
+        }
+
+        DatagramPacket dp =
+           new DatagramPacket(payload, payload.length, address, port);
+        outSocket.send(dp);
+      } catch (IOException e) {
+        outSocket = null;
+        LogLog.warn("Detected problem with Multicast connection: " + e);
+      }
+    }
+  }
+
+  InetAddress getAddressByName(String host) {
+    try {
+      return InetAddress.getByName(host);
+    } catch (Exception e) {
+      LogLog.error("Could not find address of [" + host + "].", e);
+      return null;
+    }
+  }
+
+  /**
+     The <b>RemoteHost</b> option takes a string value which should be
+     the host name or ipaddress to send the multicast packets.
+   */
+  public void setRemoteHost(String host) {
+    remoteHost = host;
+  }
+
+  /**
+     Returns value of the <b>RemoteHost</b> option.
+   */
+  public String getRemoteHost() {
+    return remoteHost;
+  }
+
+  /**
+  The <b>LocationInfo</b> option takes a boolean value. If true,
+  the information sent to the remote host will include location
+  information. By default no location information is sent to the server.
+   */
+  public void setLocationInfo(boolean locationInfo) {
+	  this.locationInfo = locationInfo;
+  }
+
+  /**
+   * Returns value of the <b>LocationInfo</b> option.
+   */
+  public boolean getLocationInfo() {
+	  return locationInfo;
+  }
+
+  /**
+      The <b>Encoding</b> option specifies how the bytes are encoded.  If this option is not specified, 
+      the System encoding is used.
+    */
+   public void setEncoding(String encoding) {
+     this.encoding = encoding;
+   }
+
+   /**
+      Returns value of the <b>Encoding</b> option.
+    */
+   public String getEncoding() {
+     return encoding;
+   }
+  /**
+     The <b>App</b> option takes a string value which should be the name of the application getting logged.
+     If property was already set (via system property), don't set here.
+   */
+  public void setApplication(String app) {
+    this.application = app;
+  }
+
+  /**
+     Returns value of the <b>App</b> option.
+   */
+  public String getApplication() {
+    return application;
+  }
+
+  /**
+     The <b>Time to live</b> option takes a positive integer representing
+     the time to live value.
+   */
+  public void setTimeToLive(int timeToLive) {
+    this.timeToLive = timeToLive;
+  }
+
+  /**
+     Returns value of the <b>Time to Live</b> option.
+   */
+  public int getTimeToLive() {
+    return timeToLive;
+  }
+
+  /**
+     The <b>Port</b> option takes a positive integer representing
+     the port where multicast packets will be sent.
+   */
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  /**
+     Returns value of the <b>Port</b> option.
+   */
+  public int getPort() {
+    return port;
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.log4j.net.NetworkBased#isActive()
+   */
+  public boolean isActive() {
+    // TODO handle active/inactive
+    return true;
+  }
+
+    /**
+     * Gets whether appender requires a layout.
+     * @return false
+     */
+  public boolean requiresLayout() {
+      return true;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+      return advertiseViaMulticastDNS;
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+      this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/MulticastReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/MulticastReceiver.java b/src/main/java/org/apache/log4j/net/MulticastReceiver.java
new file mode 100644
index 0000000..2dfcec2
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/MulticastReceiver.java
@@ -0,0 +1,276 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+import java.net.MulticastSocket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+ *  Multicast-based receiver.  Accepts LoggingEvents encoded using
+ *  MulticastAppender and XMLLayout. The the XML data is converted
+ *  back to a LoggingEvent and is posted.
+ *
+ *  @author Scott Deboy <sd...@apache.org>
+ *
+ */
+public class MulticastReceiver extends Receiver implements PortBased,
+  AddressBased, Pauseable {
+  private static final int PACKET_LENGTH = 16384;
+  private int port;
+  private String address;
+  private String encoding;
+  private MulticastSocket socket = null;
+
+  //default to log4j xml decoder
+  private String decoder = "org.apache.log4j.xml.XMLDecoder";
+  private Decoder decoderImpl;
+  private MulticastHandlerThread handlerThread;
+  private MulticastReceiverThread receiverThread;
+  private boolean paused;
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+  /**
+   * The MulticastDNS zone advertised by a MulticastReceiver
+   */
+  public static final String ZONE = "_log4j_xml_mcast_receiver.local.";
+
+  public String getDecoder() {
+    return decoder;
+  }
+
+  public void setDecoder(String decoder) {
+    this.decoder = decoder;
+  }
+
+  public int getPort() {
+    return port;
+  }
+
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  public String getAddress() {
+    return address;
+  }
+
+  /**
+      The <b>Encoding</b> option specifies how the bytes are encoded.  If this option is not specified,
+      the system encoding will be used.
+    */
+  public void setEncoding(String encoding) {
+    this.encoding = encoding;
+  }
+
+  /**
+     Returns value of the <b>Encoding</b> option.
+   */
+  public String getEncoding() {
+    return encoding;
+  }
+
+  public synchronized void shutdown() {
+    active = false;
+    if (advertiseViaMulticastDNS) {
+        zeroConf.unadvertise();
+    }
+    if (handlerThread != null) {
+        handlerThread.interrupt();
+    }
+    if (receiverThread != null) {
+        receiverThread.interrupt();
+    }
+    if (socket != null) {
+        socket.close();
+    }
+  }
+
+  public void setAddress(String address) {
+    this.address = address;
+  }
+
+  public boolean isPaused() {
+    return paused;
+  }
+
+  public void setPaused(boolean b) {
+    paused = b;
+  }
+
+  public void activateOptions() {
+    InetAddress addr = null;
+
+    try {
+      Class c = Class.forName(decoder);
+      Object o = c.newInstance();
+
+      if (o instanceof Decoder) {
+        this.decoderImpl = (Decoder) o;
+      }
+    } catch (ClassNotFoundException cnfe) {
+      getLogger().warn("Unable to find decoder", cnfe);
+    } catch (IllegalAccessException iae) {
+      getLogger().warn("Could not construct decoder", iae);
+    } catch (InstantiationException ie) {
+      getLogger().warn("Could not construct decoder", ie);
+    }
+
+    try {
+      addr = InetAddress.getByName(address);
+    } catch (UnknownHostException uhe) {
+      uhe.printStackTrace();
+    }
+
+    try {
+      active = true;
+      socket = new MulticastSocket(port);
+      socket.joinGroup(addr);
+      receiverThread = new MulticastReceiverThread();
+      receiverThread.start();
+      handlerThread = new MulticastHandlerThread();
+      handlerThread.start();
+      if (advertiseViaMulticastDNS) {
+        zeroConf = new ZeroConfSupport(ZONE, port, getName());
+        zeroConf.advertise();
+      }
+
+    } catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+  }
+
+    public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+        this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+    }
+
+    public boolean isAdvertiseViaMulticastDNS() {
+        return advertiseViaMulticastDNS;
+    }
+
+    class MulticastHandlerThread extends Thread {
+    private List list = new ArrayList();
+
+    public MulticastHandlerThread() {
+      setDaemon(true);
+    }
+
+    public void append(String data) {
+      synchronized (list) {
+        list.add(data);
+        list.notify();
+      }
+    }
+
+    public void run() {
+      ArrayList list2 = new ArrayList();
+
+      while (isAlive()) {
+        synchronized (list) {
+          try {
+            while (list.size() == 0) {
+              list.wait();
+            }
+
+            if (list.size() > 0) {
+              list2.addAll(list);
+              list.clear();
+            }
+          } catch (InterruptedException ie) {
+          }
+        }
+
+        if (list2.size() > 0) {
+          Iterator iter = list2.iterator();
+
+          while (iter.hasNext()) {
+            String data = (String) iter.next();
+            List v = decoderImpl.decodeEvents(data.trim());
+
+            if (v != null) {
+              Iterator eventIter = v.iterator();
+
+              while (eventIter.hasNext()) {
+                if (!isPaused()) {
+                  doPost((LoggingEvent) eventIter.next());
+                }
+              }
+            }
+          }
+
+          list2.clear();
+        } else {
+          try {
+            synchronized (this) {
+              wait(1000);
+            }
+          } catch (InterruptedException ie) {
+          }
+        }
+      }
+    }
+  }
+
+  class MulticastReceiverThread extends Thread {
+    public MulticastReceiverThread() {
+      setDaemon(true);
+    }
+
+    public void run() {
+      active = true;
+
+      byte[] b = new byte[PACKET_LENGTH];
+      DatagramPacket p = new DatagramPacket(b, b.length);
+
+      while (active) {
+        try {
+          socket.receive(p);
+
+          //this string constructor which accepts a charset throws an exception if it is 
+          //null
+            if (encoding == null) {
+            handlerThread.append(
+              new String(p.getData(), 0, p.getLength()));
+          } else {
+            handlerThread.append(
+              new String(p.getData(), 0, p.getLength(), encoding));
+          }
+        } catch (SocketException se) {
+          //disconnected
+        } catch (IOException ioe) {
+          ioe.printStackTrace();
+        }
+      }
+
+      getLogger().debug("{}'s thread is ending.", MulticastReceiver.this.getName());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/MulticastReceiverBeanInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/MulticastReceiverBeanInfo.java b/src/main/java/org/apache/log4j/net/MulticastReceiverBeanInfo.java
new file mode 100644
index 0000000..4dec14c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/MulticastReceiverBeanInfo.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.net;
+
+import java.beans.PropertyDescriptor;
+import java.beans.SimpleBeanInfo;
+
+
+/**
+ * BeanInfo class for the meta-data of the MulticastReceiver.
+ *
+ * @author Paul Smith <ps...@apache.org>
+ *
+ */
+public class MulticastReceiverBeanInfo extends SimpleBeanInfo {
+
+    /* (non-Javadoc)
+     * @see java.beans.BeanInfo#getPropertyDescriptors()
+     */
+    public PropertyDescriptor[] getPropertyDescriptors() {
+
+        try {
+
+            return new PropertyDescriptor[] {
+                new PropertyDescriptor("name", MulticastReceiver.class),
+                new PropertyDescriptor("address", MulticastReceiver.class),
+                new PropertyDescriptor("port", MulticastReceiver.class),
+                new PropertyDescriptor("threshold", MulticastReceiver.class),
+                new PropertyDescriptor("decoder", MulticastReceiver.class),
+                new PropertyDescriptor("advertiseViaMulticastDNS", MulticastReceiver.class),
+            };
+        } catch (Exception e) {
+        }
+
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/NetworkBased.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/NetworkBased.java b/src/main/java/org/apache/log4j/net/NetworkBased.java
new file mode 100644
index 0000000..9c5153f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/NetworkBased.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+/**
+ * The parent of all the Network based interfaces.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public interface NetworkBased {
+
+    /**
+     * Get name.
+     * @return name.
+     */
+  String getName();
+
+    /**
+     * Get if item is active.
+     * @return if true, item is active.
+     */
+  boolean isActive();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/PortBased.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/PortBased.java b/src/main/java/org/apache/log4j/net/PortBased.java
new file mode 100644
index 0000000..c7c1f97
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/PortBased.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+
+/**
+ * Net based entities that 'work with' a Port should consider implementing this
+ * interface so that they can be treated generically.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public interface PortBased extends NetworkBased {
+  /**
+   * Returns the Port # that this net based thing is using.
+   * @return int port number
+   */
+  int getPort();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/SocketHubReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/SocketHubReceiver.java b/src/main/java/org/apache/log4j/net/SocketHubReceiver.java
new file mode 100644
index 0000000..85058e8
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/SocketHubReceiver.java
@@ -0,0 +1,409 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.LoggerRepository;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+  SocketHubReceiver receives a remote logging event on a configured
+  socket and "posts" it to a LoggerRepository as if the event was
+  generated locally. This class is designed to receive events from
+  the SocketHubAppender class (or classes that send compatible events).
+
+  <p>Once the event has been "posted", it will be handled by the
+  appenders currently configured in the LoggerRespository.
+
+  @author Mark Womack
+  @author Ceki G&uuml;lc&uuml;
+  @author Paul Smith (psmith@apache.org)
+*/
+public class SocketHubReceiver
+extends Receiver implements SocketNodeEventListener, PortBased {
+
+    /**
+     * Default reconnection delay.
+     */
+  static final int DEFAULT_RECONNECTION_DELAY   = 30000;
+
+    /**
+     * Host.
+     */
+  protected String host;
+
+    /**
+     * Port.
+     */
+  protected int port;
+    /**
+     * Reconnection delay.
+     */
+  protected int reconnectionDelay = DEFAULT_RECONNECTION_DELAY;
+
+  /**
+   * The MulticastDNS zone advertised by a SocketHubReceiver
+   */
+  public static final String ZONE = "_log4j_obj_tcpconnect_receiver.local.";
+
+    /**
+     * Active.
+     */
+  protected boolean active = false;
+
+    /**
+     * Connector.
+     */
+  protected Connector connector;
+
+    /**
+     * Socket.
+     */
+  protected SocketNode13 socketNode;
+
+    /**
+     * Listener list.
+     */
+  private List listenerList = Collections.synchronizedList(new ArrayList());
+
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+    /**
+     * Create new instance.
+     */
+  public SocketHubReceiver() {
+     super();
+  }
+
+    /**
+     * Create new instance.
+     * @param h host
+     * @param p port
+     */
+  public SocketHubReceiver(final String h,
+                           final int p) {
+    super();
+    host = h;
+    port = p;
+  }
+
+    /**
+     * Create new instance.
+     * @param h host
+     * @param p port
+     * @param repo logger repository
+     */
+  public SocketHubReceiver(final String h,
+                           final int p,
+                           final LoggerRepository repo) {
+    super();
+    host = h;
+    port = p;
+    repository = repo;
+  }
+
+  /**
+   * Adds a SocketNodeEventListener to this receiver to be notified
+   * of SocketNode events.
+   * @param l listener
+   */
+  public void addSocketNodeEventListener(final SocketNodeEventListener l) {
+    listenerList.add(l);
+  }
+
+  /**
+   * Removes a specific SocketNodeEventListener from this instance
+   * so that it will no  longer be notified of SocketNode events.
+   * @param l listener
+   */
+  public void removeSocketNodeEventListener(
+          final SocketNodeEventListener l) {
+    listenerList.remove(l);
+  }
+
+  /**
+    Get the remote host to connect to for logging events.
+    @return host
+   */
+  public String getHost() {
+    return host;
+  }
+
+  /**
+   * Configures the Host property, this will require activateOptions
+   * to be called for this to take effect.
+   * @param remoteHost address of remote host.
+   */
+  public void setHost(final String remoteHost) {
+    this.host = remoteHost;
+  }
+  /**
+    Set the remote host to connect to for logging events.
+   Equivalent to setHost.
+   @param remoteHost address of remote host.
+   */
+  public void setPort(final String remoteHost) {
+    host = remoteHost;
+  }
+
+  /**
+    Get the remote port to connect to for logging events.
+   @return port
+   */
+  public int getPort() {
+    return port;
+  }
+
+  /**
+    Set the remote port to connect to for logging events.
+    @param p port
+   */
+  public void setPort(final int p) {
+    this.port = p;
+  }
+
+  /**
+     The <b>ReconnectionDelay</b> option takes a positive integer
+     representing the number of milliseconds to wait between each
+     failed connection attempt to the server. The default value of
+     this option is 30000 which corresponds to 30 seconds.
+
+     <p>Setting this option to zero turns off reconnection
+     capability.
+   @param delay milliseconds to wait or zero to not reconnect.
+   */
+  public void setReconnectionDelay(final int delay) {
+    int oldValue = this.reconnectionDelay;
+    this.reconnectionDelay = delay;
+    firePropertyChange("reconnectionDelay", oldValue, this.reconnectionDelay);
+  }
+
+  /**
+     Returns value of the <b>ReconnectionDelay</b> option.
+   @return value of reconnection delay option.
+   */
+  public int getReconnectionDelay() {
+    return reconnectionDelay;
+  }
+
+  /**
+   * Returns true if the receiver is the same class and they are
+   * configured for the same properties, and super class also considers
+   * them to be equivalent. This is used by PluginRegistry when determining
+   * if the a similarly configured receiver is being started.
+   *
+   * @param testPlugin The plugin to test equivalency against.
+   * @return boolean True if the testPlugin is equivalent to this plugin.
+   */
+  public boolean isEquivalent(final Plugin testPlugin) {
+    if (testPlugin != null && testPlugin instanceof SocketHubReceiver) {
+      SocketHubReceiver sReceiver = (SocketHubReceiver) testPlugin;
+
+      return (port == sReceiver.getPort()
+              && host.equals(sReceiver.getHost())
+              && reconnectionDelay == sReceiver.getReconnectionDelay()
+              && super.isEquivalent(testPlugin));
+    }
+    return false;
+  }
+
+  /**
+    Sets the flag to indicate if receiver is active or not.
+   @param b new value
+   */
+  protected synchronized void setActive(final boolean b) {
+    active = b;
+  }
+
+  /**
+    Starts the SocketReceiver with the current options. */
+  public void activateOptions() {
+    if (!isActive()) {
+      setActive(true);
+      if (advertiseViaMulticastDNS) {
+        zeroConf = new ZeroConfSupport(ZONE, port, getName());
+        zeroConf.advertise();
+      }
+
+      fireConnector(false);
+    }
+  }
+
+  /**
+    Called when the receiver should be stopped. Closes the socket */
+  public synchronized void shutdown() {
+    // mark this as no longer running
+    active = false;
+
+    // close the socket
+    try {
+      if (socketNode != null) {
+        socketNode.close();
+        socketNode = null;
+      }
+    } catch (Exception e) {
+      getLogger().info("Excpetion closing socket", e);
+      // ignore for now
+    }
+
+    // stop the connector
+    if (connector != null) {
+      connector.interrupted = true;
+      connector = null;  // allow gc
+    }
+    if (advertiseViaMulticastDNS) {
+        zeroConf.unadvertise();
+    }
+  }
+
+  /**
+    Listen for a socketClosedEvent from the SocketNode. Reopen the
+    socket if this receiver is still active.
+   @param e exception not used.
+   */
+  public void socketClosedEvent(final Exception e) {
+    // if it is a non-normal closed event
+    // we clear the connector object here
+    // so that it actually does reconnect if the
+    // remote socket dies.
+    if (e != null) {
+      connector = null;
+      fireConnector(true);
+    }
+  }
+
+    /**
+     * Fire connectors.
+     * @param isReconnect true if reconnect.
+     */
+  private synchronized void fireConnector(final boolean isReconnect) {
+    if (active && connector == null) {
+      getLogger().debug("Starting a new connector thread.");
+      connector = new Connector(isReconnect);
+      connector.setDaemon(true);
+      connector.setPriority(Thread.MIN_PRIORITY);
+      connector.start();
+    }
+  }
+
+    /**
+     * Set socket.
+     * @param newSocket new value for socket.
+     */
+  private synchronized void setSocket(final Socket newSocket) {
+    connector = null;
+    socketNode = new SocketNode13(newSocket, this);
+    socketNode.addSocketNodeEventListener(this);
+
+    synchronized (listenerList) {
+        for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+            SocketNodeEventListener listener =
+                    (SocketNodeEventListener) iter.next();
+            socketNode.addSocketNodeEventListener(listener);
+        }
+    }
+    new Thread(socketNode).start();
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+      this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+      return advertiseViaMulticastDNS;
+  }
+
+  /**
+   The Connector will reconnect when the server becomes available
+   again.  It does this by attempting to open a new connection every
+   <code>reconnectionDelay</code> milliseconds.
+
+   <p>It stops trying whenever a connection is established. It will
+   restart to try reconnect to the server when previpously open
+   connection is droppped.
+
+   @author  Ceki G&uuml;lc&uuml;
+   */
+  private final class Connector extends Thread {
+
+      /**
+       * Interruption status.
+       */
+    boolean interrupted = false;
+      /**
+       * If true, then delay on next iteration.
+       */
+    boolean doDelay;
+
+      /**
+       * Create new instance.
+       * @param isReconnect true if reconnecting.
+       */
+    public Connector(final boolean isReconnect) {
+      super();
+      doDelay = isReconnect;
+    }
+
+      /**
+       * Attempt to connect until interrupted.
+       */
+    public void run() {
+      while (!interrupted) {
+        try {
+          if (doDelay) {
+            getLogger().debug("waiting for " + reconnectionDelay
+              + " milliseconds before reconnecting.");
+            sleep(reconnectionDelay);
+          }
+          doDelay = true;
+          getLogger().debug("Attempting connection to " + host);
+          Socket s = new Socket(host, port);
+          setSocket(s);
+          getLogger().debug(
+                  "Connection established. Exiting connector thread.");
+          break;
+        } catch (InterruptedException e) {
+          getLogger().debug("Connector interrupted. Leaving loop.");
+          return;
+        } catch (java.net.ConnectException e) {
+          getLogger().debug("Remote host {} refused connection.", host);
+        } catch (IOException e) {
+          getLogger().debug("Could not connect to {}. Exception is {}.",
+                  host, e);
+        }
+      }
+    }
+  }
+
+    /**
+     * This method does nothing.
+     * @param remoteInfo remote info.
+     */
+  public void socketOpened(final String remoteInfo) {
+
+    // This method does nothing.
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/SocketNode13.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/SocketNode13.java b/src/main/java/org/apache/log4j/net/SocketNode13.java
new file mode 100644
index 0000000..e27c68e
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/SocketNode13.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.ComponentBase;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+// Contributors:  Moses Hohman <mm...@rainbow.uchicago.edu>
+
+/**
+   Read {@link LoggingEvent} objects sent from a remote client using
+   Sockets (TCP). These logging events are logged according to local
+   policy, as if they were generated locally.
+
+   <p>For example, the socket node might decide to log events to a
+   local file and also resent them to a second socket node.
+
+    Implementation lifted from org.apache.log4j.net.SocketNode
+    in log4j 1.3 and renamed to prevent collision with
+    log4j 1.2 implementation.
+
+    @author  Ceki G&uuml;lc&uuml;
+    @author  Paul Smith (psmith@apache.org)
+
+
+*/
+public class SocketNode13 extends ComponentBase implements Runnable, Pauseable {
+
+    /**
+     * Paused state.
+     */
+  private boolean paused;
+    /**
+     * Closed state.
+     */
+  private boolean closed;
+    /**
+     * Socket.
+     */
+  private Socket socket;
+    /**
+     * Receiver.
+     */
+  private Receiver receiver;
+    /**
+     * List of listeners.
+     */
+  private List listenerList = Collections.synchronizedList(new ArrayList());
+
+
+
+  /**
+    Constructor for socket and logger repository.
+   @param s socket
+   @param hierarchy logger repository
+   */
+  public SocketNode13(final Socket s,
+                    final LoggerRepository hierarchy) {
+    super();
+    this.socket = s;
+    this.repository = hierarchy;
+  }
+
+  /**
+    Constructor for socket and receiver.
+   @param s socket
+   @param r receiver
+   */
+  public SocketNode13(final Socket s, final Receiver r) {
+    super();
+    this.socket = s;
+    this.receiver = r;
+  }
+
+  /**
+   * Set the event listener on this node.
+   *
+   * @deprecated Now supports mutliple listeners, this method
+   * simply invokes the removeSocketNodeEventListener() to remove
+   * the listener, and then readds it.
+   * @param l listener
+   */
+  public void setListener(final SocketNodeEventListener l) {
+    removeSocketNodeEventListener(l);
+    addSocketNodeEventListener(l);
+  }
+
+  /**
+   * Adds the listener to the list of listeners to be notified of the
+   * respective event.
+   * @param listener the listener to add to the list
+   */
+  public void addSocketNodeEventListener(
+          final SocketNodeEventListener listener) {
+    listenerList.add(listener);
+  }
+
+  /**
+   * Removes the registered Listener from this instances list of
+   * listeners.  If the listener has not been registered, then invoking
+   * this method has no effect.
+   *
+   * @param listener the SocketNodeEventListener to remove
+   */
+  public void removeSocketNodeEventListener(
+          final SocketNodeEventListener listener) {
+    listenerList.remove(listener);
+  }
+
+
+    /**
+     * Deserialize events from socket until interrupted.
+     */
+  public void run() {
+    LoggingEvent event;
+    Logger remoteLogger;
+    Exception listenerException = null;
+    ObjectInputStream ois = null;
+
+    try {
+      ois =
+        new ObjectInputStream(
+          new BufferedInputStream(socket.getInputStream()));
+    } catch (Exception e) {
+      ois = null;
+      listenerException = e;
+      getLogger().error("Exception opening ObjectInputStream to " + socket, e);
+    }
+
+    if (ois != null) {
+
+      String hostName = socket.getInetAddress().getHostName();
+      String remoteInfo = hostName + ":" + socket.getPort();
+
+      /**
+       * notify the listener that the socket has been
+       * opened and this SocketNode is ready and waiting
+       */
+      fireSocketOpened(remoteInfo);
+
+      try {
+        while (!isClosed()) {
+          // read an event from the wire
+          event = (LoggingEvent) ois.readObject();
+          event.setProperty(Constants.HOSTNAME_KEY, hostName);
+          // store the known remote info in an event property
+          event.setProperty("log4j.remoteSourceInfo", remoteInfo);
+
+          // if configured with a receiver, tell it to post the event
+          if (!isPaused() && !isClosed()) {
+            if ((receiver != null)) {
+              receiver.doPost(event);
+
+              // else post it via the hierarchy
+            } else {
+              // get a logger from the hierarchy. The name of the logger
+              // is taken to be the name contained in the event.
+              remoteLogger = repository.getLogger(event.getLoggerName());
+
+              //event.logger = remoteLogger;
+              // apply the logger-level filter
+              if (event
+                .getLevel()
+                .isGreaterOrEqual(remoteLogger.getEffectiveLevel())) {
+                // finally log the event as if was generated locally
+                remoteLogger.callAppenders(event);
+              }
+            }
+          } else {
+            //we simply discard this event.
+          }
+        }
+      } catch (java.io.EOFException e) {
+        getLogger().info("Caught java.io.EOFException closing connection.");
+        listenerException = e;
+      } catch (java.net.SocketException e) {
+        getLogger().info("Caught java.net.SocketException closing connection.");
+        listenerException = e;
+      } catch (IOException e) {
+        getLogger().info("Caught java.io.IOException: " + e);
+        getLogger().info("Closing connection.");
+        listenerException = e;
+      } catch (Exception e) {
+        getLogger().error("Unexpected exception. Closing connection.", e);
+        listenerException = e;
+      }
+    }
+
+    // close the socket
+    try {
+      if (ois != null) {
+        ois.close();
+      }
+    } catch (Exception e) {
+      //getLogger().info("Could not close connection.", e);
+    }
+
+    // send event to listener, if configured
+    if (listenerList.size() > 0 && !isClosed()) {
+      fireSocketClosedEvent(listenerException);
+    }
+  }
+
+  /**
+   * Notifies all registered listeners regarding the closing of the Socket.
+   * @param listenerException listener exception
+   */
+  private void fireSocketClosedEvent(final Exception listenerException) {
+    synchronized (listenerList) {
+        for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+            SocketNodeEventListener snel =
+                    (SocketNodeEventListener) iter.next();
+            if (snel != null) {
+                snel.socketClosedEvent(listenerException);
+            }
+        }
+    }
+  }
+
+  /**
+   * Notifies all registered listeners regarding the opening of a Socket.
+   * @param remoteInfo remote info
+   */
+  private void fireSocketOpened(final String remoteInfo) {
+    synchronized (listenerList) {
+        for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+            SocketNodeEventListener snel =
+                    (SocketNodeEventListener) iter.next();
+            if (snel != null) {
+                snel.socketOpened(remoteInfo);
+            }
+        }
+    }
+  }
+
+    /**
+     * Sets if node is paused.
+     * @param b new value
+     */
+  public void setPaused(final boolean b) {
+    this.paused = b;
+  }
+
+    /**
+     * Get if node is paused.
+     * @return true if pause.
+     */
+  public boolean isPaused() {
+    return this.paused;
+  }
+
+    /**
+     * Close the node and underlying socket
+     */
+  public void close() throws IOException {
+    getLogger().debug("closing socket");
+    this.closed = true;
+    socket.close();
+    fireSocketClosedEvent(null);
+  }
+  
+    /**
+     * Get if node is closed.
+     * @return true if closed.
+     */
+  public boolean isClosed() {
+    return this.closed;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/SocketNodeEventListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/SocketNodeEventListener.java b/src/main/java/org/apache/log4j/net/SocketNodeEventListener.java
new file mode 100644
index 0000000..6d17602
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/SocketNodeEventListener.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.util.EventListener;
+
+/**
+  Interface used to listen for {@link SocketNode} related
+  events. Clients register an instance of the interface and the
+  instance is called back when the various events occur.
+
+  @author Mark Womack
+  @author Paul Smith (psmith@apache.org)
+*/
+public interface SocketNodeEventListener extends EventListener {
+
+  /**
+   * Called when the SocketNode is created and begins awaiting data.
+   *  @param remoteInfo remote info
+   */
+  void socketOpened(String remoteInfo);
+
+  /**
+    Called when the socket the node was given has been closed.
+    @param e exception
+   */
+  void socketClosedEvent(Exception e);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/SocketReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/SocketReceiver.java b/src/main/java/org/apache/log4j/net/SocketReceiver.java
new file mode 100644
index 0000000..9d4aac9
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/SocketReceiver.java
@@ -0,0 +1,479 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.IOException;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+  SocketReceiver receives a remote logging event on a configured
+  socket and "posts" it to a LoggerRepository as if the event was
+  generated locally. This class is designed to receive events from
+  the SocketAppender class (or classes that send compatible events).
+
+  <p>Once the event has been "posted", it will be handled by the
+  appenders currently configured in the LoggerRespository.
+
+  @author Mark Womack
+  @author Scott Deboy (sdeboy@apache.org)
+  @author Paul Smith (psmith@apache.org)
+*/
+public class SocketReceiver extends Receiver implements Runnable, PortBased,
+  Pauseable {
+    /**
+     * socket map.
+     */
+  private Map socketMap = new HashMap();
+    /**
+     * Paused.
+     */
+  private boolean paused;
+    /**
+     * Thread.
+     */
+  private Thread rThread;
+    /**
+     * Port.
+     */
+  protected int port;
+    /**
+     * Server socket.
+     */
+  private ServerSocket serverSocket;
+    /**
+     * Socket list.
+     */
+  private Vector socketList = new Vector();
+
+  /**
+   * The MulticastDNS zone advertised by a SocketReceiver
+   */
+  public static final String ZONE = "_log4j_obj_tcpaccept_receiver.local.";
+
+    /**
+     * Listener.
+     */
+  private SocketNodeEventListener listener = null;
+    /**
+     * Listeners.
+     */
+  private List listenerList = Collections.synchronizedList(new ArrayList());
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+    /**
+     * Create new instance.
+     */
+  public SocketReceiver() {
+        super();
+  }
+
+    /**
+     * Create new instance.
+     * @param p port
+     */
+  public SocketReceiver(final int p) {
+    super();
+    port = p;
+  }
+
+    /**
+     * Create new instance.
+     * @param p port
+     * @param repo logger repository
+     */
+  public SocketReceiver(final int p, final LoggerRepository repo) {
+    super();
+    this.port = p;
+    repository = repo;
+  }
+
+    /** {@inheritDoc} */
+  public int getPort() {
+    return port;
+  }
+
+  /** {@inheritDoc} */
+  public void setPort(final int p) {
+    port = p;
+  }
+
+  /**
+   * Returns true if the receiver is the same class and they are
+   * configured for the same properties, and super class also considers
+   * them to be equivalent. This is used by PluginRegistry when determining
+   * if the a similarly configured receiver is being started.
+   *
+   * @param testPlugin The plugin to test equivalency against.
+   * @return boolean True if the testPlugin is equivalent to this plugin.
+   */
+  public boolean isEquivalent(final Plugin testPlugin) {
+    if ((testPlugin != null) && testPlugin instanceof SocketReceiver) {
+      SocketReceiver sReceiver = (SocketReceiver) testPlugin;
+
+      return (port == sReceiver.getPort() && super.isEquivalent(testPlugin));
+    }
+
+    return false;
+  }
+
+  /**
+    Starts the SocketReceiver with the current options. */
+  public void activateOptions() {
+    if (!isActive()) {
+      //      shutdown();
+      rThread = new Thread(this);
+      rThread.setDaemon(true);
+      rThread.start();
+      if (advertiseViaMulticastDNS) {
+        zeroConf = new ZeroConfSupport(ZONE, port, getName());
+        zeroConf.advertise();
+      }
+
+      active = true;
+    }
+  }
+
+  /**
+   * Called when the receiver should be stopped. Closes the
+   * server socket and all of the open sockets.
+   */
+  public synchronized void shutdown() {
+    getLogger().debug(getName() + " received shutdown request");
+
+    // mark this as no longer running
+    active = false;
+
+    if (rThread != null) {
+      rThread.interrupt();
+      rThread = null;
+    }
+    if (advertiseViaMulticastDNS) {
+        zeroConf.unadvertise();
+    }
+
+    doShutdown();
+  }
+
+  /**
+   * Does the actual shutting down by closing the server socket
+   * and any connected sockets that have been created.
+   */
+  private synchronized void doShutdown() {
+    active = false;
+
+    getLogger().debug(getName() + " doShutdown called");
+
+    // close the server socket
+    closeServerSocket();
+
+    // close all of the accepted sockets
+    closeAllAcceptedSockets();
+  }
+
+  /**
+   * Closes the server socket, if created.
+   */
+  private void closeServerSocket() {
+    getLogger().debug("{} closing server socket", getName());
+
+    try {
+      if (serverSocket != null) {
+        serverSocket.close();
+      }
+    } catch (Exception e) {
+      // ignore for now
+    }
+
+    serverSocket = null;
+  }
+
+  /**
+   * Closes all the connected sockets in the List.
+   */
+  private synchronized void closeAllAcceptedSockets() {
+    for (int x = 0; x < socketList.size(); x++) {
+      try {
+        ((Socket) socketList.get(x)).close();
+      } catch (Exception e) {
+        // ignore for now
+      }
+    }
+
+    // clear member variables
+    socketMap.clear();
+    socketList.clear();
+  }
+
+  /**
+    Sets the flag to indicate if receiver is active or not.
+   @param b new value
+   */
+  protected synchronized void setActive(final boolean b) {
+    active = b;
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+      this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+      return advertiseViaMulticastDNS;
+  }
+
+  /**
+    Loop, accepting new socket connections. */
+  public void run() {
+    /**
+     * Ensure we start fresh.
+     */
+    closeServerSocket();
+    closeAllAcceptedSockets();
+
+    // start the server socket
+    try {
+      serverSocket = new ServerSocket(port);
+    } catch (Exception e) {
+      getLogger().error(
+        "error starting SocketReceiver (" + this.getName()
+        + "), receiver did not start", e);
+      active = false;
+
+      return;
+    }
+
+    Socket socket = null;
+
+    try {
+      getLogger().debug("in run-about to enter while not interrupted loop");
+
+      active = true;
+
+      while (!rThread.isInterrupted()) {
+        // if we have a socket, start watching it
+        if (socket != null) {
+          getLogger().debug(
+                  "socket not null - creating and starting socketnode");
+          socketList.add(socket);
+
+          SocketNode13 node = new SocketNode13(socket, this);
+          synchronized (listenerList) {
+            for (Iterator iter = listenerList.iterator();
+                 iter.hasNext();) {
+                SocketNodeEventListener l =
+                        (SocketNodeEventListener) iter.next();
+                node.addSocketNodeEventListener(l);
+            }
+          }
+          socketMap.put(socket, node);
+          new Thread(node).start();
+          socket = null;
+        }
+
+        getLogger().debug("waiting to accept socket");
+
+        // wait for a socket to open, then loop to start it
+        socket = serverSocket.accept();
+        getLogger().debug("accepted socket");
+      }
+    } catch (Exception e) {
+      getLogger().warn(
+        "exception while watching socket server in SocketReceiver ("
+        + this.getName() + "), stopping");
+    }
+
+    getLogger().debug("{} has exited the not interrupted loop", getName());
+
+    // socket not watched because we a no longer running
+    // so close it now.
+    if (socket != null) {
+      try {
+        socket.close();
+      } catch (IOException e1) {
+        getLogger().warn("socket exception caught - socket closed");
+      }
+    }
+
+    getLogger().debug("{} is exiting main run loop", getName());
+  }
+
+  /**
+   * Returns a Vector of SocketDetail representing the IP/Domain name
+   * of the currently connected sockets that this receiver has
+   * been responsible for creating.
+   * @return Vector of SocketDetails
+   */
+  public Vector getConnectedSocketDetails() {
+    Vector details = new Vector(socketList.size());
+
+    for (Enumeration enumeration = socketList.elements();
+         enumeration.hasMoreElements();
+            ) {
+      Socket socket = (Socket) enumeration.nextElement();
+      details.add(
+        new SocketDetail(socket, (SocketNode13) socketMap.get(socket)));
+    }
+
+    return details;
+  }
+
+  /**
+   * Returns the currently configured SocketNodeEventListener that
+   * will be automatically set for each SocketNode created.
+   * @return SocketNodeEventListener currently configured
+   *
+   * @deprecated This receiver now supports multiple listeners
+   */
+  public SocketNodeEventListener getListener() {
+    return listener;
+  }
+
+  /**
+   * Adds the listener to the list of listeners to be notified of the
+   * respective event.
+   * @param l the listener to add to the list
+   */
+  public void addSocketNodeEventListener(
+          final SocketNodeEventListener l) {
+    listenerList.add(l);
+  }
+
+  /**
+   * Removes the registered Listener from this instances list of
+   * listeners.  If the listener has not been registered, then invoking
+   * this method has no effect.
+   *
+   * @param l the SocketNodeEventListener to remove
+   */
+  public void removeSocketNodeEventListener(
+          final SocketNodeEventListener l) {
+    listenerList.remove(l);
+  }
+
+  /**
+   * Sets the SocketNodeEventListener that will be used for each
+   * created SocketNode.
+   * @param l the listener to set on each creation of a SocketNode
+   * @deprecated This receiver now supports multiple listeners and
+   * so this method simply removes the listener (if there already)
+   * and readds it to the list.
+   *
+   * The passed listener will also be returned via the getListener()
+   * method still, but this is also deprecated
+   */
+  public void setListener(final SocketNodeEventListener l) {
+    removeSocketNodeEventListener(l);
+    addSocketNodeEventListener(l);
+    this.listener = l;
+  }
+
+    /** {@inheritDoc} */
+  public boolean isPaused() {
+    return paused;
+  }
+
+    /** {@inheritDoc} */
+  public void setPaused(final boolean b) {
+    paused = b;
+  }
+
+    /**
+     * Socket detail.
+     */
+  private static final class SocketDetail implements AddressBased, PortBased,
+    Pauseable {
+      /**
+       * Address.
+       */
+    private String address;
+      /**
+       * Port.
+       */
+    private int port;
+      /**
+       * Socket node.
+       */
+    private SocketNode13 socketNode;
+
+      /**
+       * Create new instance.
+       * @param socket socket
+       * @param node socket node
+       */
+    private SocketDetail(final Socket socket,
+                         final SocketNode13 node) {
+      super();
+      this.address = socket.getInetAddress().getHostName();
+      this.port = socket.getPort();
+      this.socketNode = node;
+    }
+
+      /** {@inheritDoc} */
+    public String getAddress() {
+      return address;
+    }
+
+      /** {@inheritDoc} */
+    public int getPort() {
+      return port;
+    }
+
+      /** {@inheritDoc} */
+    public String getName() {
+      return "Socket";
+    }
+
+      /** {@inheritDoc} */
+    public boolean isActive() {
+      return true;
+    }
+
+      /** {@inheritDoc} */
+    public boolean isPaused() {
+      return socketNode.isPaused();
+    }
+
+      /** {@inheritDoc} */
+    public void setPaused(final boolean b) {
+      socketNode.setPaused(b);
+    }
+  }
+    /** {@inheritDoc} */
+  public void doPost(final LoggingEvent event) {
+    if (!isPaused()) {
+      super.doPost(event);
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/UDPAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/UDPAppender.java b/src/main/java/org/apache/log4j/net/UDPAppender.java
new file mode 100644
index 0000000..55bc6f1
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/UDPAppender.java
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.xml.XMLLayout;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+
+/**
+ *  Sends log information as a UDP datagrams.
+ *
+ *  <p>The UDPAppender is meant to be used as a diagnostic logging tool
+ *  so that logging can be monitored by a simple UDP client.
+ *
+ *  <p>Messages are not sent as LoggingEvent objects but as text after
+ *  applying the designated Layout.
+ *
+ *  <p>The port and remoteHost properties can be set in configuration properties.
+ *  By setting the remoteHost to a broadcast address any number of clients can
+ *  listen for log messages.
+ *
+ *  <p>This was inspired and really extended/copied from {@link SocketAppender}.
+ *  Please see the docs for the proper credit to the authors of that class.
+ *
+ *  @author  <a href="mailto:kbrown@versatilesolutions.com">Kevin Brown</a>
+ *  @author Scott Deboy <sd...@apache.org>
+ */
+public class UDPAppender extends AppenderSkeleton implements PortBased{
+  /**
+    * The default port number for the UDP packets, 9991.
+  */
+  public static final int DEFAULT_PORT = 9991;
+
+  /**
+     We remember host name as String in addition to the resolved
+     InetAddress so that it can be returned via getOption().
+  */
+  String hostname;
+  String remoteHost;
+  String application;
+  String encoding;
+  InetAddress address;
+  int port = DEFAULT_PORT;
+  DatagramSocket outSocket;
+
+  /**
+   * The MulticastDNS zone advertised by a UDPAppender
+   */
+  public static final String ZONE = "_log4j_xml_udp_appender.local.";
+
+  // if there is something irrecoverably wrong with the settings, there is no
+  // point in sending out packeets.
+  boolean inError = false;
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+    public UDPAppender() {
+      super(false);
+  }
+
+  /**
+     Sends UDP packets to the <code>address</code> and <code>port</code>.
+  */
+  public UDPAppender(final InetAddress address, final int port) {
+    super(false);
+    this.address = address;
+    this.remoteHost = address.getHostName();
+    this.port = port;
+    activateOptions();
+  }
+
+  /**
+     Sends UDP packets to the <code>address</code> and <code>port</code>.
+  */
+  public UDPAppender(final String host, final int port) {
+    super(false);
+    this.port = port;
+    this.address = getAddressByName(host);
+    this.remoteHost = host;
+    activateOptions();
+  }
+
+  /**
+     Open the UDP sender for the <b>RemoteHost</b> and <b>Port</b>.
+  */
+  public void activateOptions() {
+    try {
+      hostname = InetAddress.getLocalHost().getHostName();
+    } catch (UnknownHostException uhe) {
+      try {
+        hostname = InetAddress.getLocalHost().getHostAddress();
+      } catch (UnknownHostException uhe2) {
+        hostname = "unknown";
+      }
+    }
+
+    //allow system property of application to be primary
+    if (application == null) {
+      application = System.getProperty(Constants.APPLICATION_KEY);
+    } else {
+      if (System.getProperty(Constants.APPLICATION_KEY) != null) {
+        application = application + "-" + System.getProperty(Constants.APPLICATION_KEY);
+      }
+    }
+
+    if(remoteHost != null) {
+      address = getAddressByName(remoteHost);
+      connect(address, port);
+    } else {
+      String err = "The RemoteHost property is required for SocketAppender named "+ name;
+      LogLog.error(err);
+      throw new IllegalStateException(err);
+    }
+
+    if (layout == null) {
+        layout = new XMLLayout();
+    }
+
+    if (advertiseViaMulticastDNS) {
+      zeroConf = new ZeroConfSupport(ZONE, port, getName());
+      zeroConf.advertise();
+    }
+
+    super.activateOptions();
+  }
+
+  /**
+     Close this appender.
+     <p>This will mark the appender as closed and
+     call then {@link #cleanUp} method.
+  */
+  public synchronized void close() {
+    if (closed) {
+      return;
+    }
+
+    if (advertiseViaMulticastDNS) {
+      zeroConf.unadvertise();
+    }
+      
+    this.closed = true;
+    cleanUp();
+  }
+
+  /**
+     Close the UDP Socket and release the underlying
+     connector thread if it has been created
+   */
+  public void cleanUp() {
+    if (outSocket != null) {
+      try {
+        outSocket.close();
+      } catch (Exception e) {
+        LogLog.error("Could not close outSocket.", e);
+      }
+
+      outSocket = null;
+    }
+  }
+
+  void connect(InetAddress address, int port) {
+    if (this.address == null) {
+      return;
+    }
+
+    try {
+      // First, close the previous connection if any.
+      cleanUp();
+      outSocket = new DatagramSocket();
+      outSocket.connect(address, port);
+    } catch (IOException e) {
+      LogLog.error(
+        "Could not open UDP Socket for sending.", e);
+      inError = true;
+    }
+  }
+
+  public void append(LoggingEvent event) {
+    if(inError) {
+      return;
+    }
+    
+    if (event == null) {
+      return;
+    }
+
+    if (address == null) {
+      return;
+    }
+
+    if (outSocket != null) {
+      event.setProperty(Constants.HOSTNAME_KEY, hostname);
+      if (application != null) {
+        event.setProperty(Constants.APPLICATION_KEY, application);
+      }
+
+      try {
+        StringBuffer buf = new StringBuffer(layout.format(event));
+
+        byte[] payload;
+        if(encoding == null) {
+          payload = buf.toString().getBytes();
+        } else {
+          payload = buf.toString().getBytes(encoding);
+        }
+
+        DatagramPacket dp =
+           new DatagramPacket(payload, payload.length, address, port);
+        outSocket.send(dp);
+      } catch (IOException e) {
+        outSocket = null;
+        LogLog.warn("Detected problem with UDP connection: " + e);
+      }
+    }
+  }
+
+  public boolean isActive() {
+    return !inError;
+  }
+  
+  InetAddress getAddressByName(String host) {
+    try {
+      return InetAddress.getByName(host);
+    } catch (Exception e) {
+      LogLog.error("Could not find address of [" + host + "].", e);
+      return null;
+    }
+  }
+
+  /**
+     The UDPAppender uses layouts. Hence, this method returns
+     <code>true</code>.
+  */
+  public boolean requiresLayout() {
+    return true;
+  }
+
+  /**
+     The <b>RemoteHost</b> option takes a string value which should be
+     the host name or ipaddress to send the UDP packets.
+   */
+  public void setRemoteHost(String host) {
+    remoteHost = host;
+  }
+
+  /**
+     Returns value of the <b>RemoteHost</b> option.
+   */
+  public String getRemoteHost() {
+    return remoteHost;
+  }
+
+  /**
+     The <b>App</b> option takes a string value which should be the name of the application getting logged.
+     If property was already set (via system property), don't set here.
+   */
+  public void setApplication(String app) {
+    this.application = app;
+  }
+
+  /**
+     Returns value of the <b>App</b> option.
+   */
+  public String getApplication() {
+    return application;
+  }
+
+  /**
+     The <b>Encoding</b> option specifies how the bytes are encoded.  If this option is not specified, 
+     the System encoding is used.
+   */
+  public void setEncoding(String encoding) {
+    this.encoding = encoding;
+  }
+
+  /**
+     Returns value of the <b>Encoding</b> option.
+   */
+  public String getEncoding() {
+    return encoding;
+  }
+
+    /**
+     The <b>Port</b> option takes a positive integer representing
+     the port where UDP packets will be sent.
+   */
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  /**
+     Returns value of the <b>Port</b> option.
+   */
+  public int getPort() {
+    return port;
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+    this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+    return advertiseViaMulticastDNS;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/UDPReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/UDPReceiver.java b/src/main/java/org/apache/log4j/net/UDPReceiver.java
new file mode 100644
index 0000000..a8c7375
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/UDPReceiver.java
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.SocketException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+ *  Receive LoggingEvents encoded with an XMLLayout, convert the XML data to a
+ *  LoggingEvent and post the LoggingEvent.
+ *
+ *  @author Scott Deboy <sd...@apache.org>
+ *
+ */
+public class UDPReceiver extends Receiver implements PortBased, Pauseable {
+  private static final int PACKET_LENGTH = 16384;
+  private UDPReceiverThread receiverThread;
+  private String encoding;
+
+  //default to log4j xml decoder
+  private String decoder = "org.apache.log4j.xml.XMLDecoder";
+  private Decoder decoderImpl;
+  protected boolean paused;
+  private transient boolean closed = false;
+  private int port;
+  private DatagramSocket socket;
+  UDPHandlerThread handlerThread;
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+  /**
+   * The MulticastDNS zone advertised by a UDPReceiver
+   */
+  public static final String ZONE = "_log4j_xml_udp_receiver.local.";
+
+
+    public int getPort() {
+    return port;
+  }
+
+  public void setPort(int port) {
+    this.port = port;
+  }
+
+  /**
+   * The <b>Encoding</b> option specifies how the bytes are encoded.  If this 
+   * option is not specified, the system encoding will be used.
+   * */
+  public void setEncoding(String encoding) {
+    this.encoding = encoding;
+  }
+
+  /**
+   * Returns value of the <b>Encoding</b> option.
+   */
+  public String getEncoding() {
+    return encoding;
+  }
+
+  public String getDecoder() {
+    return decoder;
+  }
+
+  public void setDecoder(String decoder) {
+    this.decoder = decoder;
+  }
+
+  public boolean isPaused() {
+    return paused;
+  }
+
+  public void setPaused(boolean b) {
+    paused = b;
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+    this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+    return advertiseViaMulticastDNS;
+  }
+
+  public synchronized void shutdown() {
+    if(closed == true) {
+      return;
+    }
+    closed = true;
+    active = false;
+    // Closing the datagram socket will unblock the UDPReceiverThread if it is
+    // was waiting to receive data from the socket.
+    if (socket != null) {
+    	socket.close();
+    }
+
+    if (advertiseViaMulticastDNS) {
+      zeroConf.unadvertise();
+    }
+      
+    try {
+      if(handlerThread != null) {
+      	handlerThread.close();
+        handlerThread.join();
+      }
+      if(receiverThread != null) {
+        receiverThread.join();
+      }
+    } catch(InterruptedException ie) {
+    }
+  }
+
+  /**
+    Returns true if this receiver is active. */
+//  public synchronized boolean isActive() {
+//    return isActive;
+//}
+
+  public void activateOptions() {
+    try {
+      Class c = Class.forName(decoder);
+      Object o = c.newInstance();
+
+      if (o instanceof Decoder) {
+        this.decoderImpl = (Decoder) o;
+      }
+    } catch (ClassNotFoundException cnfe) {
+      getLogger().warn("Unable to find decoder", cnfe);
+    } catch (IllegalAccessException iae) {
+      getLogger().warn("Could not construct decoder", iae);
+    } catch (InstantiationException ie) {
+      getLogger().warn("Could not construct decoder", ie);
+    }
+
+    try {
+      socket = new DatagramSocket(port);
+      receiverThread = new UDPReceiverThread();
+      receiverThread.start();
+      handlerThread = new UDPHandlerThread();
+      handlerThread.start();
+      if (advertiseViaMulticastDNS) {
+        zeroConf = new ZeroConfSupport(ZONE, port, getName());
+        zeroConf.advertise();
+      }
+      active = true;
+    } catch (IOException ioe) {
+      ioe.printStackTrace();
+    }
+  }
+
+  class UDPHandlerThread extends Thread {
+    private List list = new ArrayList();
+
+    public UDPHandlerThread() {
+      setDaemon(true);
+    }
+
+    public void append(String data) {
+      synchronized (list) {
+        list.add(data);
+        list.notify();
+      }
+    }
+
+    /**
+     * Allow the UDPHandlerThread to wakeup and exit gracefully.
+     */
+    void close() {
+      synchronized(list) {
+      	list.notify();
+      }
+    }
+
+    public void run() {
+      ArrayList list2 = new ArrayList();
+
+      while (!UDPReceiver.this.closed) {
+        synchronized (list) {
+          try {
+            while (!UDPReceiver.this.closed && list.size() == 0) {
+              list.wait(300);
+            }
+
+            if (list.size() > 0) {
+              list2.addAll(list);
+              list.clear();
+            }
+          } catch (InterruptedException ie) {
+          }
+        }
+
+        if (list2.size() > 0) {
+          Iterator iter = list2.iterator();
+
+          while (iter.hasNext()) {
+            String data = (String) iter.next();
+            List v = decoderImpl.decodeEvents(data);
+
+            if (v != null) {
+              Iterator eventIter = v.iterator();
+
+              while (eventIter.hasNext()) {
+                if (!isPaused()) {
+                  doPost((LoggingEvent) eventIter.next());
+                }
+              }
+            }
+          }
+
+          list2.clear();
+        } else {
+          try {
+            synchronized (this) {
+              wait(1000);
+            }
+          } catch (InterruptedException ie) {
+          }
+        }
+      } // while
+      getLogger().debug(UDPReceiver.this.getName()+ "'s handler thread is exiting");
+    } // run
+  } // UDPHandlerThread
+
+  class UDPReceiverThread extends Thread {
+    public UDPReceiverThread() {
+      setDaemon(true);
+    }
+    
+    public void run() {
+      byte[] b = new byte[PACKET_LENGTH];
+      DatagramPacket p = new DatagramPacket(b, b.length);
+
+      while (!UDPReceiver.this.closed) {
+        try {
+          socket.receive(p);
+          
+          //this string constructor which accepts a charset throws an exception if it is 
+          //null
+          if (encoding == null) {
+            handlerThread.append(
+              new String(p.getData(), 0, p.getLength()));
+          } else {
+            handlerThread.append(
+              new String(p.getData(), 0, p.getLength(), encoding));
+          }
+        } catch (SocketException se) {
+          //disconnected
+        } catch (IOException ioe) {
+          ioe.printStackTrace();
+        }
+      }
+
+      //LogLog.debug(UDPReceiver.this.getName() + "'s thread is ending.");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/XMLSocketNode.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/XMLSocketNode.java b/src/main/java/org/apache/log4j/net/XMLSocketNode.java
new file mode 100644
index 0000000..95ab638
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/XMLSocketNode.java
@@ -0,0 +1,205 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import org.apache.log4j.*;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.*;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import java.net.Socket;
+
+import java.util.Iterator;
+import java.util.List;
+
+
+/**
+   Read {@link LoggingEvent} objects sent from a remote client using XML over
+   Sockets (TCP). These logging events are logged according to local
+   policy, as if they were generated locally.
+
+   <p>For example, the socket node might decide to log events to a
+   local file and also resent them to a second socket node.
+
+    @author  Scott Deboy <sd...@apache.org>;
+
+    @since 0.8.4
+*/
+public class XMLSocketNode extends ComponentBase implements Runnable {
+  Socket socket;
+  Receiver receiver;
+  Decoder decoder;
+  SocketNodeEventListener listener;
+
+  /**
+    Constructor for socket and logger repository. */
+  public XMLSocketNode(
+    String decoder, Socket socket, LoggerRepository hierarchy) {
+    this.repository = hierarchy;
+    try {
+      Class c = Class.forName(decoder);
+      Object o = c.newInstance();
+
+      if (o instanceof Decoder) {
+        this.decoder = (Decoder) o;
+      }
+    } catch (ClassNotFoundException cnfe) {
+      getLogger().warn("Unable to find decoder", cnfe);
+    } catch (IllegalAccessException iae) {
+      getLogger().warn("Unable to construct decoder", iae);
+    } catch (InstantiationException ie) {
+      getLogger().warn("Unable to construct decoder", ie);
+    }
+
+    this.socket = socket;
+  }
+
+  /**
+    Constructor for socket and reciever. */
+  public XMLSocketNode(String decoder, Socket socket, Receiver receiver) {
+    try {
+      Class c = Class.forName(decoder);
+      Object o = c.newInstance();
+
+      if (o instanceof Decoder) {
+        this.decoder = (Decoder) o;
+      }
+    } catch (ClassNotFoundException cnfe) {
+      getLogger().warn("Unable to find decoder", cnfe);
+    } catch (IllegalAccessException iae) {
+      getLogger().warn("Unable to construct decoder", iae);
+    } catch (InstantiationException ie) {
+      getLogger().warn("Unable to construct decoder", ie);
+    }
+
+    this.socket = socket;
+    this.receiver = receiver;
+  }
+
+  /**
+    Set the event listener on this node. */
+  public void setListener(SocketNodeEventListener _listener) {
+    listener = _listener;
+  }
+
+  public void run() {
+    Logger remoteLogger;
+    Exception listenerException = null;
+    InputStream is = null;
+
+    if ((this.receiver == null) || (this.decoder == null)) {
+      is = null;
+      listenerException =
+        new Exception(
+          "No receiver or decoder provided.  Cannot process xml socket events");
+      getLogger().error(
+        "Exception constructing XML Socket Receiver", listenerException);
+    }
+
+    try {
+      is = socket.getInputStream();
+    } catch (Exception e) {
+      is = null;
+      listenerException = e;
+      getLogger().error("Exception opening ObjectInputStream to " + socket, e);
+    }
+
+    if (is != null) {
+        String hostName = socket.getInetAddress().getHostName();
+        String remoteInfo = hostName + ":" + socket.getPort();
+    	
+      try {
+        //read data from the socket
+        //it's up to the individual decoder to handle incomplete event data
+        while (true) {
+          byte[] b = new byte[1024];
+          int length = is.read(b);
+          if (length == -1) {
+            getLogger().info(
+              "no bytes read from stream - closing connection.");
+            break;
+          }
+          List v = decoder.decodeEvents(new String(b, 0, length));
+
+          if (v != null) {
+            Iterator iter = v.iterator();
+
+            while (iter.hasNext()) {
+              LoggingEvent e = (LoggingEvent) iter.next();
+              e.setProperty(Constants.HOSTNAME_KEY, hostName);
+
+              // store the known remote info in an event property
+              e.setProperty("log4j.remoteSourceInfo", remoteInfo);
+
+              // if configured with a receiver, tell it to post the event
+              if (receiver != null) {
+                receiver.doPost(e);
+
+                // else post it via the hierarchy
+              } else {
+                // get a logger from the hierarchy. The name of the logger
+                // is taken to be the name contained in the event.
+                remoteLogger = repository.getLogger(e.getLoggerName());
+
+                //event.logger = remoteLogger;
+                // apply the logger-level filter
+                if (
+                  e.getLevel().isGreaterOrEqual(
+                      remoteLogger.getEffectiveLevel())) {
+                  // finally log the event as if was generated locally
+                  remoteLogger.callAppenders(e);
+                }
+              }
+            }
+          }
+        }
+      } catch (java.io.EOFException e) {
+        getLogger().info("Caught java.io.EOFException closing connection.");
+        listenerException = e;
+      } catch (java.net.SocketException e) {
+        getLogger().info(
+          "Caught java.net.SocketException closing connection.");
+        listenerException = e;
+      } catch (IOException e) {
+        getLogger().info("Caught java.io.IOException: " + e);
+        getLogger().info("Closing connection.");
+        listenerException = e;
+      } catch (Exception e) {
+        getLogger().error("Unexpected exception. Closing connection.", e);
+        listenerException = e;
+      }
+    }
+
+    // close the socket
+    try {
+      if (is != null) {
+        is.close();
+      }
+    } catch (Exception e) {
+      //logger.info("Could not close connection.", e);
+    }
+
+    // send event to listener, if configured
+    if (listener != null) {
+      listener.socketClosedEvent(listenerException);
+    }
+  }
+}


[38/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.



Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/08c7be5c
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/08c7be5c
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/08c7be5c

Branch: refs/heads/master
Commit: 08c7be5cdb56374f77d297a0e90440aeef541b8a
Parents: decd6ab
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Oct 3 06:15:40 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Oct 3 06:15:40 2011 +0000

----------------------------------------------------------------------
 HOWTOBUILD.txt                                  |   13 -
 pom.xml                                         |   38 +-
 .../apache/log4j/LoggerRepositoryExImpl.java    |  697 ++++++++++++
 src/main/java/org/apache/log4j/ULogger.java     |  203 ++++
 .../org/apache/log4j/db/ConnectionSource.java   |   69 ++
 .../log4j/db/ConnectionSourceSkeleton.java      |  150 +++
 .../apache/log4j/db/CustomSQLDBReceiver.java    |  468 ++++++++
 .../java/org/apache/log4j/db/DBAppender.java    |  403 +++++++
 src/main/java/org/apache/log4j/db/DBHelper.java |   68 ++
 .../java/org/apache/log4j/db/DBReceiver.java    |  140 +++
 .../java/org/apache/log4j/db/DBReceiverJob.java |  230 ++++
 .../log4j/db/DataSourceConnectionSource.java    |  105 ++
 .../log4j/db/DriverManagerConnectionSource.java |  133 +++
 .../apache/log4j/db/JNDIConnectionSource.java   |  143 +++
 .../apache/log4j/db/dialect/HSQLDBDialect.java  |   31 +
 .../apache/log4j/db/dialect/MsSQLDialect.java   |   34 +
 .../apache/log4j/db/dialect/MySQLDialect.java   |   32 +
 .../apache/log4j/db/dialect/OracleDialect.java  |   33 +
 .../log4j/db/dialect/PostgreSQLDialect.java     |   35 +
 .../org/apache/log4j/db/dialect/SQLDialect.java |   27 +
 .../apache/log4j/db/dialect/SybaseDialect.java  |   32 +
 .../java/org/apache/log4j/db/dialect/Util.java  |  125 +++
 .../java/org/apache/log4j/db/dialect/db2.sql    |   64 ++
 .../java/org/apache/log4j/db/dialect/db2l.sql   |   61 +
 .../java/org/apache/log4j/db/dialect/hsqldb.sql |   60 +
 .../java/org/apache/log4j/db/dialect/mssql.sql  |   61 +
 .../java/org/apache/log4j/db/dialect/mysql.sql  |   71 ++
 .../java/org/apache/log4j/db/dialect/oracle.sql |   77 ++
 .../org/apache/log4j/db/dialect/postgresql.sql  |   63 ++
 src/main/java/org/apache/log4j/db/package.html  |   36 +
 .../org/apache/log4j/helpers/Constants.java     |  126 +++
 .../apache/log4j/helpers/MessageFormatter.java  |  154 +++
 .../apache/log4j/helpers/UtilLoggingLevel.java  |  238 ++++
 .../java/org/apache/log4j/net/AddressBased.java |   36 +
 .../java/org/apache/log4j/net/JMSReceiver.java  |  301 +++++
 .../apache/log4j/net/JMSReceiverBeanInfo.java   |   52 +
 .../org/apache/log4j/net/MulticastAppender.java |  345 ++++++
 .../org/apache/log4j/net/MulticastReceiver.java |  276 +++++
 .../log4j/net/MulticastReceiverBeanInfo.java    |   51 +
 .../java/org/apache/log4j/net/NetworkBased.java |   39 +
 .../java/org/apache/log4j/net/PortBased.java    |   34 +
 .../org/apache/log4j/net/SocketHubReceiver.java |  409 +++++++
 .../java/org/apache/log4j/net/SocketNode13.java |  299 +++++
 .../log4j/net/SocketNodeEventListener.java      |   43 +
 .../org/apache/log4j/net/SocketReceiver.java    |  479 ++++++++
 .../java/org/apache/log4j/net/UDPAppender.java  |  330 ++++++
 .../java/org/apache/log4j/net/UDPReceiver.java  |  281 +++++
 .../org/apache/log4j/net/XMLSocketNode.java     |  205 ++++
 .../org/apache/log4j/net/XMLSocketReceiver.java |  316 ++++++
 .../org/apache/log4j/plugins/Pauseable.java     |   39 +
 .../java/org/apache/log4j/plugins/Plugin.java   |  144 +++
 .../org/apache/log4j/plugins/PluginEvent.java   |   47 +
 .../apache/log4j/plugins/PluginListener.java    |   43 +
 .../apache/log4j/plugins/PluginRegistry.java    |  303 +++++
 .../apache/log4j/plugins/PluginSkeleton.java    |  222 ++++
 .../java/org/apache/log4j/plugins/Receiver.java |  131 +++
 .../apache/log4j/rewrite/MapRewritePolicy.java  |   85 ++
 .../log4j/rewrite/PropertyRewritePolicy.java    |   93 ++
 .../log4j/rewrite/ReflectionRewritePolicy.java  |   89 ++
 .../apache/log4j/rewrite/RewriteAppender.java   |  199 ++++
 .../org/apache/log4j/rewrite/RewritePolicy.java |   37 +
 .../java/org/apache/log4j/scheduler/Job.java    |   36 +
 .../org/apache/log4j/scheduler/Scheduler.java   |  307 ++++++
 .../java/org/apache/log4j/spi/Component.java    |   37 +
 .../org/apache/log4j/spi/ComponentBase.java     |  126 +++
 src/main/java/org/apache/log4j/spi/Decoder.java |   63 ++
 .../java/org/apache/log4j/spi/ErrorItem.java    |  172 +++
 .../java/org/apache/log4j/spi/Log4JULogger.java |  229 ++++
 .../apache/log4j/spi/LoggerEventListener.java   |   59 +
 .../spi/LoggerRepositoryEventListener.java      |   53 +
 .../apache/log4j/spi/LoggerRepositoryEx.java    |  198 ++++
 .../java/org/apache/log4j/spi/NOPULogger.java   |  200 ++++
 .../org/apache/log4j/spi/SimpleULogger.java     |  305 +++++
 .../org/apache/log4j/spi/Thresholdable.java     |   58 +
 .../apache/log4j/varia/ListModelAppender.java   |   79 ++
 .../log4j/varia/LogFilePatternReceiver.java     | 1043 ++++++++++++++++++
 .../varia/LogFilePatternReceiverBeanInfo.java   |   53 +
 .../apache/log4j/xml/LogFileXMLReceiver.java    |  310 ++++++
 .../log4j/xml/UtilLoggingEntityResolver.java    |   50 +
 .../apache/log4j/xml/UtilLoggingXMLDecoder.java |  468 ++++++++
 .../java/org/apache/log4j/xml/XMLDecoder.java   |  495 +++++++++
 .../log4j/chainsaw/help/release-notes.html      |    1 +
 .../java/org/apache/log4j/VectorAppender.java   |   91 ++
 .../org/apache/log4j/db/FullCycleDBTest.java    |  327 ++++++
 .../log4j/helpers/UtilLoggingLevelTest.java     |   46 +
 .../log4j/rewrite/RewriteAppenderTest.java      |  132 +++
 .../java/org/apache/log4j/util/Compare.java     |  202 ++++
 .../org/apache/log4j/xml/XMLDecoderTest.java    |   86 ++
 .../log4j/db/append-with-drivermanager1.xml     |   48 +
 .../log4j/db/read-with-drivermanager1.xml       |   55 +
 .../resources/org/apache/log4j/rewrite/map.log  |    3 +
 .../resources/org/apache/log4j/rewrite/map.xml  |   38 +
 .../org/apache/log4j/rewrite/property.log       |    2 +
 .../org/apache/log4j/rewrite/property.xml       |   40 +
 .../org/apache/log4j/rewrite/reflection.log     |    3 +
 .../org/apache/log4j/rewrite/reflection.xml     |   38 +
 .../org/apache/log4j/xml/xmlLayout.1.xml        |  162 +++
 .../org/apache/log4j/xml/xsltLayout.1.xml       |  139 +++
 98 files changed, 14874 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/HOWTOBUILD.txt
----------------------------------------------------------------------
diff --git a/HOWTOBUILD.txt b/HOWTOBUILD.txt
index 7375489..ebbd4bb 100644
--- a/HOWTOBUILD.txt
+++ b/HOWTOBUILD.txt
@@ -23,19 +23,6 @@ Firstly, you'll need maven 2.0.9+ to build Chainsaw:
 http://maven.apache.org
 
 
-Next, an interim step is required until the 'companions' are voted on and released:
-
-* SVN check out the following projects:
-	log4j-component - http://svn.apache.org/repos/asf/logging/log4j/companions/component/trunk/
-	log4j-extras - http://svn.apache.org/repos/asf/logging/log4j/companions/extras/trunk/
-	log4j-receivers - http://svn.apache.org/repos/asf/logging/log4j/companions/receivers/trunk/
-
-  In each of these checkout directories:
-  	mvn install
-
-  This will install into your local maven repository the correct releases of the required dependencies. 
-  These dependencies are not yet available in the standard maven repositories, and so failure to complete this step will prevent you from building Chainsaw.
-
 * cd to Chainsaw project checkout directory
 
 	mvn install

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index f434fcd..18c0f43 100644
--- a/pom.xml
+++ b/pom.xml
@@ -118,8 +118,7 @@
       <plugin>
         <artifactId>maven-compiler-plugin</artifactId>
         <configuration>
-          <source>1.2</source>
-          <target>1.1</target>
+          <source>1.4</source>
         </configuration>
       </plugin>
       <plugin>
@@ -220,7 +219,7 @@
             <artifactId>ant-contrib</artifactId>
             <version>1.0b2</version>
           </dependency>
-        </dependencies>
+	</dependencies>
       </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
@@ -324,6 +323,14 @@
           <iconFile>${basedir}/src/main/resources/logo.icns</iconFile>
           <bundleName>Chainsaw</bundleName>
         </configuration>
+        <executions>
+            <execution>
+                <phase>package</phase>
+                <goals>
+                    <goal>bundle</goal>
+                </goals>
+            </execution>
+       </executions>
       </plugin>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
@@ -386,17 +393,6 @@
     </dependency>
     <dependency>
       <groupId>log4j</groupId>
-      <artifactId>apache-log4j-receivers</artifactId>
-      <version>1.0-SNAPSHOT</version>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
-      <artifactId>apache-log4j-receivers</artifactId>
-      <version>1.0-SNAPSHOT</version>
-      <classifier>javadoc</classifier>
-    </dependency>
-    <dependency>
-      <groupId>log4j</groupId>
       <artifactId>log4j</artifactId>
       <version>1.2.16</version>
     </dependency>
@@ -437,6 +433,18 @@
       <artifactId>jsch</artifactId>
       <version>0.1.42</version>
     </dependency>
+    <dependency>
+		<groupId>hsqldb</groupId>
+		<artifactId>hsqldb</artifactId>
+		<version>1.8.0.7</version>
+		<scope>test</scope>
+	</dependency>
+    <dependency>
+        <groupId>org.apache.geronimo.specs</groupId>
+        <artifactId>geronimo-jms_1.1_spec</artifactId>
+        <version>1.0</version>
+        <optional>true</optional>
+    </dependency>
   </dependencies>
   <reporting>
     <excludeDefaults>true</excludeDefaults>
@@ -480,7 +488,7 @@
       </plugin>
     </plugins>
   </reporting>
-  <distributionManagement>
+    <distributionManagement>
     <repository>
       <id>logging.repo</id>
       <url>scp://people.apache.org/www/people.apache.org/builds/logging/repo/</url>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/LoggerRepositoryExImpl.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/LoggerRepositoryExImpl.java b/src/main/java/org/apache/log4j/LoggerRepositoryExImpl.java
new file mode 100644
index 0000000..c2f5aaf
--- /dev/null
+++ b/src/main/java/org/apache/log4j/LoggerRepositoryExImpl.java
@@ -0,0 +1,697 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.or.ObjectRenderer;
+import org.apache.log4j.or.RendererMap;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.PluginRegistry;
+import org.apache.log4j.scheduler.Scheduler;
+import org.apache.log4j.spi.ErrorItem;
+import org.apache.log4j.spi.HierarchyEventListener;
+import org.apache.log4j.spi.LoggerEventListener;
+import org.apache.log4j.spi.LoggerFactory;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEventListener;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.spi.RendererSupport;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.w3c.dom.Element;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+
+/**
+ * This class implements LoggerRepositoryEx by
+ *   wrapping an existing LoggerRepository implementation
+ *   and implementing the newly added capabilities.
+*/
+public final class LoggerRepositoryExImpl
+        implements LoggerRepositoryEx,
+        RendererSupport,
+        UnrecognizedElementHandler {
+
+    /**
+     * Wrapped logger repository.
+     */
+  private final LoggerRepository repo;
+
+    /**
+     * Logger factory.  Does not affect class of logger
+     * created by underlying repository.
+     */
+  private LoggerFactory loggerFactory;
+
+    /**
+     *  Renderer support.
+     */
+  private final RendererSupport rendererSupport;
+
+    /**
+     * List of repository event listeners.
+     */
+  private final ArrayList repositoryEventListeners = new ArrayList();
+    /**
+     * Map of HierarchyEventListener keyed by LoggingEventListener.
+     */
+  private final Map loggerEventListeners = new HashMap();
+    /**
+     * Name of hierarchy.
+     */
+  private String name;
+    /**
+     * Plug in registry.
+     */
+  private PluginRegistry pluginRegistry;
+    /**
+     * Properties.
+     */
+  private final Map properties = new Hashtable();
+    /**
+     * Scheduler.
+     */
+  private Scheduler scheduler;
+
+  /** The repository can also be used as an object store
+   * for various objects used by log4j components.
+   */
+  private Map objectMap = new HashMap();
+
+
+    /**
+     * Error list.
+     */
+  private List errorList = new Vector();
+
+    /**
+     * True if hierarchy has not been modified.
+     */
+  private boolean pristine = true;
+
+  /**
+     Constructs a new logger hierarchy.
+
+     @param repository Base implementation of repository.
+
+   */
+  public LoggerRepositoryExImpl(final LoggerRepository repository) {
+    super();
+    if (repository == null) {
+        throw new NullPointerException("repository");
+    }
+    repo = repository;
+    if (repository instanceof RendererSupport) {
+        rendererSupport = (RendererSupport) repository;
+    } else {
+        rendererSupport = new RendererSupportImpl();
+    }
+  }
+
+
+  /**
+    Add a {@link LoggerRepositoryEventListener} to the repository. The
+    listener will be called when repository events occur.
+    @param listener listener
+    */
+  public void addLoggerRepositoryEventListener(
+    final LoggerRepositoryEventListener listener) {
+    synchronized (repositoryEventListeners) {
+      if (repositoryEventListeners.contains(listener)) {
+        LogLog.warn(
+          "Ignoring attempt to add a previously "
+                  + "registered LoggerRepositoryEventListener.");
+      } else {
+        repositoryEventListeners.add(listener);
+      }
+    }
+  }
+
+
+  /**
+    Remove a {@link LoggerRepositoryEventListener} from the repository.
+    @param listener listener
+    */
+  public void removeLoggerRepositoryEventListener(
+    final LoggerRepositoryEventListener listener) {
+    synchronized (repositoryEventListeners) {
+      if (!repositoryEventListeners.contains(listener)) {
+        LogLog.warn(
+          "Ignoring attempt to remove a "
+                  + "non-registered LoggerRepositoryEventListener.");
+      } else {
+        repositoryEventListeners.remove(listener);
+      }
+    }
+  }
+
+  /**
+    Add a {@link LoggerEventListener} to the repository. The  listener
+    will be called when repository events occur.
+    @param listener listener
+   */
+  public void addLoggerEventListener(final LoggerEventListener listener) {
+    synchronized (loggerEventListeners) {
+      if (loggerEventListeners.get(listener) != null) {
+        LogLog.warn(
+         "Ignoring attempt to add a previously registerd LoggerEventListener.");
+      } else {
+        HierarchyEventListenerProxy proxy =
+                new HierarchyEventListenerProxy(listener);
+        loggerEventListeners.put(listener, proxy);
+        repo.addHierarchyEventListener(proxy);
+      }
+    }
+  }
+
+    /**
+       Add a {@link org.apache.log4j.spi.HierarchyEventListener}
+     event to the repository.
+     @param listener listener
+       @deprecated Superceded by addLoggerEventListener
+    */
+    public
+    void addHierarchyEventListener(final HierarchyEventListener listener) {
+        repo.addHierarchyEventListener(listener);
+    }
+
+
+  /**
+    Remove a {@link LoggerEventListener} from the repository.
+    @param listener listener to be removed
+    */
+  public void removeLoggerEventListener(final LoggerEventListener listener) {
+    synchronized (loggerEventListeners) {
+      HierarchyEventListenerProxy proxy =
+              (HierarchyEventListenerProxy) loggerEventListeners.get(listener);
+      if (proxy == null) {
+        LogLog.warn(
+          "Ignoring attempt to remove a non-registered LoggerEventListener.");
+      } else {
+        loggerEventListeners.remove(listener);
+        proxy.disable();
+      }
+    }
+  }
+
+    /**
+     * Issue warning that there are no appenders in hierarchy.
+     * @param cat logger, not currently used.
+     */
+  public void emitNoAppenderWarning(final Category cat) {
+    repo.emitNoAppenderWarning(cat);
+  }
+
+  /**
+     Check if the named logger exists in the hierarchy. If so return
+     its reference, otherwise returns <code>null</code>.
+
+     @param loggerName The name of the logger to search for.
+     @return true if logger exists.
+  */
+  public Logger exists(final String loggerName) {
+    return repo.exists(loggerName);
+  }
+
+  /**
+   * Return the name of this hierarchy.
+   * @return name of hierarchy
+   */
+  public String getName() {
+    return name;
+  }
+
+  /**
+   * Set the name of this repository.
+   *
+   * Note that once named, a repository cannot be rerenamed.
+   * @param repoName name of hierarchy
+   */
+  public void setName(final String repoName) {
+    if (name == null) {
+      name = repoName;
+    } else if (!name.equals(repoName)) {
+      throw new IllegalStateException(
+        "Repository [" + name + "] cannot be renamed as [" + repoName + "].");
+    }
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public Map getProperties() {
+    return properties;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public String getProperty(final String key) {
+     return (String) properties.get(key);
+  }
+
+  /**
+   * Set a property by key and value. The property will be shared by all
+   * events in this repository.
+   * @param key property name
+   * @param value property value
+   */
+  public void setProperty(final String key,
+                          final String value) {
+   properties.put(key, value);
+  }
+
+  /**
+     The string form of {@link #setThreshold(Level)}.
+   @param levelStr symbolic name for level
+  */
+  public void setThreshold(final String levelStr) {
+    repo.setThreshold(levelStr);
+  }
+
+  /**
+     Enable logging for logging requests with level <code>l</code> or
+     higher. By default all levels are enabled.
+
+     @param l The minimum level for which logging requests are sent to
+     their appenders.  */
+  public void setThreshold(final Level l) {
+    repo.setThreshold(l);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public PluginRegistry getPluginRegistry() {
+   if (pluginRegistry == null) {
+     pluginRegistry = new PluginRegistry(this);
+   }
+   return pluginRegistry;
+  }
+
+
+    /**
+      Requests that a appender added event be sent to any registered
+      {@link LoggerEventListener}.
+      @param logger The logger to which the appender was added.
+      @param appender The appender added to the logger.
+     */
+    public void fireAddAppenderEvent(final Category logger,
+                                     final Appender appender) {
+        repo.fireAddAppenderEvent(logger, appender);
+    }
+
+
+    /**
+      Requests that a appender removed event be sent to any registered
+      {@link LoggerEventListener}.
+      @param logger The logger from which the appender was removed.
+      @param appender The appender removed from the logger.
+      */
+    public void fireRemoveAppenderEvent(final Category logger,
+                                        final Appender appender) {
+       if (repo instanceof Hierarchy) {
+           ((Hierarchy) repo).fireRemoveAppenderEvent(logger, appender);
+       }
+    }
+
+
+  /**
+    Requests that a level changed event be sent to any registered
+    {@link LoggerEventListener}.
+    @param logger The logger which changed levels.
+    */
+  public void fireLevelChangedEvent(final Logger logger) {
+  }
+
+  /**
+   *
+   * Requests that a configuration changed event be sent to any registered
+   * {@link LoggerRepositoryEventListener}.
+   * 
+   */
+  public void fireConfigurationChangedEvent() {
+  }
+
+
+  /**
+     Returns the current threshold.
+     @return current threshold level
+
+     @since 1.2 */
+  public Level getThreshold() {
+    return repo.getThreshold();
+  }
+
+
+  /**
+     Return a new logger instance named as the first parameter using
+     the default factory.
+
+     <p>If a logger of that name already exists, then it will be
+     returned.  Otherwise, a new logger will be instantiated and
+     then linked with its existing ancestors as well as children.
+
+     @param loggerName The name of the logger to retrieve.
+     @return logger
+
+  */
+  public Logger getLogger(final String loggerName) {
+    return repo.getLogger(loggerName);
+  }
+
+  /**
+      Return a new logger instance named as the first parameter using
+      <code>factory</code>.
+
+      <p>If a logger of that name already exists, then it will be
+      returned.  Otherwise, a new logger will be instantiated by the
+      <code>factory</code> parameter and linked with its existing
+      ancestors as well as children.
+
+      @param loggerName The name of the logger to retrieve.
+      @param factory The factory that will make the new logger instance.
+      @return logger
+
+  */
+  public Logger getLogger(final String loggerName,
+                          final LoggerFactory factory) {
+    return repo.getLogger(loggerName, factory);
+  }
+
+  /**
+     Returns all the currently defined categories in this hierarchy as
+     an {@link java.util.Enumeration Enumeration}.
+
+     <p>The root logger is <em>not</em> included in the returned
+     {@link Enumeration}.
+     @return enumerator of current loggers
+   */
+  public Enumeration getCurrentLoggers() {
+    return repo.getCurrentLoggers();
+  }
+
+  /**
+   * Return the the list of previously encoutered {@link ErrorItem error items}.
+   * @return list of errors
+   */
+  public List getErrorList() {
+    return errorList;
+  }
+
+  /**
+   * Add an error item to the list of previously encountered errors.
+   * @param errorItem error to add to list of errors.
+   */
+  public void addErrorItem(final ErrorItem errorItem) {
+    getErrorList().add(errorItem);
+  }
+
+  /**
+   * Get enumerator over current loggers.
+   * @return enumerator over current loggers
+     @deprecated Please use {@link #getCurrentLoggers} instead.
+   */
+  public Enumeration getCurrentCategories() {
+    return repo.getCurrentCategories();
+  }
+
+  /**
+     Get the renderer map for this hierarchy.
+   @return renderer map
+  */
+  public RendererMap getRendererMap() {
+    return rendererSupport.getRendererMap();
+  }
+
+  /**
+     Get the root of this hierarchy.
+
+     @since 0.9.0
+   @return root of hierarchy
+   */
+  public Logger getRootLogger() {
+    return repo.getRootLogger();
+  }
+
+  /**
+     This method will return <code>true</code> if this repository is
+     disabled for <code>level</code> value passed as parameter and
+     <code>false</code> otherwise. See also the {@link
+     #setThreshold(Level) threshold} method.
+   @param level numeric value for level.
+   @return true if disabled for specified level
+   */
+  public boolean isDisabled(final int level) {
+    return repo.isDisabled(level);
+  }
+
+  /**
+     Reset all values contained in this hierarchy instance to their
+     default.  This removes all appenders from all categories, sets
+     the level of all non-root categories to <code>null</code>,
+     sets their additivity flag to <code>true</code> and sets the level
+     of the root logger to DEBUG.  Moreover,
+     message disabling is set its default "off" value.
+
+     <p>Existing categories are not removed. They are just reset.
+
+     <p>This method should be used sparingly and with care as it will
+     block all logging until it is completed.</p>
+
+     @since 0.8.5 */
+  public void resetConfiguration() {
+    repo.resetConfiguration();
+  }
+
+  /**
+     Used by subclasses to add a renderer to the hierarchy passed as parameter.
+   @param renderedClass class
+   @param renderer object used to render class.
+   */
+  public void setRenderer(final Class renderedClass,
+                          final ObjectRenderer renderer) {
+    rendererSupport.setRenderer(renderedClass, renderer);
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public boolean isPristine() {
+    return pristine;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  public void setPristine(final boolean state) {
+    pristine = state;
+  }
+
+  /**
+     Shutting down a hierarchy will <em>safely</em> close and remove
+     all appenders in all categories including the root logger.
+
+     <p>Some appenders such as org.apache.log4j.net.SocketAppender
+     and AsyncAppender need to be closed before the
+     application exists. Otherwise, pending logging events might be
+     lost.
+
+     <p>The <code>shutdown</code> method is careful to close nested
+     appenders before closing regular appenders. This is allows
+     configurations where a regular appender is attached to a logger
+     and again to a nested appender.
+
+     @since 1.0 */
+  public void shutdown() {
+    repo.shutdown();
+  }
+
+
+  /**
+   * Return this repository's own scheduler.
+   * The scheduler is lazily instantiated.
+   * @return this repository's own scheduler.
+   */
+  public Scheduler getScheduler() {
+    if (scheduler == null) {
+      scheduler = new Scheduler();
+      scheduler.setDaemon(true);
+      scheduler.start();
+    }
+    return scheduler;
+  }
+
+    /**
+     * Puts object by key.
+     * @param key key, may not be null.
+     * @param value object to associate with key.
+     */
+  public void putObject(final String key,
+                        final Object value) {
+    objectMap.put(key, value);
+  }
+
+    /**
+     * Get object by key.
+     * @param key key, may not be null.
+     * @return object associated with key or null.
+     */
+  public Object getObject(final String key) {
+    return objectMap.get(key);
+  }
+
+    /**
+     * Set logger factory.
+     * @param factory logger factory.
+     */
+  public void setLoggerFactory(final LoggerFactory factory) {
+    if (factory == null) {
+      throw new NullPointerException();
+    }
+    this.loggerFactory = factory;
+  }
+
+    /**
+     * Get logger factory.
+     * @return logger factory.
+     */
+  public LoggerFactory getLoggerFactory() {
+    return loggerFactory;
+  }
+
+    /** {@inheritDoc} */
+    public boolean parseUnrecognizedElement(
+            final Element element,
+            final Properties props) throws Exception {
+        if ("plugin".equals(element.getNodeName())) {
+            Object instance =
+                    DOMConfigurator.parseElement(element, props, Plugin.class);
+            if (instance instanceof Plugin) {
+                Plugin plugin = (Plugin) instance;
+                String pluginName = DOMConfigurator.subst(element.getAttribute("name"), props);
+                if (pluginName.length() > 0) {
+                    plugin.setName(pluginName);
+                }
+                getPluginRegistry().addPlugin(plugin);
+                plugin.setLoggerRepository(this);
+
+                LogLog.debug("Pushing plugin on to the object stack.");
+                plugin.activateOptions();
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+
+    /**
+     * Implementation of RendererSupportImpl if not
+     * provided by LoggerRepository.
+     */
+   private static final class RendererSupportImpl implements RendererSupport {
+        /**
+         * Renderer map.
+         */
+       private final RendererMap renderers = new RendererMap();
+
+        /**
+         * Create new instance.
+         */
+       public RendererSupportImpl() {
+           super();
+       }
+
+        /** {@inheritDoc} */
+       public RendererMap getRendererMap() {
+           return renderers;
+       }
+
+        /** {@inheritDoc} */
+       public void setRenderer(final Class renderedClass,
+                               final ObjectRenderer renderer) {
+           renderers.put(renderedClass, renderer);
+       }
+   }
+
+    /**
+     * Proxy that implements HierarchyEventListener
+     * and delegates to LoggerEventListener.
+     */
+   private static final class HierarchyEventListenerProxy
+        implements HierarchyEventListener {
+        /**
+         * Wrapper listener.
+         */
+       private LoggerEventListener listener;
+
+        /**
+         * Creates new instance.
+         * @param l listener
+         */
+       public HierarchyEventListenerProxy(final LoggerEventListener l) {
+           super();
+           if (l == null) {
+               throw new NullPointerException("l");
+           }
+           listener = l;
+       }
+
+        /** {@inheritDoc} */
+       public void addAppenderEvent(final Category cat,
+                                    final Appender appender) {
+           if (isEnabled() && cat instanceof Logger) {
+                listener.appenderAddedEvent((Logger) cat, appender);
+           }
+       }
+
+        /** {@inheritDoc} */
+       public void removeAppenderEvent(final Category cat,
+                                    final Appender appender) {
+           if (isEnabled() && cat instanceof Logger) {
+                listener.appenderRemovedEvent((Logger) cat, appender);
+           }
+       }
+
+        /**
+         * Disable forwarding of notifications to
+         * simulate removal of listener.
+         */
+       public synchronized void disable() {
+           listener = null;
+       }
+
+        /**
+         * Gets whether proxy is enabled.
+         * @return true if proxy is enabled.
+         */
+       private synchronized boolean isEnabled() {
+           return listener != null;
+       }
+   }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/ULogger.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/ULogger.java b/src/main/java/org/apache/log4j/ULogger.java
new file mode 100644
index 0000000..83a6bb8
--- /dev/null
+++ b/src/main/java/org/apache/log4j/ULogger.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+
+/**
+ * A proxy for org.slf4j.ULogger.  In slf4j implementing builds, this
+ *     interface will extend org.slf4j.ULogger and add no additional methods.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ * @author Curt Arnold
+ */
+ public interface ULogger {
+
+
+  /**
+   * Is the logger instance enabled for the DEBUG level?
+   * @return true if debug is enabled.
+   */
+  boolean isDebugEnabled();
+
+  /**
+   * Log a message object with the DEBUG level.
+   * @param msg - the message object to be logged
+   */
+  void debug(Object msg);
+
+
+  /**
+   * Log a parameterized message object at the DEBUG level.
+   *
+   * <p>This form is useful in avoiding the superflous object creation
+   * problem when invoking this method while it is disabled.
+   * </p>
+   * @param parameterizedMsg - the parameterized message object
+   * @param param1 - the parameter
+   */
+  void debug(Object parameterizedMsg, Object param1);
+
+  /**
+   * Log a parameterized message object at the DEBUG level.
+   *
+   * <p>This form is useful in avoiding the superflous object creation
+   * problem when invoking this method while it is disabled.
+   * </p>
+   * @param parameterizedMsg - the parameterized message object
+   * @param param1 - the first parameter
+   * @param param2 - the second parameter
+   */
+  void debug(String parameterizedMsg, Object param1, Object param2);
+    /**
+     * Log a message object with the <code>DEBUG</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     *
+     * @param msg the message object to log.
+     * @param t the exception to log, including its stack trace.
+     */
+  void debug(Object msg, Throwable t);
+
+
+    /**
+     * Is the logger instance enabled for the INFO level?
+     * @return true if debug is enabled.
+     */
+  boolean isInfoEnabled();
+    /**
+     * Log a message object with the INFO level.
+     * @param msg - the message object to be logged
+     */
+  void info(Object msg);
+    /**
+     * Log a parameterized message object at the INFO level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the parameter
+     */
+  void info(Object parameterizedMsg, Object param1);
+    /**
+     * Log a parameterized message object at the INFO level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the first parameter
+     * @param param2 - the second parameter
+     */
+  void info(String parameterizedMsg, Object param1, Object param2);
+    /**
+     * Log a message object with the <code>INFO</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     *
+     * @param msg the message object to log.
+     * @param t the exception to log, including its stack trace.
+     */
+  void info(Object msg, Throwable t);
+
+
+    /**
+     * Is the logger instance enabled for the WARN level?
+     * @return true if debug is enabled.
+     */
+  boolean isWarnEnabled();
+    /**
+     * Log a message object with the WARN level.
+     * @param msg - the message object to be logged
+     */
+  void warn(Object msg);
+    /**
+     * Log a parameterized message object at the WARN level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the parameter
+     */
+  void warn(Object parameterizedMsg, Object param1);
+    /**
+     * Log a parameterized message object at the WARN level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the first parameter
+     * @param param2 - the second parameter
+     */
+  void warn(String parameterizedMsg, Object param1, Object param2);
+    /**
+     * Log a message object with the <code>WARN</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     *
+     * @param msg the message object to log.
+     * @param t the exception to log, including its stack trace.
+     */
+  void warn(Object msg, Throwable t);
+
+
+    /**
+     * Is the logger instance enabled for the ERROR level?
+     * @return true if debug is enabled.
+     */
+  boolean isErrorEnabled();
+    /**
+     * Log a message object with the ERROR level.
+     * @param msg - the message object to be logged
+     */
+  void error(Object msg);
+    /**
+     * Log a parameterized message object at the ERROR level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the parameter
+     */
+  void error(Object parameterizedMsg, Object param1);
+    /**
+     * Log a parameterized message object at the ERROR level.
+     *
+     * <p>This form is useful in avoiding the superflous object creation
+     * problem when invoking this method while it is disabled.
+     * </p>
+     * @param parameterizedMsg - the parameterized message object
+     * @param param1 - the first parameter
+     * @param param2 - the second parameter
+     */
+  void error(String parameterizedMsg, Object param1, Object param2);
+
+    /**
+     * Log a message object with the <code>ERROR</code> level including the
+     * stack trace of the {@link Throwable}<code>t</code> passed as parameter.
+     *
+     *
+     * @param msg the message object to log.
+     * @param t the exception to log, including its stack trace.
+     */
+    void error(Object msg, Throwable t);
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/ConnectionSource.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/ConnectionSource.java b/src/main/java/org/apache/log4j/db/ConnectionSource.java
new file mode 100644
index 0000000..0578734
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/ConnectionSource.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import org.apache.log4j.spi.Component;
+import org.apache.log4j.spi.OptionHandler;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+
+/**
+ *  The <id>ConnectionSource</id> interface provides a pluggable means of
+ *  transparently obtaining JDBC {@link java.sql.Connection}s for log4j classes
+ *  that require the use of a {@link java.sql.Connection}.
+ *
+ *  @author <a href="mailto:rdecampo@twcny.rr.com">Ray DeCampo</a>
+ */
+public interface ConnectionSource extends Component, OptionHandler {
+
+  final int UNKNOWN_DIALECT = 0;
+  final int POSTGRES_DIALECT = 1;
+  final int MYSQL_DIALECT = 2;
+  final int ORACLE_DIALECT = 3;
+  final int MSSQL_DIALECT = 4;
+  final int HSQL_DIALECT = 5;  
+  /**
+   *  Obtain a {@link java.sql.Connection} for use.  The client is
+   *  responsible for closing the {@link java.sql.Connection} when it is no
+   *  longer required.
+   *
+   *  @throws SQLException  if a {@link java.sql.Connection} could not be
+   *                        obtained
+   */
+  Connection getConnection() throws SQLException;
+
+  /**
+   * Get the SQL dialect that should be used for this connection. Note that the
+   * dialect is not needed if the JDBC driver supports the getGeneratedKeys 
+   * method.
+   */
+  int getSQLDialectCode();
+  
+  /**
+   * If the connection supports the JDBC 3.0 getGeneratedKeys method, then
+   * we do not need any specific dialect support.
+   */
+  boolean supportsGetGeneratedKeys();
+  
+  /**
+   * If the connection does not support batch updates, we will avoid using them.
+   */  
+  public boolean supportsBatchUpdates();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/ConnectionSourceSkeleton.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/ConnectionSourceSkeleton.java b/src/main/java/org/apache/log4j/db/ConnectionSourceSkeleton.java
new file mode 100644
index 0000000..a5abecb
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/ConnectionSourceSkeleton.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+import org.apache.log4j.db.dialect.Util;
+import org.apache.log4j.spi.ComponentBase;
+
+
+/**
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public abstract class ConnectionSourceSkeleton extends ComponentBase implements ConnectionSource {
+  
+  private Boolean overriddenSupportsGetGeneratedKeys = null;
+  
+  private String user = null;
+  private String password = null;
+
+  // initially we have an unkonw dialect
+  private int dialectCode = UNKNOWN_DIALECT;
+  private boolean supportsGetGeneratedKeys = false;
+  private boolean supportsBatchUpdates = false;
+
+
+  /**
+   * Learn relevant information about this connection source.
+   *
+   */
+  public void discoverConnnectionProperties() {
+    Connection connection = null;
+    try {
+      connection = getConnection();
+      if (connection == null) {
+        getLogger().warn("Could not get a conneciton");
+        return;
+      }
+      DatabaseMetaData meta = connection.getMetaData();
+      Util util = new Util();
+      util.setLoggerRepository(repository);
+      if (overriddenSupportsGetGeneratedKeys != null) {
+        supportsGetGeneratedKeys = overriddenSupportsGetGeneratedKeys
+            .booleanValue();
+      } else {
+        supportsGetGeneratedKeys = util.supportsGetGeneratedKeys(meta);
+      }
+      supportsBatchUpdates = util.supportsBatchUpdates(meta);
+      dialectCode = Util.discoverSQLDialect(meta);
+    } catch (SQLException se) {
+      getLogger().warn("Could not discover the dialect to use.", se);
+    } finally {
+      DBHelper.closeConnection(connection);
+    }
+  }
+
+  /**
+   * Does this connection support the JDBC Connection.getGeneratedKeys method?
+   */
+  public final boolean supportsGetGeneratedKeys() {
+    return supportsGetGeneratedKeys;
+  }
+
+  public final int getSQLDialectCode() {
+    return dialectCode;
+  }
+
+  /**
+   * Get the password for this connection source.
+   */
+  public final String getPassword() {
+    return password;
+  }
+
+  /**
+   * Sets the password.
+   * @param password The password to set
+   */
+  public final void setPassword(final String password) {
+    this.password = password;
+  }
+
+  /**
+   * Get the user for this connection source.
+   */
+  public final String getUser() {
+    return user;
+  }
+
+  /**
+   * Sets the username.
+   * @param username The username to set
+   */
+  public final void setUser(final String username) {
+    this.user = username;
+  }
+
+  /**
+   * Returns the "overridden" value of "supportsGetGeneratedKeys" property of
+   * the JDBC driver. In certain cases, getting (e.g. Oracle 10g) generated keys
+   * does not work because it returns the ROWID, not the value of the sequence.
+   * 
+   * @return A non null string, with "true" or "false" value, if overridden,
+   *         <code>null</code> if not overridden.
+   */
+  public String getOverriddenSupportsGetGeneratedKeys() {
+    return overriddenSupportsGetGeneratedKeys != null ? overriddenSupportsGetGeneratedKeys
+        .toString()
+        : null;
+  }
+
+  /**
+   * Sets the "overridden" value of "supportsGetGeneratedKeys" property of the
+   * JDBC driver. In certain cases, getting (e.g. Oracle 10g) generated keys
+   * does not work because it returns the ROWID, not the value of the sequence.
+   * 
+   * @param overriddenSupportsGetGeneratedKeys
+   *          A non null string, with "true" or "false" value, if overridden,
+   *          <code>null</code> if not overridden.
+   */
+  public void setOverriddenSupportsGetGeneratedKeys(
+      String overriddenSupportsGetGeneratedKeys) {
+    this.overriddenSupportsGetGeneratedKeys = Boolean
+        .valueOf(overriddenSupportsGetGeneratedKeys);
+  }
+  
+  /**
+   * Does this connection support batch updates?
+   */
+  public final boolean supportsBatchUpdates() {
+    return supportsBatchUpdates;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/CustomSQLDBReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/CustomSQLDBReceiver.java b/src/main/java/org/apache/log4j/db/CustomSQLDBReceiver.java
new file mode 100644
index 0000000..6c2d78b
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/CustomSQLDBReceiver.java
@@ -0,0 +1,468 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Hashtable;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.scheduler.Job;
+import org.apache.log4j.scheduler.Scheduler;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+/**
+ * Converts log data stored in a database into LoggingEvents.
+ * <p>
+ * <b>NOTE:</b> This receiver cannot yet be created through Chainsaw's receiver panel.  
+ * It must be created through an XML configuration file.
+ * <p>
+ * This receiver supports database configuration via ConnectionSource, in the
+ * org.apache.log4j.db package: DriverManagerConnectionSource,
+ * DataSourceConnectionSource, JNDIConnectionSource
+ * <p>
+ * This database receiver differs from DBReceiver in that this receiver relies
+ * on custom SQL to retrieve logging event data, where DBReceiver requires the
+ * use of a log4j-defined schema.
+ * <p>
+ * A 'refreshMillis' int parameter controls SQL execution. If 'refreshMillis' is
+ * zero (the default), the receiver will run only one time. If it is set to any
+ * other numeric value, the SQL will be executed on a recurring basis every
+ * 'refreshMillis' milliseconds.
+ * <p>
+ * The receiver closes the connection and acquires a new connection on each 
+ * execution of the SQL (use pooled connections if possible).
+ * <p>
+ * If the SQL will be executing on a recurring basis, specify the IDField param -
+ * the column name holding the unique identifier (int) representing the logging
+ * event.
+ * <p>
+ * As events are retrieved, the column represented by IDField is examined and
+ * the largest value is held and used by the next execution of the SQL statement
+ * to avoid retrieving previously processed events.
+ * <p>
+ * As an example, the IDField references a 'COUNTER' (int, auto-increment,
+ * unique) column. The first execution of the SQL statement returns 500 rows,
+ * with a final value in the COUNTER field of 500.
+ * <p>
+ * The SQL statement is manipulated prior to the next execution, adding ' WHERE
+ * COUNTER > 500' to the statement to avoid retrieval of previously processed
+ * events.
+ * <p>
+ * The select statement must provide ALL fields which define a LoggingEvent.
+ * <p>
+ * The SQL statement MUST include the columns: LOGGER, TIMESTAMP, LEVEL, THREAD,
+ * MESSAGE, NDC, MDC, CLASS, METHOD, FILE, LINE, PROPERTIES, THROWABLE
+ * <p>
+ * Use ' AS ' in the SQL statement to alias the SQL's column names to match your
+ * database schema. (see example below).
+ * <p>
+ * Include all fields in the SQL statement, even if you don't have data for the
+ * field (specify an empty string as the value for columns which you don't have
+ * data).
+ * <p>
+ * The TIMESTAMP column must be a datetime.
+ * <p>
+ * Both a PROPERTIES column and an MDC column are supported. These fields
+ * represent Maps on the logging event, but require the use of string
+ * concatenation database functions to hold the (possibly multiple) name/value
+ * pairs in the column.
+ * <p>
+ * For example, to include both 'userid' and 'lastname' properties in the
+ * logging event (from either the PROPERTIES or MDC columns), the name/value
+ * pairs must be concatenated together by your database.
+ * <p>
+ * The resulting PROPERTIES or MDC column must have data in this format: {{name,
+ * value, name2, value2}}
+ * <p>
+ * The resulting PROPERTIES column would contain this text: {{userid, someone,
+ * lastname, mylastname}}
+ * <p>
+ * Here is an example of concatenating a PROPERTIES or MDC column using MySQL's
+ * concat function, where the 'application' and 'hostname' parameters were fixed
+ * text, but the 'log4jid' key's value is the value of the COUNTER column:
+ * <p>
+ * concat("{{application,databaselogs,hostname,mymachine,log4jid,", COUNTER,
+ * "}}") as PROPERTIES
+ * <p>
+ * log4jid is a special property that is used by Chainsaw to represent an 'ID'
+ * field. Specify this property to ensure you can map events in Chainsaw to
+ * events in the database if you need to go back and view events at a later time
+ * or save the events to XML for later analysis.
+ * <p>
+ * Here is a complete MySQL SQL statement which can be used to provide events to
+ * Chainsaw (note how in the example below, there is no column in logtable representing the throwable, so an
+ * empty string is passed in and an ALIAS is still defined):
+ * <p>
+ * select myloggercolumn as LOGGER, mytimestampcolumn as TIMESTAMP, mylevelcolumn as LEVEL, mythreadcolumn as
+ * THREAD, mymessagecolumn as MESSAGE, myndccolumn as NDC, mymdccolumn as MDC, myclasscolumn as CLASS, mymethodcolumn as
+ * METHOD, myfilecolumn as FILE, mylinecolumn as LINE,
+ * concat("{{application,databaselogs,hostname,mymachine, log4jid,",
+ * COUNTER,"}}") as PROPERTIES, "" as THROWABLE from logtable
+ * <p>
+ * @author Scott Deboy <sd...@apache.org>
+ * <p>
+ */
+public class CustomSQLDBReceiver extends Receiver implements Pauseable, UnrecognizedElementHandler {
+
+    protected volatile Connection connection = null;
+
+    protected String sqlStatement = "";
+
+    /**
+     * By default we refresh data every 1000 milliseconds.
+     * 
+     * @see #setRefreshMillis
+     */
+    static int DEFAULT_REFRESH_MILLIS = 1000;
+
+    int refreshMillis = DEFAULT_REFRESH_MILLIS;
+
+    protected String idField = null;
+
+    int lastID = -1;
+
+    private static final String WHERE_CLAUSE = " WHERE ";
+
+    private static final String AND_CLAUSE = " AND ";
+
+    private boolean whereExists = false;
+
+    private boolean paused = false;
+
+    private ConnectionSource connectionSource;
+
+    public static final String LOG4J_ID_KEY = "log4jid";
+
+    private Job customReceiverJob;
+
+    public void activateOptions() {
+      
+      if(connectionSource == null)  {
+        throw new IllegalStateException(
+          "CustomSQLDBReceiver cannot function without a connection source");
+      }
+      whereExists = (sqlStatement.toUpperCase().indexOf(WHERE_CLAUSE) > -1);
+    
+      customReceiverJob = new CustomReceiverJob();
+        
+      if(this.repository == null) {
+        throw new IllegalStateException(
+        "CustomSQLDBReceiver cannot function without a reference to its owning repository");
+      }
+     
+    
+
+      if (repository instanceof LoggerRepositoryEx) {
+        Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+      
+        scheduler.schedule(
+          customReceiverJob, System.currentTimeMillis() + 500, refreshMillis);
+      }
+
+    }
+
+    void closeConnection() {
+        if (connection != null) {
+            try {
+                // LogLog.warn("closing the connection. ", new Exception("x"));
+                connection.close();
+            } catch (SQLException sqle) {
+                // nothing we can do here
+            }
+        }
+    }
+
+    public void setRefreshMillis(int refreshMillis) {
+        this.refreshMillis = refreshMillis;
+    }
+
+    public int getRefreshMillis() {
+        return refreshMillis;
+    }
+
+    /**
+     * @return Returns the connectionSource.
+     */
+    public ConnectionSource getConnectionSource() {
+        return connectionSource;
+    }
+
+    /**
+     * @param connectionSource
+     *            The connectionSource to set.
+     */
+    public void setConnectionSource(ConnectionSource connectionSource) {
+        this.connectionSource = connectionSource;
+    }
+
+    public void close() {
+        try {
+            if ((connection != null) && !connection.isClosed()) {
+                connection.close();
+            }
+        } catch (SQLException e) {
+            e.printStackTrace();
+        } finally {
+            connection = null;
+        }
+    }
+
+    public void finalize() throws Throwable {
+        super.finalize();
+        close();
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see org.apache.log4j.plugins.Plugin#shutdown()
+     */
+    public void shutdown() {
+        getLogger().info("removing receiverJob from the Scheduler.");
+
+        if(this.repository instanceof LoggerRepositoryEx) {
+          Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+          scheduler.delete(customReceiverJob);
+        }
+
+        lastID = -1;
+    }
+
+    public void setSql(String s) {
+        sqlStatement = s;
+    }
+
+    public String getSql() {
+        return sqlStatement;
+    }
+
+    public void setIDField(String id) {
+        idField = id;
+    }
+
+    public String getIDField() {
+        return idField;
+    }
+
+    public synchronized void setPaused(boolean p) {
+        paused = p;
+    }
+
+    public synchronized boolean isPaused() {
+        return paused;
+    }
+
+    class CustomReceiverJob implements Job {
+        public void execute() {
+            int oldLastID = lastID;
+            try {
+                connection = connectionSource.getConnection();
+                Statement statement = connection.createStatement();
+
+                Logger eventLogger = null;
+                long timeStamp = 0L;
+                String level = null;
+                String threadName = null;
+                Object message = null;
+                String ndc = null;
+                Hashtable mdc = null;
+                String[] throwable = null;
+                String className = null;
+                String methodName = null;
+                String fileName = null;
+                String lineNumber = null;
+                Hashtable properties = null;
+
+                String currentSQLStatement = sqlStatement;
+                if (whereExists) {
+                    currentSQLStatement = sqlStatement + AND_CLAUSE + idField
+                            + " > " + lastID;
+                } else {
+                    currentSQLStatement = sqlStatement + WHERE_CLAUSE + idField
+                            + " > " + lastID;
+                }
+
+                ResultSet rs = statement.executeQuery(currentSQLStatement);
+
+                int i = 0;
+                while (rs.next()) {
+                    // add a small break every 1000 received events
+                    if (++i == 1000) {
+                        synchronized (this) {
+                            try {
+                                // add a delay
+                                wait(300);
+                            } catch (InterruptedException ie) {
+                            }
+                            i = 0;
+                        }
+                    }
+                    eventLogger = Logger.getLogger(rs.getString("LOGGER"));
+                    timeStamp = rs.getTimestamp("TIMESTAMP").getTime();
+
+                    level = rs.getString("LEVEL");
+                    threadName = rs.getString("THREAD");
+                    message = rs.getString("MESSAGE");
+                    ndc = rs.getString("NDC");
+
+                    String mdcString = rs.getString("MDC");
+                    mdc = new Hashtable();
+
+                    if (mdcString != null) {
+                        // support MDC being wrapped in {{name, value}}
+                        // or
+                        // just name, value
+                        if ((mdcString.indexOf("{{") > -1)
+                                && (mdcString.indexOf("}}") > -1)) {
+                            mdcString = mdcString
+                                    .substring(mdcString.indexOf("{{") + 2,
+                                            mdcString.indexOf("}}"));
+                        }
+
+                        StringTokenizer tok = new StringTokenizer(mdcString,
+                                ",");
+
+                        while (tok.countTokens() > 1) {
+                            mdc.put(tok.nextToken(), tok.nextToken());
+                        }
+                    }
+
+                    throwable = new String[] { rs.getString("THROWABLE") };
+                    className = rs.getString("CLASS");
+                    methodName = rs.getString("METHOD");
+                    fileName = rs.getString("FILE");
+                    lineNumber = rs.getString("LINE");
+
+                    // if properties are provided in the
+                    // SQL they can be used here (for example, to route
+                    // events to a unique tab in
+                    // Chainsaw if the machinename and/or appname
+                    // property
+                    // are set)
+                    String propertiesString = rs.getString("PROPERTIES");
+                    properties = new Hashtable();
+
+                    if (propertiesString != null) {
+                        // support properties being wrapped in {{name,
+                        // value}} or just name, value
+                        if ((propertiesString.indexOf("{{") > -1)
+                                && (propertiesString.indexOf("}}") > -1)) {
+                            propertiesString = propertiesString.substring(
+                                    propertiesString.indexOf("{{") + 2,
+                                    propertiesString.indexOf("}}"));
+                        }
+
+                        StringTokenizer tok2 = new StringTokenizer(
+                                propertiesString, ",");
+                        while (tok2.countTokens() > 1) {
+                            String tokenName = tok2.nextToken();
+                            String value = tok2.nextToken();
+                            if (tokenName.equals(LOG4J_ID_KEY)) {
+                                try {
+                                    int thisInt = Integer.parseInt(value);
+                                    value = String.valueOf(thisInt);
+                                    if (thisInt > lastID) {
+                                        lastID = thisInt;
+                                    }
+                                } catch (Exception e) {
+                                }
+                            }
+                            properties.put(tokenName, value);
+                        }
+                    }
+
+                    Level levelImpl = Level.toLevel(level);
+
+
+					LocationInfo locationInfo = new LocationInfo(fileName,
+	                            className, methodName, lineNumber);
+	
+					ThrowableInformation throwableInfo =  new ThrowableInformation(
+		                            throwable);
+	
+					properties.putAll(mdc);
+		
+				    LoggingEvent event = new LoggingEvent(eventLogger.getName(),
+				            eventLogger, timeStamp, levelImpl, message,
+				            threadName,
+				            throwableInfo,
+				            ndc,
+				            locationInfo,
+				            properties);
+
+                    doPost(event);
+                }
+                //log when rows are retrieved
+                if (lastID != oldLastID) {
+                    getLogger().debug("lastID: " + lastID);
+                    oldLastID = lastID;
+                }
+
+                statement.close();
+                statement = null;
+            } catch (SQLException sqle) {
+                getLogger()
+                        .error("*************Problem receiving events", sqle);
+            } finally {
+                closeConnection();
+            }
+
+            // if paused, loop prior to executing sql query
+            synchronized (this) {
+                while (isPaused()) {
+                    try {
+                        wait(1000);
+                    } catch (InterruptedException ie) {
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * @{inheritDoc}
+     */
+  public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+        if ("connectionSource".equals(element.getNodeName())) {
+            Object instance =
+                    DOMConfigurator.parseElement(element, props, ConnectionSource.class);
+            if (instance instanceof ConnectionSource) {
+               ConnectionSource source = (ConnectionSource) instance;
+               source.activateOptions();
+               setConnectionSource(source);
+            }
+            return true;
+        }
+        return false;
+  }
+    
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DBAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DBAppender.java b/src/main/java/org/apache/log4j/db/DBAppender.java
new file mode 100644
index 0000000..15deac3
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DBAppender.java
@@ -0,0 +1,403 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.db.dialect.SQLDialect;
+import org.apache.log4j.db.dialect.Util;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+
+/**
+ * The DBAppender inserts loggin events into three database tables in a format
+ * independent of the Java programming language. The three tables that
+ * DBAppender inserts to must exists before DBAppender can be used. These tables
+ * may be created with the help of SQL scripts found in the
+ * <em>src/java/org/apache/log4j/db/dialect</em> directory. There is a
+ * specific script for each of the most popular database systems. If the script
+ * for your particular type of database system is missing, it should be quite
+ * easy to write one, taking example on the already existing scripts. If you
+ * send them to us, we will gladly include missing scripts in future releases.
+ *
+ * <p>
+ * If the JDBC driver you are using supports the
+ * {@link java.sql.Statement#getGeneratedKeys}method introduced in JDBC 3.0
+ * specification, then you are all set. Otherwise, there must be an
+ * {@link SQLDialect}appropriate for your database system. Currently, we have
+ * dialects for PostgreSQL, MySQL, Oracle and MsSQL. As mentioed previously, an
+ * SQLDialect is required only if the JDBC driver for your database system does
+ * not support the {@link java.sql.Statement#getGeneratedKeys getGeneratedKeys}
+ * method.
+ * </p>
+ *
+ * <table border="1" cellpadding="4">
+ * <tr>
+ * <th>RDBMS</th>
+ * <th>supports <br/><code>getGeneratedKeys()</code> method</th>
+ * <th>specific <br/>SQLDialect support</th>
+ * <tr>
+ * <tr>
+ * <td>PostgreSQL</td>
+ * <td align="center">NO</td>
+ * <td>present and used</td>
+ * <tr>
+ * <tr>
+ * <td>MySQL</td>
+ * <td align="center">YES</td>
+ * <td>present, but not actually needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>Oracle</td>
+ * <td align="center">YES</td>
+ * <td>present, but not actually needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>DB2</td>
+ * <td align="center">YES</td>
+ * <td>not present, and not needed or used</td>
+ * <tr>
+ * <tr>
+ * <td>MsSQL</td>
+ * <td align="center">YES</td>
+ * <td>not present, and not needed or used</td>
+ * <tr>
+ * <tr>
+ *   <td>HSQL</td>
+ *    <td align="center">NO</td>
+ *    <td>present and used</td>
+ * <tr>
+ *
+ * </table>
+ * <p>
+ * <b>Performance: </b> Experiments show that writing a single event into the
+ * database takes approximately 50 milliseconds, on a "standard" PC. If pooled
+ * connections are used, this figure drops to under 10 milliseconds. Note that
+ * most JDBC drivers already ship with connection pooling support.
+ * </p>
+ *
+ *
+ *
+ * <p>
+ * <b>Configuration </b> DBAppender can be configured programmatically, or using
+ * {@link org.apache.log4j.xml.DOMConfigurator JoranConfigurator}. Example
+ * scripts can be found in the <em>tests/input/db</em> directory.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ * @author Ray DeCampo
+ */
+public class DBAppender extends AppenderSkeleton implements UnrecognizedElementHandler {
+  static final String insertPropertiesSQL =
+    "INSERT INTO  logging_event_property (event_id, mapped_key, mapped_value) VALUES (?, ?, ?)";
+  static final String insertExceptionSQL =
+    "INSERT INTO  logging_event_exception (event_id, i, trace_line) VALUES (?, ?, ?)";
+  static final String insertSQL;
+  private static final Method GET_GENERATED_KEYS_METHOD;
+
+
+  static {
+    StringBuffer sql = new StringBuffer();
+    sql.append("INSERT INTO logging_event (");
+    sql.append("sequence_number, ");
+    sql.append("timestamp, ");
+    sql.append("rendered_message, ");
+    sql.append("logger_name, ");
+    sql.append("level_string, ");
+    sql.append("ndc, ");
+    sql.append("thread_name, ");
+    sql.append("reference_flag, ");
+    sql.append("caller_filename, ");
+    sql.append("caller_class, ");
+    sql.append("caller_method, ");
+    sql.append("caller_line) ");
+    sql.append(" VALUES (?, ?, ? ,?, ?, ?, ?, ?, ?, ?, ?, ?)");
+    insertSQL = sql.toString();
+    //
+    //   PreparedStatement.getGeneratedKeys added in JDK 1.4
+    //
+    Method getGeneratedKeysMethod;
+    try {
+        getGeneratedKeysMethod = PreparedStatement.class.getMethod("getGeneratedKeys", null);
+    } catch(Exception ex) {
+        getGeneratedKeysMethod = null;
+    }
+    GET_GENERATED_KEYS_METHOD = getGeneratedKeysMethod;
+  }
+
+  ConnectionSource connectionSource;
+  boolean cnxSupportsGetGeneratedKeys = false;
+  boolean cnxSupportsBatchUpdates = false;
+  SQLDialect sqlDialect;
+  boolean locationInfo = false;
+  
+
+  public DBAppender() {
+      super(false);
+  }
+
+  public void activateOptions() {
+    LogLog.debug("DBAppender.activateOptions called");
+
+    if (connectionSource == null) {
+      throw new IllegalStateException(
+        "DBAppender cannot function without a connection source");
+    }
+
+    sqlDialect = Util.getDialectFromCode(connectionSource.getSQLDialectCode());
+    if (GET_GENERATED_KEYS_METHOD != null) {
+        cnxSupportsGetGeneratedKeys = connectionSource.supportsGetGeneratedKeys();
+    } else {
+        cnxSupportsGetGeneratedKeys = false;
+    }
+    cnxSupportsBatchUpdates = connectionSource.supportsBatchUpdates();
+    if (!cnxSupportsGetGeneratedKeys && (sqlDialect == null)) {
+      throw new IllegalStateException(
+        "DBAppender cannot function if the JDBC driver does not support getGeneratedKeys method *and* without a specific SQL dialect");
+    }
+    
+    // all nice and dandy on the eastern front
+    super.activateOptions();
+  }
+
+  /**
+   * @return Returns the connectionSource.
+   */
+  public ConnectionSource getConnectionSource() {
+    return connectionSource;
+  }
+
+  /**
+   * @param connectionSource
+   *          The connectionSource to set.
+   */
+  public void setConnectionSource(ConnectionSource connectionSource) {
+    LogLog.debug("setConnectionSource called for DBAppender");
+    this.connectionSource = connectionSource;
+  }
+
+  protected void append(LoggingEvent event) {
+      Connection connection = null;
+      try {
+          connection = connectionSource.getConnection();
+          connection.setAutoCommit(false);
+          
+          PreparedStatement insertStatement;
+          if (cnxSupportsGetGeneratedKeys) {
+        	  insertStatement = connection.prepareStatement(insertSQL, Statement.RETURN_GENERATED_KEYS);
+          } else {
+              insertStatement = connection.prepareStatement(insertSQL);
+          }
+
+/*          insertStatement.setLong(1, event.getSequenceNumber());*/
+		  insertStatement.setLong(1, 0);
+		
+          insertStatement.setLong(2, event.getTimeStamp());
+          insertStatement.setString(3, event.getRenderedMessage());
+          insertStatement.setString(4, event.getLoggerName());
+          insertStatement.setString(5, event.getLevel().toString());
+          insertStatement.setString(6, event.getNDC());
+          insertStatement.setString(7, event.getThreadName());
+          insertStatement.setShort(8, DBHelper.computeReferenceMask(event));
+          
+          LocationInfo li;
+          
+          if (event.locationInformationExists() || locationInfo) {
+              li = event.getLocationInformation();
+          } else {
+              li = LocationInfo.NA_LOCATION_INFO;
+          }
+          
+          insertStatement.setString(9, li.getFileName());
+          insertStatement.setString(10, li.getClassName());
+          insertStatement.setString(11, li.getMethodName());
+          insertStatement.setString(12, li.getLineNumber());
+          
+          int updateCount = insertStatement.executeUpdate();
+          if (updateCount != 1) {
+              LogLog.warn("Failed to insert loggingEvent");
+          }
+          
+          ResultSet rs = null;
+          Statement idStatement = null;
+          boolean gotGeneratedKeys = false;
+          if (cnxSupportsGetGeneratedKeys) {
+              try {
+                  rs = (ResultSet) GET_GENERATED_KEYS_METHOD.invoke(insertStatement, null);
+                  gotGeneratedKeys = true;
+              } catch(InvocationTargetException ex) {
+                  Throwable target = ex.getTargetException();
+                  if (target instanceof SQLException) {
+                      throw (SQLException) target;
+                  }
+                  throw ex; 
+              } catch(IllegalAccessException ex) {
+                  LogLog.warn("IllegalAccessException invoking PreparedStatement.getGeneratedKeys", ex);
+              }
+          }
+          
+          if (!gotGeneratedKeys) {
+              insertStatement.close();
+              insertStatement = null;
+              
+              idStatement = connection.createStatement();
+              idStatement.setMaxRows(1);
+              rs = idStatement.executeQuery(sqlDialect.getSelectInsertId());
+          }
+          
+          // A ResultSet cursor is initially positioned before the first row; the 
+          // first call to the method next makes the first row the current row
+          rs.next();
+          int eventId = rs.getInt(1);
+          
+          rs.close();
+
+          // we no longer need the insertStatement
+          if(insertStatement != null) {
+              insertStatement.close();
+              insertStatement = null;
+          }
+
+          if(idStatement != null) {
+              idStatement.close();
+              idStatement = null;
+          }
+
+          Set propertiesKeys = event.getPropertyKeySet();
+          
+          if (propertiesKeys.size() > 0) {
+              PreparedStatement insertPropertiesStatement =
+                  connection.prepareStatement(insertPropertiesSQL);
+              
+              for (Iterator i = propertiesKeys.iterator(); i.hasNext();) {
+                  String key = (String) i.next();
+                  String value = (String) event.getProperty(key);
+                  
+                  //LogLog.info("id " + eventId + ", key " + key + ", value " + value);
+                  insertPropertiesStatement.setInt(1, eventId);
+                  insertPropertiesStatement.setString(2, key);
+                  insertPropertiesStatement.setString(3, value);
+                  
+                  if (cnxSupportsBatchUpdates) {
+                      insertPropertiesStatement.addBatch();
+                  } else {
+                      insertPropertiesStatement.execute();
+                  }
+              }
+              
+              if (cnxSupportsBatchUpdates) {
+                  insertPropertiesStatement.executeBatch();
+              }
+              
+              insertPropertiesStatement.close();
+              insertPropertiesStatement = null;
+          }
+          
+          String[] strRep = event.getThrowableStrRep();
+          
+          if (strRep != null) {
+              LogLog.debug("Logging an exception");
+              
+              PreparedStatement insertExceptionStatement =
+                  connection.prepareStatement(insertExceptionSQL);
+              
+              for (short i = 0; i < strRep.length; i++) {
+                  insertExceptionStatement.setInt(1, eventId);
+                  insertExceptionStatement.setShort(2, i);
+                  insertExceptionStatement.setString(3, strRep[i]);
+                  if (cnxSupportsBatchUpdates) {
+                      insertExceptionStatement.addBatch();
+                  } else {
+                      insertExceptionStatement.execute();
+                  }
+              }
+              if (cnxSupportsBatchUpdates) {
+                  insertExceptionStatement.executeBatch();
+              }
+              insertExceptionStatement.close();
+              insertExceptionStatement = null;
+          }
+          
+          connection.commit();
+      } catch (Throwable sqle) {
+          LogLog.error("problem appending event", sqle);
+      } finally {
+          DBHelper.closeConnection(connection);
+      }
+  }
+
+  public void close() {
+    closed = true;
+  }
+
+  /**
+   * Returns value of the <b>LocationInfo </b> property which determines whether
+   * caller's location info is written to the database.
+   */
+  public boolean getLocationInfo() {
+    return locationInfo;
+  }
+
+  /**
+   * If true, the information written to the database will include caller's
+   * location information. Due to performance concerns, by default no location
+   * information is written to the database.
+   */
+  public void setLocationInfo(boolean locationInfo) {
+    this.locationInfo = locationInfo;
+  }
+
+    /**
+     * Gets whether appender requires a layout.
+     * @return false
+     */
+  public boolean requiresLayout() {
+      return false;
+  }
+
+    /**
+     * @{inheritDoc}
+     */
+  public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+        if ("connectionSource".equals(element.getNodeName())) {
+            Object instance =
+                    DOMConfigurator.parseElement(element, props, ConnectionSource.class);
+            if (instance instanceof ConnectionSource) {
+               ConnectionSource source = (ConnectionSource) instance;
+               source.activateOptions();
+               setConnectionSource(source);
+            }
+            return true;
+        }
+        return false;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DBHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DBHelper.java b/src/main/java/org/apache/log4j/db/DBHelper.java
new file mode 100644
index 0000000..b400506
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DBHelper.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Set;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * @author Ceki G&uuml;lc&uuml;
+ *
+ */
+public class DBHelper {
+  
+  public final static short PROPERTIES_EXIST = 0x01;
+  public final static short EXCEPTION_EXISTS = 0x02;
+  
+  public  static short computeReferenceMask(LoggingEvent event) {
+    short mask = 0;
+    Set propertiesKeys = event.getPropertyKeySet();
+    if(propertiesKeys.size() > 0) {
+      mask = PROPERTIES_EXIST;
+    }
+    String[] strRep = event.getThrowableStrRep();
+    if(strRep != null) {
+      mask |= EXCEPTION_EXISTS;
+    }
+    return mask;
+  }
+  
+  static public void closeConnection(Connection connection) {
+    if(connection != null) {
+      try { 
+        connection.close();
+      } catch(SQLException sqle) {
+        // static utility classes should not log without an explicit repository
+        // reference
+      }
+    }
+  }
+  
+  public static void closeStatement(Statement statement) {
+    if(statement != null) {
+      try {
+        statement.close();
+      } catch(SQLException sqle) {
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/db/DBReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/db/DBReceiver.java b/src/main/java/org/apache/log4j/db/DBReceiver.java
new file mode 100644
index 0000000..eee1068
--- /dev/null
+++ b/src/main/java/org/apache/log4j/db/DBReceiver.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.db;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.scheduler.Scheduler;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+import java.util.Properties;
+
+/**
+ *
+ * @author Scott Deboy <sd...@apache.org>
+ * @author Ceki G&uuml;lc&uuml;
+ *
+ */
+public class DBReceiver extends Receiver implements Pauseable, UnrecognizedElementHandler {
+  /**
+   * By default we refresh data every 1000 milliseconds.
+   * @see #setRefreshMillis
+   */
+  static int DEFAULT_REFRESH_MILLIS = 1000;
+  ConnectionSource connectionSource;
+  int refreshMillis = DEFAULT_REFRESH_MILLIS;
+  DBReceiverJob receiverJob;
+  boolean paused = false;
+
+  public void activateOptions() {
+    
+    if(connectionSource == null)  {
+      throw new IllegalStateException(
+        "DBAppender cannot function without a connection source");
+    }
+  
+    receiverJob = new DBReceiverJob(this);
+    receiverJob.setLoggerRepository(repository);
+      
+    if(this.repository == null) {
+      throw new IllegalStateException(
+      "DBAppender cannot function without a reference to its owning repository");
+    }
+
+    if (repository instanceof LoggerRepositoryEx) {
+        Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+    
+        scheduler.schedule(
+            receiverJob, System.currentTimeMillis() + 500, refreshMillis);
+    }
+   
+  }
+
+  public void setRefreshMillis(int refreshMillis) {
+    this.refreshMillis = refreshMillis;
+  }
+
+  public int getRefreshMillis() {
+    return refreshMillis;
+  }
+
+
+  /**
+   * @return Returns the connectionSource.
+   */
+  public ConnectionSource getConnectionSource() {
+    return connectionSource;
+  }
+
+
+  /**
+   * @param connectionSource The connectionSource to set.
+   */
+  public void setConnectionSource(ConnectionSource connectionSource) {
+    this.connectionSource = connectionSource;
+  }
+
+
+  /* (non-Javadoc)
+   * @see org.apache.log4j.plugins.Plugin#shutdown()
+   */
+  public void shutdown() {
+    getLogger().info("removing receiverJob from the Scheduler.");
+
+    if(this.repository instanceof LoggerRepositoryEx) {
+      Scheduler scheduler = ((LoggerRepositoryEx) repository).getScheduler();
+      scheduler.delete(receiverJob);
+    }
+  }
+
+
+  /* (non-Javadoc)
+   * @see org.apache.log4j.plugins.Pauseable#setPaused(boolean)
+   */
+  public void setPaused(boolean paused) {
+    this.paused = paused;
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.log4j.plugins.Pauseable#isPaused()
+   */
+  public boolean isPaused() {
+    return paused;
+  }
+
+    /**
+     * @{inheritDoc}
+     */
+  public boolean parseUnrecognizedElement(Element element, Properties props) throws Exception {
+        if ("connectionSource".equals(element.getNodeName())) {
+            Object instance =
+                    DOMConfigurator.parseElement(element, props, ConnectionSource.class);
+            if (instance instanceof ConnectionSource) {
+                ConnectionSource source = (ConnectionSource) instance;
+                source.activateOptions();
+                setConnectionSource(source);
+            }
+            return true;
+        }
+        return false;
+  }
+
+}


[12/50] [abbrv] logging-chainsaw git commit: Slight improvements to UI fidelity (on Mac) - ok/cancel button order is cancel/ok on Mac, ok/cancel everywhere else - use 'FileDialog' instead of JFileChooser on Mac since it looks more like a native Mac fil

Posted by rg...@apache.org.
Slight improvements to UI fidelity (on Mac)
 - ok/cancel button order is cancel/ok on Mac, ok/cancel everywhere else
 - use 'FileDialog' instead of JFileChooser on Mac since it looks more like a native Mac file-open dialog


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/98f2a549
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/98f2a549
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/98f2a549

Branch: refs/heads/master
Commit: 98f2a549255b1a4b0a8c766995a521bf3f7457a0
Parents: 4c8ba76
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Oct 30 18:58:21 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Oct 30 18:58:21 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/AbstractPreferencePanel.java | 10 ++--
 .../ApplicationPreferenceModelPanel.java        | 17 +++---
 .../apache/log4j/chainsaw/FileLoadAction.java   | 35 ++----------
 .../chainsaw/ReceiverConfigurationPanel.java    | 58 ++++++--------------
 .../log4j/chainsaw/helper/SwingHelper.java      | 57 +++++++++++++++++++
 5 files changed, 90 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/98f2a549/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java b/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
index 50adbc6..89e4e5f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/AbstractPreferencePanel.java
@@ -23,6 +23,7 @@ import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.event.ActionListener;
 import java.util.Enumeration;
+import java.util.List;
 
 import javax.swing.BorderFactory;
 import javax.swing.Box;
@@ -42,6 +43,7 @@ import javax.swing.tree.TreeModel;
 import javax.swing.tree.TreePath;
 import javax.swing.tree.TreeSelectionModel;
 
+import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
 /**
  * Some basic plumbing for Preference related dialogs.
@@ -106,14 +108,12 @@ public abstract class AbstractPreferencePanel extends JPanel
   
     add(mainPanel, BorderLayout.CENTER);
   
-  
-
-  
     Box buttonBox = Box.createHorizontalBox();
+    List buttons = SwingHelper.orderOKCancelButtons(okButton, cancelButton);
     buttonBox.add(Box.createHorizontalGlue());
-    buttonBox.add(okButton);
+    buttonBox.add((JButton)buttons.get(0));
     buttonBox.add(Box.createHorizontalStrut(10));
-    buttonBox.add(cancelButton);
+    buttonBox.add((JButton)buttons.get(1));
   
     add(buttonBox, BorderLayout.SOUTH);
   

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/98f2a549/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index 35457be..64cba35 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -40,7 +40,6 @@ import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
-import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JOptionPane;
@@ -58,6 +57,7 @@ import javax.swing.tree.TreeModel;
 
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.chainsaw.osx.OSXIntegration;
 
 
@@ -509,7 +509,7 @@ public static void main(String[] args) {
 
       p6.add(configURLPanel);
 
-      JButton browseButton = new JButton(" Browse ");
+      JButton browseButton = new JButton(" Open File... ");
       browseButton.addActionListener(new ActionListener()
       {
           public void actionPerformed(ActionEvent e)
@@ -552,7 +552,7 @@ public static void main(String[] args) {
                   File currentConfigurationPath = new File(selectedItem.toString()).getParentFile();
                   if (currentConfigurationPath != null) {
                       defaultPath = currentConfigurationPath.getPath();
-                      //JFileChooser constructor will not navigate to this location unless we remove the prefixing protocol and slash
+                      //FileDialog will not navigate to this location unless we remove the prefixing protocol and slash
                       //at least on winxp
                       if (defaultPath.toLowerCase().startsWith("file:\\")) {
                           defaultPath = defaultPath.substring("file:\\".length());
@@ -560,14 +560,11 @@ public static void main(String[] args) {
                   }
               }
           }
-
-          JFileChooser chooser = new JFileChooser(defaultPath);
-          int result = chooser.showOpenDialog(ApplicationPreferenceModelPanel.this);
-          if (JFileChooser.APPROVE_OPTION == result) {
-              File f = chooser.getSelectedFile();
+      File selectedFile = SwingHelper.promptForFile(this, defaultPath, "Select a Chainsaw configuration file");
+      if (selectedFile != null) {
               try
               {
-                  String newConfigurationFile = f.toURI().toURL().toExternalForm();
+                  String newConfigurationFile = selectedFile.toURI().toURL().toExternalForm();
                   if (!committedPreferenceModel.getConfigurationURLs().contains(newConfigurationFile)) {
                     configurationURL.addItem(newConfigurationFile);
                   }
@@ -575,7 +572,7 @@ public static void main(String[] args) {
               }
               catch (MalformedURLException e1)
               {
-                  e1.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
+                  e1.printStackTrace();
               }
           }
       }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/98f2a549/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java b/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
index d5432e5..638bc50 100644
--- a/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
+++ b/src/main/java/org/apache/log4j/chainsaw/FileLoadAction.java
@@ -27,11 +27,10 @@ import java.util.Map;
 import java.util.Vector;
 
 import javax.swing.AbstractAction;
-import javax.swing.JFileChooser;
 import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileFilter;
 
 import org.apache.log4j.Logger;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.chainsaw.prefs.MRUFileList;
 import org.apache.log4j.helpers.Constants;
 import org.apache.log4j.spi.Decoder;
@@ -57,8 +56,6 @@ class FileLoadAction extends AbstractAction {
 
     private LogUI parent;
 
-    private JFileChooser chooser = null;
-
     private boolean remoteURL = false;
 
     public FileLoadAction(LogUI parent, Decoder decoder, String title,
@@ -81,35 +78,13 @@ class FileLoadAction extends AbstractAction {
         String name = "";
         URL url = null;
 
-        if (!remoteURL) {
-            if (chooser == null) {
-                chooser = new JFileChooser();
-
-                chooser.setDialogTitle("Load Events from XML file...");
-
-                chooser.setAcceptAllFileFilterUsed(true);
-
-                chooser.setFileFilter(new FileFilter() {
-                    public boolean accept(File f) {
-                        return (f.getName().toLowerCase().endsWith(".xml") || f.getName().toLowerCase().endsWith(".zip")
-                                || f.isDirectory());
-                    }
-
-                    public String getDescription() {
-                        return "XML files (*.xml), ZIP files (*.zip)";
-                    }
-                });
-            }
-
-            int i = chooser.showOpenDialog(parent);
-            if (i != JFileChooser.APPROVE_OPTION) {
-                return;
-            }
-            File selectedFile = chooser.getSelectedFile();
-
+      if (!remoteURL) {
             try {
+              File selectedFile = SwingHelper.promptForFile(parent, null, "Load Events from XML file or zipped XML file...");
+              if (selectedFile != null) {
                 url = selectedFile.toURI().toURL();
                 name = selectedFile.getName();
+              }
             } catch (Exception ex) {
                 // TODO: handle exception
             }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/98f2a549/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index fbd4c22..8f276f1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -29,6 +29,7 @@ import java.awt.event.FocusListener;
 import java.io.File;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.util.List;
 
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
@@ -37,7 +38,6 @@ import javax.swing.DefaultComboBoxModel;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
-import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -45,13 +45,13 @@ import javax.swing.JRadioButton;
 import javax.swing.JTextField;
 import javax.swing.JTextPane;
 import javax.swing.SwingUtilities;
-import javax.swing.filechooser.FileFilter;
 import javax.swing.text.SimpleAttributeSet;
 import javax.swing.text.StyleConstants;
 import javax.swing.text.StyledDocument;
 
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
+import org.apache.log4j.chainsaw.helper.SwingHelper;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
 import org.apache.log4j.net.SocketReceiver;
 import org.apache.log4j.net.UDPReceiver;
@@ -210,20 +210,24 @@ class ReceiverConfigurationPanel extends JPanel {
         dontwarnIfNoReceiver = new JCheckBox("Always start Chainsaw with this configuration");
         panel.add(dontwarnIfNoReceiver, c);
 
+        okButton = new JButton(" OK ");
+        cancelButton = new JButton(" Cancel ");
+
+        List okCancelButtons = SwingHelper.orderOKCancelButtons(okButton, cancelButton);
+
         c = new GridBagConstraints();
         c.fill = GridBagConstraints.HORIZONTAL;
         c.gridx = 1;
         c.gridy = 0;
         c.insets = new Insets(0, 0, 0, 10);
-        okButton = new JButton(" OK ");
-        panel.add(okButton, c);
+        panel.add((JButton)okCancelButtons.get(0), c);
 
         c = new GridBagConstraints();
         c.fill = GridBagConstraints.HORIZONTAL;
         c.gridx = 2;
         c.gridy = 0;
-        cancelButton = new JButton(" Cancel ");
-        panel.add(cancelButton, c);
+        panel.add((JButton)okCancelButtons.get(1), c);
+
         cancelButton.addActionListener(new ActionListener()
         {
             public void actionPerformed(ActionEvent e)
@@ -308,7 +312,7 @@ class ReceiverConfigurationPanel extends JPanel {
 
     private JPanel buildLogFileReceiverPanel() {
         JPanel panel = new JPanel(new GridBagLayout());
-        browseLogFileButton = new JButton(new AbstractAction(" Find a log file ") {
+        browseLogFileButton = new JButton(new AbstractAction(" Open File... ") {
             public void actionPerformed(ActionEvent e) {
                 try {
 
@@ -465,7 +469,7 @@ class ReceiverConfigurationPanel extends JPanel {
                 }
             });
 
-        browseForAnExistingConfigurationButton = new JButton(new AbstractAction(" Find an existing configuration ") {
+        browseForAnExistingConfigurationButton = new JButton(new AbstractAction(" Open File... ") {
                     public void actionPerformed(ActionEvent e) {
                         try {
 
@@ -549,39 +553,15 @@ class ReceiverConfigurationPanel extends JPanel {
      * or null if they cancelled.
      */
     private URL browseConfig() throws MalformedURLException {
-
-        JFileChooser chooser = new JFileChooser();
-        chooser.setDialogTitle("Use an existing configuration file...");
-        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
-        chooser.setFileFilter(new FileFilter() {
-                public boolean accept(File f) {
-
-                    return f.isDirectory() ||
-                    f.getName().endsWith(".properties") ||
-                    f.getName().endsWith(".xml");
-                }
-
-                public String getDescription() {
-
-                    return "Log4j Configuration file";
-                }
-            });
-
-        chooser.showOpenDialog(this);
-
-        File selectedFile = chooser.getSelectedFile();
-
+        File selectedFile = SwingHelper.promptForFile(this, null, "Choose a Chainsaw configuration file");
         if (selectedFile == null) {
-
             return null;
         }
 
         if (!selectedFile.exists() || !selectedFile.canRead()) {
-
             return null;
         }
-
-        return chooser.getSelectedFile().toURI().toURL();
+        return selectedFile.toURI().toURL();
     }
 
     /**
@@ -590,13 +570,7 @@ class ReceiverConfigurationPanel extends JPanel {
      */
     private URL browseLogFile() throws MalformedURLException {
 
-        JFileChooser chooser = new JFileChooser();
-        chooser.setDialogTitle("Browse for a log file...");
-        chooser.setDialogType(JFileChooser.OPEN_DIALOG);
-        chooser.showOpenDialog(this);
-
-        File selectedFile = chooser.getSelectedFile();
-
+        File selectedFile = SwingHelper.promptForFile(this, null, "Select a log file");
         if (selectedFile == null) {
             return null;
         }
@@ -605,7 +579,7 @@ class ReceiverConfigurationPanel extends JPanel {
             return null;
         }
 
-        return chooser.getSelectedFile().toURI().toURL();
+        return selectedFile.toURI().toURL();
     }
 
     public static void main(String[] args) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/98f2a549/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
index f10b441..018e45c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
@@ -18,11 +18,17 @@
 package org.apache.log4j.chainsaw.helper;
 
 import java.awt.Component;
+import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.FileDialog;
+import java.awt.Frame;
 import java.awt.Toolkit;
 import java.awt.EventQueue;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -30,6 +36,7 @@ import javax.swing.InputMap;
 import javax.swing.JButton;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
+import javax.swing.JFileChooser;
 import javax.swing.KeyStroke;
 
 /**
@@ -82,4 +89,54 @@ public final class SwingHelper {
       EventQueue.invokeLater(runnable);
     }
   }
+
+  public static boolean isMacOSX() {
+    return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
+  }
+
+  public static List orderOKCancelButtons(JButton okButton, JButton cancelButton) {
+    List result = new ArrayList();
+    if (isMacOSX()) {
+      result.add(cancelButton);
+      result.add(okButton);
+    } else {
+      result.add(okButton);
+      result.add(cancelButton);
+    }
+    return result;
+  }
+
+  public static File promptForFile(Container parent, String defaultPath, String title) {
+        if (SwingHelper.isMacOSX()) {
+            //use filedialog on mac
+            FileDialog fileDialog = new FileDialog((Frame)null, title);
+            if (defaultPath != null) {
+              fileDialog.setDirectory(defaultPath);
+            }
+            fileDialog.setVisible(true);
+            String fileString = fileDialog.getFile();
+            if (fileString == null) {
+              return null;
+            }
+            return new File(fileString);
+          } else {
+
+                JFileChooser chooser;
+                if (defaultPath != null) {
+                  chooser = new JFileChooser(defaultPath);
+                } else {
+                  chooser = new JFileChooser();
+                }
+
+                chooser.setDialogTitle(title);
+
+                chooser.setAcceptAllFileFilterUsed(true);
+
+                int i = chooser.showOpenDialog(parent);
+                if (i != JFileChooser.APPROVE_OPTION) {
+                    return null;
+                }
+            return chooser.getSelectedFile();
+        }
+    }
 }


[11/50] [abbrv] logging-chainsaw git commit: Support URLs that start with protocol:/ as well as protocol://

Posted by rg...@apache.org.
Support URLs that start with protocol:/ as well as protocol://


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/4c8ba760
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/4c8ba760
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/4c8ba760

Branch: refs/heads/master
Commit: 4c8ba7609f5efbf039e3fdc0649fcce0ac6aa0e0
Parents: 51e80e4
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Oct 29 07:42:02 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Oct 29 07:42:02 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java  | 13 +++++++++++++
 1 file changed, 13 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/4c8ba760/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
index 982b298..fadc480 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
@@ -302,7 +302,20 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
     	  		  });
     		  }}).start();
       } else {
+        //starts with protocol:/  but not protocol://
         String oldURL = getFileURL();
+        if (oldURL != null && oldURL.indexOf(":/") > -1 && oldURL.indexOf("://") == -1) {
+          int index = oldURL.indexOf(":/");
+          String lastPart = oldURL.substring(index + ":/".length());
+          int passEndIndex = lastPart.indexOf("@");
+          if (passEndIndex > -1) { //we have a username/password
+              setHost(oldURL.substring(0, index + ":/".length()));
+              setPath(lastPart.substring(passEndIndex + 1));
+          }
+          vfsReader = new VFSReader();
+          new Thread(vfsReader).start();
+        }
+        //starts with protocol://
         if (oldURL != null && oldURL.indexOf("://") > -1) {
             int index = oldURL.indexOf("://");
             String lastPart = oldURL.substring(index + "://".length());


[42/50] [abbrv] logging-chainsaw git commit: Remove optional leading and trailing spaces around LEVEL and LOGGER definitions

Posted by rg...@apache.org.
Remove optional leading and trailing spaces around LEVEL and LOGGER definitions

Supports parsing of log entries where the start of the entry is a right-aligned level


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/e55aeec4
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/e55aeec4
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/e55aeec4

Branch: refs/heads/master
Commit: e55aeec49804cd61ff8e490ab2db0b141e0b8f84
Parents: ef6872d
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Feb 21 05:29:20 2013 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Feb 21 05:29:20 2013 +0000

----------------------------------------------------------------------
 src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e55aeec4/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index 4430205..c4fb451 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -157,7 +157,8 @@ public class LogFilePatternReceiver extends Receiver {
   private static final String REGEXP_DEFAULT_WILDCARD = ".*?";
   private static final String REGEXP_GREEDY_WILDCARD = ".*";
   private static final String PATTERN_WILDCARD = "*";
-  private static final String NOSPACE_GROUP = "(\\S*\\s*?)";
+  //pull in optional leading and trailing spaces
+  private static final String NOSPACE_GROUP = "(\\s*?\\S*?\\s*?)";
   private static final String DEFAULT_GROUP = "(" + REGEXP_DEFAULT_WILDCARD + ")";
   private static final String GREEDY_GROUP = "(" + REGEXP_GREEDY_WILDCARD + ")";
   private static final String MULTIPLE_SPACES_REGEXP = "[ ]+";


[23/50] [abbrv] logging-chainsaw git commit: Add ID field as a column that can be added to refine focus & find field via context menu

Posted by rg...@apache.org.
Add ID field as a column that can be added to refine focus & find field via context menu


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/a9a78bf9
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/a9a78bf9
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/a9a78bf9

Branch: refs/heads/master
Commit: a9a78bf99de4ba4ff0287f6907aab084a294a7ce
Parents: b108e6a
Author: Scott Deboy <sd...@apache.org>
Authored: Sun Nov 7 01:52:52 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sun Nov 7 01:52:52 2010 +0000

----------------------------------------------------------------------
 src/main/java/org/apache/log4j/chainsaw/LogPanel.java | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/a9a78bf9/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index b7a376f..7bdd00d 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -309,6 +309,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     columnNameKeywordMap.put(ChainsawConstants.THREAD_COL_NAME, LoggingEventFieldResolver.THREAD_FIELD);
     columnNameKeywordMap.put(ChainsawConstants.THROWABLE_COL_NAME, LoggingEventFieldResolver.EXCEPTION_FIELD);
     columnNameKeywordMap.put(ChainsawConstants.TIMESTAMP_COL_NAME, LoggingEventFieldResolver.TIMESTAMP_FIELD);
+    columnNameKeywordMap.put(ChainsawConstants.ID_COL_NAME.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + Constants.LOG4J_ID_KEY);
     columnNameKeywordMap.put(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE);
     columnNameKeywordMap.put(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE.toUpperCase(), LoggingEventFieldResolver.PROP_FIELD + ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE);
 


[32/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/xml/xsltLayout.1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/xml/xsltLayout.1.xml b/src/test/resources/org/apache/log4j/xml/xsltLayout.1.xml
new file mode 100644
index 0000000..596e84d
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/xml/xsltLayout.1.xml
@@ -0,0 +1,139 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+ 
+       http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase$X" time="2007-08-15T16:42:31.821Z" timestamp="1187196151821" level="INFO" thread="main">
+<log4j:message>in X() constructor</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.252Z" timestamp="1187196152252" level="DEBUG" thread="main">
+<log4j:message>Message 0</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.254Z" timestamp="1187196152254" level="DEBUG" thread="main">
+<log4j:message>Message 0</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.263Z" timestamp="1187196152263" level="INFO" thread="main">
+<log4j:message>Message 1</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.264Z" timestamp="1187196152264" level="INFO" thread="main">
+<log4j:message>Message 1</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.268Z" timestamp="1187196152268" level="WARN" thread="main">
+<log4j:message>Message 2</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.269Z" timestamp="1187196152269" level="WARN" thread="main">
+<log4j:message>Message 2</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.271Z" timestamp="1187196152271" level="ERROR" thread="main">
+<log4j:message>Message 3</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.272Z" timestamp="1187196152272" level="ERROR" thread="main">
+<log4j:message>Message 3</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.273Z" timestamp="1187196152273" level="FATAL" thread="main">
+<log4j:message>Message 4</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.275Z" timestamp="1187196152275" level="FATAL" thread="main">
+<log4j:message>Message 4</log4j:message>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.279Z" timestamp="1187196152279" level="DEBUG" thread="main">
+<log4j:message>Message 5</log4j:message>
+<log4j:throwable>java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XSLTLayoutTestCase.common(XSLTLayoutTestCase.java:201)
+	at org.apache.log4j.xml.XSLTLayoutTestCase.testBasic(XSLTLayoutTestCase.java:65)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+</log4j:throwable>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.304Z" timestamp="1187196152304" level="DEBUG" thread="main">
+<log4j:message>Message 5</log4j:message>
+<log4j:throwable>java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XSLTLayoutTestCase.common(XSLTLayoutTestCase.java:201)
+	at org.apache.log4j.xml.XSLTLayoutTestCase.testBasic(XSLTLayoutTestCase.java:65)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+</log4j:throwable>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="org.apache.log4j.xml.XSLTLayoutTestCase" time="2007-08-15T16:42:32.308Z" timestamp="1187196152308" level="ERROR" thread="main">
+<log4j:message>Message 6</log4j:message>
+<log4j:throwable>java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XSLTLayoutTestCase.common(XSLTLayoutTestCase.java:201)
+	at org.apache.log4j.xml.XSLTLayoutTestCase.testBasic(XSLTLayoutTestCase.java:65)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+</log4j:throwable>
+</log4j:event>
+<log4j:event xmlns:log4j="http://jakarta.apache.org/log4j/" logger="root" time="2007-08-15T16:42:32.312Z" timestamp="1187196152312" level="ERROR" thread="main">
+<log4j:message>Message 6</log4j:message>
+<log4j:throwable>java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XSLTLayoutTestCase.common(XSLTLayoutTestCase.java:201)
+	at org.apache.log4j.xml.XSLTLayoutTestCase.testBasic(XSLTLayoutTestCase.java:65)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+</log4j:throwable>
+</log4j:event>


[44/50] [abbrv] logging-chainsaw git commit: Committing in-progress work to support Log4j2 fileappender configurations advertised via Multicast DNS

Posted by rg...@apache.org.
Committing in-progress work to support Log4j2  fileappender configurations advertised via Multicast DNS



Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/647f6918
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/647f6918
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/647f6918

Branch: refs/heads/master
Commit: 647f6918200f2f0735782d21af31945c634fa336
Parents: 7e8c583
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Feb 28 08:33:36 2013 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Feb 28 08:33:36 2013 +0000

----------------------------------------------------------------------
 pom.xml                                         |  6 +--
 .../log4j/chainsaw/zeroconf/ZeroConfPlugin.java | 48 +++++++++++++++++++-
 2 files changed, 50 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/647f6918/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 182eab5..29ea0ba 100644
--- a/pom.xml
+++ b/pom.xml
@@ -389,10 +389,10 @@
       <version>1.2.16</version>
     </dependency>
     <dependency>
-      <groupId>jmdns</groupId>
+      <groupId>javax.jmdns</groupId>
       <artifactId>jmdns</artifactId>
-      <version>1.0</version>
-    </dependency>    
+      <version>3.4.1</version>
+    </dependency>
     <dependency>
       <groupId>xstream</groupId>
       <artifactId>xstream</artifactId>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/647f6918/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
index 369e9d8..9fedd69 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
@@ -52,11 +52,13 @@ import org.apache.log4j.BasicConfigurator;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.ChainsawConstants;
+import org.apache.log4j.chainsaw.LogFilePatternLayoutBuilder;
 import org.apache.log4j.chainsaw.SmallButton;
 import org.apache.log4j.chainsaw.help.HelpManager;
 import org.apache.log4j.chainsaw.icons.ChainsawIcons;
 import org.apache.log4j.chainsaw.plugins.GUIPluginSkeleton;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
+import org.apache.log4j.chainsaw.vfs.VFSLogFilePatternReceiver;
 import org.apache.log4j.helpers.LogLog;
 import org.apache.log4j.net.MulticastReceiver;
 import org.apache.log4j.net.SocketHubReceiver;
@@ -116,6 +118,9 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
     private static final String XML_SOCKET_APPENDER_SERVICE_NAME = "_log4j_xml_tcpconnect_appender.local.";
     private static final String SOCKET_APPENDER_SERVICE_NAME = "_log4j_obj_tcpconnect_appender.local.";
     private static final String SOCKETHUB_APPENDER_SERVICE_NAME = "_log4j_obj_tcpaccept_appender.local.";
+    private static final String TCP_APPENDER_SERVICE_NAME = "_log4j._tcp.local.";
+    private static final String NEW_UDP_APPENDER_SERVICE_NAME = "_log4j._udp.local.";
+
     private JmDNS jmDNS;
 
     public ZeroConfPlugin() {
@@ -125,7 +130,11 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
 
     public void shutdown() {
         if (jmDNS != null) {
-            jmDNS.close();
+            try {
+                jmDNS.close();
+            } catch (Exception e) {
+                LOG.error("Unable to close JMDNS", e);
+            }
         }
         save();
     }
@@ -207,6 +216,8 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
         serviceNames.add(SOCKETHUB_APPENDER_SERVICE_NAME);
         serviceNames.add(UDP_APPENDER_SERVICE_NAME);
         serviceNames.add(XML_SOCKET_APPENDER_SERVICE_NAME);
+        serviceNames.add(TCP_APPENDER_SERVICE_NAME);
+        serviceNames.add(NEW_UDP_APPENDER_SERVICE_NAME);
 
         for (Iterator iter = serviceNames.iterator(); iter.hasNext();) {
             String serviceName = iter.next().toString();
@@ -489,6 +500,41 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
         String name = info.getName();
         String decoderClass = info.getPropertyString("decoder");
 
+        if (NEW_UDP_APPENDER_SERVICE_NAME.equals(zone))
+        {
+            UDPReceiver receiver = new UDPReceiver();
+            receiver.setPort(port);
+            receiver.setName(name + "-receiver");
+            return receiver;
+        }
+        //FileAppender or socketappender
+        //TODO: add more checks (actual layout format, etc)
+        if (TCP_APPENDER_SERVICE_NAME.equals(zone)) {
+            //CHECK content type
+            //application/octet-stream = SocketReceiver
+            //text/plain = VFSLogFilePatternReceiver (if structured=false)
+            String contentType = info.getPropertyString("contentType").toLowerCase();
+            //won't work with log4j2, as Chainsaw depends on log4j1.x
+            if ("application/octet-stream".equals(contentType))
+            {
+                SocketReceiver receiver = new SocketReceiver();
+                receiver.setPort(port);
+                receiver.setName(name + "-receiver");
+                return receiver;
+            }
+            //this will work - regular text log files are fine
+            if ("text/plain".equals(contentType))
+            {
+                VFSLogFilePatternReceiver receiver = new VFSLogFilePatternReceiver();
+                receiver.setAppendNonMatches(true);
+                receiver.setFileURL(info.getPropertyString("fileURI"));
+                receiver.setLogFormat(LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(info.getPropertyString("format")));
+                receiver.setTimestampFormat(LogFilePatternLayoutBuilder.getTimeStampFormat(info.getPropertyString("format")));
+                receiver.setName(name + "-receiver");
+                return receiver;
+            }
+        }
+
         //MulticastAppender
         if (MULTICAST_APPENDER_SERVICE_NAME.equals(zone)) {
             MulticastReceiver receiver = new MulticastReceiver();


[14/50] [abbrv] logging-chainsaw git commit: Remember and set as default the last log format in the receiver config screen

Posted by rg...@apache.org.
Remember and set as default the last log format in the receiver config screen


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/1d47127d
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/1d47127d
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/1d47127d

Branch: refs/heads/master
Commit: 1d47127dedb3c7bfc48e69d74ead35ddce95a2a5
Parents: 5617df5
Author: Scott Deboy <sd...@apache.org>
Authored: Thu Nov 4 05:57:05 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Thu Nov 4 05:57:05 2010 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 61 +++-----------------
 .../chainsaw/ReceiverConfigurationPanel.java    | 61 +++++++-------------
 2 files changed, 29 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/1d47127d/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 57746f1..12502f3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -204,8 +204,9 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
   private PluginRegistry pluginRegistry;
   //map of tab names to rulecolorizers
   private Map allColorizers = new HashMap();
+  private ReceiverConfigurationPanel receiverConfigurationPanel = new ReceiverConfigurationPanel();
 
-    /**
+  /**
    * Constructor which builds up all the visual elements of the frame including
    * the Menu bar
    */
@@ -713,6 +714,9 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     RuleColorizer colorizer = new RuleColorizer();
     colorizer.loadColorSettings(ChainsawConstants.DEFAULT_COLOR_RULE_NAME);
     allColorizers.put(ChainsawConstants.DEFAULT_COLOR_RULE_NAME, colorizer);
+    if (event.getSetting("SavedConfig.logFormat") != null) {
+      receiverConfigurationPanel.getModel().setLogFormat(event.getSetting("SavedConfig.logFormat"));
+    }
   }
 
   /**
@@ -729,6 +733,9 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     event.saveSetting(LogUI.MAIN_WINDOW_HEIGHT, getHeight());
     RuleColorizer colorizer = (RuleColorizer) allColorizers.get(ChainsawConstants.DEFAULT_COLOR_RULE_NAME);
     colorizer.saveColorSettings(ChainsawConstants.DEFAULT_COLOR_RULE_NAME);
+    if (receiverConfigurationPanel.getModel().getLogFormat() != null ) {
+      event.saveSetting("SavedConfig.logFormat", receiverConfigurationPanel.getModel().getLogFormat());
+    }
   }
 
   /**
@@ -1397,58 +1404,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
    * Displays a dialog which will provide options for selecting a configuratino
    */
   private void showReceiverConfigurationPanel() {
-    final ReceiverConfigurationPanel receiverConfigurationPanel =
-      new ReceiverConfigurationPanel();
-
-    final SettingsListener sl =
-      new SettingsListener() {
-        public void loadSettings(LoadSettingsEvent event) {
-          if (event.getSetting("SavedConfigs.Size") != null) {
-              int configSize = event.asInt("SavedConfigs.Size");
-              Object[] configs = new Object[configSize];
-
-              for (int i = 0; i < configSize; i++) {
-                configs[i] = event.getSetting("SavedConfigs." + i);
-              }
-
-              receiverConfigurationPanel.getModel().setRememberedConfigs(configs);
-          }
-
-          if (event.getSetting("SavedLayouts.Size") != null) {
-              int layoutSize = event.asInt("SavedLayouts.Size");
-              Object[] layouts = new Object[layoutSize];
-
-              for (int i = 0; i < layoutSize; i++) {
-                layouts[i] = event.getSetting("SavedLayouts." + i);
-              }
-              receiverConfigurationPanel.getModel().setRememberedLayouts(layouts);
-          }
-        }
-
-        public void saveSettings(SaveSettingsEvent event) {
-          Object[] configs = receiverConfigurationPanel.getModel().getRememberedConfigs();
-          event.saveSetting("SavedConfigs.Size", configs.length);
-
-          for (int i = 0; i < configs.length; i++) {
-            event.saveSetting("SavedConfigs." + i, configs[i].toString());
-          }
-          Object[] layouts = receiverConfigurationPanel.getModel().getRememberedLayouts();
-          event.saveSetting("SavedLayouts.Size", layouts.length);
-
-          for (int i = 0; i < layouts.length; i++) {
-            //the layout is an object, not a string (containing timestamp format, pattern & pattern type)
-            event.saveSetting("SavedLayouts." + i, layouts[i]);
-          }
-        }
-      };
-
-    /**
-         * This listener sets up the NoReciversWarningPanel and loads saves the
-         * configs/logfiles
-         */
-    getSettingsManager().addSettingsListener(sl);
-    getSettingsManager().configure(sl);
-
     SwingUtilities.invokeLater(
       new Runnable() {
         public void run() {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/1d47127d/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index bbc3ee3..8265361 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -236,7 +236,7 @@ class ReceiverConfigurationPanel extends JPanel {
         {
             public void actionPerformed(ActionEvent e)
             {
-                panelModel.setCancelled();
+                panelModel.setCancelled(true);
                 completionActionListener.actionPerformed(new ActionEvent(this, -1, "cancelled"));
             }
         });
@@ -245,6 +245,10 @@ class ReceiverConfigurationPanel extends JPanel {
         {
             public void actionPerformed(ActionEvent e)
             {
+                panelModel.setCancelled(false);
+                if (logFileFormatComboBox.getSelectedItem() != null && !(logFileFormatComboBox.getSelectedItem().toString().trim().equals(""))) {
+                  panelModel.setLogFormat(logFileFormatComboBox.getSelectedItem().toString());
+                }
                 completionActionListener.actionPerformed(new ActionEvent(this, -1, "cancelled"));
             }
         });
@@ -392,6 +396,7 @@ class ReceiverConfigurationPanel extends JPanel {
         logFileFormatComboBox = new JComboBox(logFileFormatComboBoxModel);
         logFileFormatComboBox.setEditable(true);
         logFileFormatComboBox.setOpaque(false);
+        logFileFormatComboBox.setSelectedIndex(0);
 
         c = new GridBagConstraints();
         c.gridx = 1;
@@ -632,10 +637,12 @@ class ReceiverConfigurationPanel extends JPanel {
      */
     class PanelModel {
 
-        private File file;
-        private boolean cancelled;
+    private File file;
+    //default to cancelled
+    private boolean cancelled = true;
+    private String lastLogFormat;
 
-        public PanelModel(){
+    public PanelModel(){
             file = new File(SettingsManager.getInstance().getSettingsDirectory(), "receiver-config.xml");
         }
 
@@ -667,29 +674,6 @@ class ReceiverConfigurationPanel extends JPanel {
             return !cancelled && logFileReceiverRadioButton.isSelected();
         }
 
-        public Object[] getRememberedConfigs() {
-
-            Object[] urls = new Object[existingConfigurationComboBoxModel.getSize()];
-
-            for (int i = 0; i < existingConfigurationComboBoxModel.getSize(); i++) {
-                urls[i] = existingConfigurationComboBoxModel.getElementAt(i);
-            }
-
-            return urls;
-        }
-
-        public void setRememberedConfigs(final Object[] configs) {
-            SwingUtilities.invokeLater(new Runnable() {
-                    public void run() {
-                        existingConfigurationComboBoxModel.removeAllElements();
-
-                        for (int i = 0; i < configs.length; i++) {
-                            existingConfigurationComboBoxModel.addElement(configs[i]);
-                        }
-                    }
-                });
-        }
-
         URL getConfigToLoad() {
 
             try
@@ -727,6 +711,9 @@ class ReceiverConfigurationPanel extends JPanel {
         }
 
         String getLogFormat() {
+            if (cancelled) {
+              return lastLogFormat;
+            }
             Object item = logFileFormatComboBox.getSelectedItem();
             if (item != null) {
                 return item.toString();
@@ -748,22 +735,16 @@ class ReceiverConfigurationPanel extends JPanel {
             return null;
         }
 
-        public void setRememberedLayouts(Object[] layouts)
+        public void setCancelled(boolean cancelled)
         {
-            //TODO: implement
-            //add an entry to the logformat, formattype and timestamp fields
-
+            this.cancelled = cancelled;
         }
 
-        public Object[] getRememberedLayouts()
-        {
-            //TODO: implement
-            return new Object[0];
-        }
-
-        public void setCancelled()
-        {
-            cancelled = true;
+        public void setLogFormat(String lastLogFormat) {
+          this.lastLogFormat = lastLogFormat;
+          logFileFormatComboBoxModel.removeElement(lastLogFormat);
+          logFileFormatComboBoxModel.insertElementAt(lastLogFormat, 0);
+          logFileFormatComboBox.setSelectedIndex(0);
         }
     }
 }


[26/50] [abbrv] logging-chainsaw git commit: Update the search result count in the status bar to contain the search matches which are displayed on screen (was previously showing search match count for all events, including events not displayed due to a f

Posted by rg...@apache.org.
Update the search result count in the status bar to contain the search matches which are displayed on screen (was previously showing search match count for all events, including events not displayed due to a filter rule)


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/8f17d6a7
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/8f17d6a7
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/8f17d6a7

Branch: refs/heads/master
Commit: 8f17d6a72ac6dcfa11a6da2c6697a5c8671a2035
Parents: 963870d
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Nov 13 22:20:45 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Nov 13 22:20:45 2010 +0000

----------------------------------------------------------------------
 .../chainsaw/ChainsawCyclicBufferTableModel.java  | 18 ++++++++++++++++--
 .../org/apache/log4j/chainsaw/EventContainer.java |  7 +++++++
 .../java/org/apache/log4j/chainsaw/LogPanel.java  | 16 ++++++++++++++--
 .../log4j/chainsaw/LoggingEventWrapper.java       | 13 ++++++++-----
 4 files changed, 45 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8f17d6a7/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
index ad51455..04370a7 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
@@ -440,7 +440,8 @@ class ChainsawCyclicBufferTableModel extends AbstractTableModel
         for (Iterator iter = unfilteredListCopy.iterator();iter.hasNext();) {
             LoggingEventWrapper loggingEventWrapper = (LoggingEventWrapper) iter.next();
             loggingEventWrapper.evaluateSearchRule(findRule);
-            if (loggingEventWrapper.isSearchMatch()) {
+            //return the count of visible search matches
+            if (loggingEventWrapper.isSearchMatch() && loggingEventWrapper.isDisplayed()) {
                 count++;
             }
         }
@@ -489,7 +490,20 @@ class ChainsawCyclicBufferTableModel extends AbstractTableModel
       return -1;
     }
 
-    public int getColumnCount() {
+  public int getSearchMatchCount() {
+    int searchMatchCount = 0;
+    synchronized(mutex) {
+      for (Iterator iter = filteredList.iterator();iter.hasNext();) {
+        LoggingEventWrapper wrapper = (LoggingEventWrapper) iter.next();
+        if (wrapper.isSearchMatch() && wrapper.isDisplayed()) {
+          searchMatchCount++;
+        }
+      }
+    }
+    return searchMatchCount;
+  }
+
+  public int getColumnCount() {
     return columnNames.size();
   }
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8f17d6a7/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/EventContainer.java b/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
index 854fd90..3c34436 100644
--- a/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/EventContainer.java
@@ -175,4 +175,11 @@ public interface EventContainer extends SortTableModel, LoggerNameModel {
    * @return
    */
   int findColoredRow(int currentRow, boolean forward);
+
+  /**
+   * Return the visible search match count
+   *
+   * @return
+   */
+  int getSearchMatchCount();
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8f17d6a7/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 449266f..37f9431 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -2154,7 +2154,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
           //these are actual LoggingEvent instances
           LoggingEvent event = (LoggingEvent)iter.next();
           //create two separate loggingEventWrappers (main table and search table), as they have different info on display state
-          LoggingEventWrapper loggingEventWrapper1 = new LoggingEventWrapper(event, tableModel);
+          LoggingEventWrapper loggingEventWrapper1 = new LoggingEventWrapper(event);
             //if the clearTableExpressionRule is not null, evaluate & clear the table if it matches
             if (clearTableExpressionRule != null && clearTableExpressionRule.evaluate(event, null)) {
                 logger.info("clear table expression matched - clearing table - matching event msg - " + event.getMessage());
@@ -2169,7 +2169,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
           rowAdded = rowAdded || isCurrentRowAdded;
 
           //create a new loggingEventWrapper via copy constructor to ensure same IDs
-          LoggingEventWrapper loggingEventWrapper2 = new LoggingEventWrapper(loggingEventWrapper1, searchModel);
+          LoggingEventWrapper loggingEventWrapper2 = new LoggingEventWrapper(loggingEventWrapper1);
           boolean isSearchCurrentRowAdded = searchModel.isAddRow(loggingEventWrapper2);
           if (isSearchCurrentRowAdded) {
               searchAddedRowCount++;
@@ -3453,17 +3453,29 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         tableRuleMediator.setFilterRule(null);
         searchRuleMediator.setFilterRule(null);
         textField.setToolTipText(defaultToolTip);
+        if (findRule != null) {
+          currentSearchMatchCount=tableModel.getSearchMatchCount();
+          statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
+        }
       } else {
         try {
           tableRuleMediator.setFilterRule(ExpressionRule.getRule(textField.getText()));
           searchRuleMediator.setFilterRule(ExpressionRule.getRule(textField.getText()));
           textField.setToolTipText(defaultToolTip);
+          if (findRule != null) {
+            currentSearchMatchCount=tableModel.getSearchMatchCount();
+            statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
+          }
           //valid expression, reset background color in case we were previously an invalid expression
           textField.setBackground(UIManager.getColor("TextField.background"));
         } catch (IllegalArgumentException iae) {
           //invalid expression, change background of the field
           textField.setToolTipText(iae.getMessage());
           textField.setBackground(ChainsawConstants.INVALID_EXPRESSION_BACKGROUND);
+          if (findRule != null) {
+            currentSearchMatchCount=tableModel.getSearchMatchCount();
+            statusBar.setSearchMatchCount(currentSearchMatchCount, getIdentifier());
+          }
         }
       }
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8f17d6a7/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
index 68d8680..65113a1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
@@ -48,18 +48,16 @@ public class LoggingEventWrapper {
   //a Map of event fields to Sets of string matches (can be used to render matches differently)
   Map eventMatches = new HashMap();
   private LoggingEventWrapper syncWrapper;
-  private EventContainer eventContainer;
+  private boolean displayed;
 
-  public LoggingEventWrapper(LoggingEvent loggingEvent, EventContainer eventContainer) {
+  public LoggingEventWrapper(LoggingEvent loggingEvent) {
     this.loggingEvent = loggingEvent;
-    this.eventContainer = eventContainer;
   }
 
-  public LoggingEventWrapper(LoggingEventWrapper loggingEventWrapper, EventContainer eventContainer) {
+  public LoggingEventWrapper(LoggingEventWrapper loggingEventWrapper) {
     this.loggingEvent = loggingEventWrapper.getLoggingEvent();
     this.id = loggingEventWrapper.id;
     this.syncWrapper = loggingEventWrapper;
-    this.eventContainer = eventContainer;
     loggingEventWrapper.syncWrapper = this;
   }
 
@@ -157,12 +155,17 @@ public class LoggingEventWrapper {
   public void setDisplayed(boolean b) {
     markerHeight = DEFAULT_HEIGHT;
     msgHeight = DEFAULT_HEIGHT;
+    displayed = b;
   }
 
   public void setPreviousDisplayedEventTimestamp(long previousDisplayedEventTimeStamp) {
     setProperty(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE, String.valueOf(loggingEvent.getTimeStamp() - previousDisplayedEventTimeStamp));
   }
 
+  public boolean isDisplayed() {
+    return displayed;
+  }
+
   public boolean equals(Object o) {
     if (this == o) {
       return true;


[39/50] [abbrv] logging-chainsaw git commit: Changed javaee and geronimo (jms) dependencies to provided in order to avoid them being copied into standalone tarball or DMG image

Posted by rg...@apache.org.
Changed javaee and geronimo (jms) dependencies to provided in order to avoid them being copied into standalone tarball or DMG image


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/0f4f8315
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/0f4f8315
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/0f4f8315

Branch: refs/heads/master
Commit: 0f4f83159b09ea02c992bbd8caf75443ca588194
Parents: 08c7be5
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Oct 3 06:48:07 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Oct 3 06:48:07 2011 +0000

----------------------------------------------------------------------
 pom.xml | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/0f4f8315/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 18c0f43..41b4e46 100644
--- a/pom.xml
+++ b/pom.xml
@@ -427,6 +427,7 @@
       <artifactId>javaee-api</artifactId>
       <version>5.0-2</version>
       <type>jar</type>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>com.jcraft</groupId>
@@ -444,6 +445,7 @@
         <artifactId>geronimo-jms_1.1_spec</artifactId>
         <version>1.0</version>
         <optional>true</optional>
+        <scope>provided</scope>
     </dependency>
   </dependencies>
   <reporting>


[45/50] [abbrv] logging-chainsaw git commit: Adding support for multi-line logFormats

Posted by rg...@apache.org.
Adding support for multi-line logFormats

If the fields for a record in a log file span multiple lines, while defining the logFormat, specify (LF) where newlines are present in the log file format


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/e041d484
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/e041d484
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/e041d484

Branch: refs/heads/master
Commit: e041d484972cb5b3e2bb6df99f616d7dd4d488e6
Parents: 647f691
Author: Scott Deboy <sd...@apache.org>
Authored: Fri May 3 06:30:41 2013 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri May 3 06:30:41 2013 +0000

----------------------------------------------------------------------
 .../log4j/varia/LogFilePatternReceiver.java     | 32 ++++++++++++++++++--
 1 file changed, 30 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e041d484/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index c4fb451..127f365 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -79,6 +79,9 @@ import org.apache.log4j.spi.ThrowableInformation;
  * MESSAGE<br>
  * NDC<br>
  * PROP(key)<br>
+ * (NL)<br>
+ * <p>
+ * (NL) represents a new line embedded in the log format, supporting log formats whose fields span multiple lines
  * <p>
  * Use a * to ignore portions of the log format that should be ignored
  * <p>
@@ -149,6 +152,7 @@ public class LogFilePatternReceiver extends Receiver {
   private static final String FILE = "FILE";
   private static final String LINE = "LINE";
   private static final String METHOD = "METHOD";
+  private static final String NEWLINE = "(LF)";
   
   private static final String DEFAULT_HOST = "file";
   
@@ -162,6 +166,7 @@ public class LogFilePatternReceiver extends Receiver {
   private static final String DEFAULT_GROUP = "(" + REGEXP_DEFAULT_WILDCARD + ")";
   private static final String GREEDY_GROUP = "(" + REGEXP_GREEDY_WILDCARD + ")";
   private static final String MULTIPLE_SPACES_REGEXP = "[ ]+";
+  private static final String NEWLINE_REGEXP = "\n";
   private final String newLine = System.getProperty("line.separator");
 
   private final String[] emptyException = new String[] { "" };
@@ -197,6 +202,9 @@ public class LogFilePatternReceiver extends Receiver {
   private boolean appendNonMatches;
   private final Map customLevelDefinitionMap = new HashMap();
 
+  //default to one line - this number is incremented for each (LF) found in the logFormat
+  private int lineCount = 1;
+
     public LogFilePatternReceiver() {
     keywords.add(TIMESTAMP);
     keywords.add(LOGGER);
@@ -491,9 +499,19 @@ public class LogFilePatternReceiver extends Receiver {
         Matcher eventMatcher;
         Matcher exceptionMatcher;
         String line;
+        //if newlines are provided in the logFormat - (LF) - combine the lines prior to matching
         while ((line = bufferedReader.readLine()) != null) {
-            //skip empty line entries
+            //there is already one line (read above, start i at 1
+            for (int i=1;i<lineCount;i++)
+            {
+                String thisLine = bufferedReader.readLine();
+                if (thisLine != null)
+                {
+                  line = line + newLine + thisLine;
+                }
+            }
             eventMatcher = regexpPattern.matcher(line);
+            //skip empty line entries
             if (line.trim().equals("")) {continue;}
             exceptionMatcher = exceptionPattern.matcher(line);
             if (eventMatcher.matches()) {
@@ -655,11 +673,22 @@ public class LogFilePatternReceiver extends Receiver {
 
     String newPattern = logFormat;
 
+    //process line feeds - (LF) - in the logFormat - before processing properties
     int index = 0;
+    while (index > -1) {
+      index = newPattern.indexOf(NEWLINE);
+      if (index > -1) {
+        //keep track of number of expected newlines in the format, so the lines can be concatenated prior to matching
+        lineCount++;
+        newPattern = singleReplace(newPattern, NEWLINE, NEWLINE_REGEXP);
+      }
+    }
+      
     String current = newPattern;
     //build a list of property names and temporarily replace the property with an empty string,
     //we'll rebuild the pattern later
     List propertyNames = new ArrayList();
+    index = 0;
     while (index > -1) {
         if (current.indexOf(PROP_START) > -1 && current.indexOf(PROP_END) > -1) {
             index = current.indexOf(PROP_START);
@@ -967,7 +996,6 @@ public class LogFilePatternReceiver extends Receiver {
 //    test.setAppendNonMatches(true);
 //    test.setTimestampFormat("yyyy-MM-d HH:mm:ss,SSS");
 //    test.setFileURL("file:///C:/log/test.log");
-//    test.initialize();
 //    test.activateOptions();
 //  }
 


[28/50] [abbrv] logging-chainsaw git commit: PMD cleanup and removing unused favourites package & classes

Posted by rg...@apache.org.
PMD cleanup and removing unused favourites package & classes


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/8fcf3755
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/8fcf3755
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/8fcf3755

Branch: refs/heads/master
Commit: 8fcf3755bbb749874bd5b2ad34fea726c27e265a
Parents: cbfde96
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Nov 15 07:17:14 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Nov 15 07:17:14 2010 +0000

----------------------------------------------------------------------
 .../ChainsawCyclicBufferTableModel.java         |  1 -
 .../log4j/chainsaw/ChainsawToolBarAndMenus.java |  2 +-
 .../log4j/chainsaw/ExpressionRuleContext.java   |  1 -
 .../chainsaw/LogFilePatternLayoutBuilder.java   |  2 +-
 .../org/apache/log4j/chainsaw/LogPanel.java     |  6 +-
 .../log4j/chainsaw/LogPanelLoggerTreeModel.java |  5 -
 .../log4j/chainsaw/LogPanelPreferenceModel.java |  3 -
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 31 -------
 .../log4j/chainsaw/LoggerNameTreePanel.java     |  7 --
 .../log4j/chainsaw/LoggingEventWrapper.java     |  7 +-
 .../log4j/chainsaw/TableColorizingRenderer.java | 15 +--
 .../org/apache/log4j/chainsaw/WelcomePanel.java |  3 -
 .../apache/log4j/chainsaw/color/ColorPanel.java |  6 +-
 .../log4j/chainsaw/dnd/FileDnDTarget.java       |  2 -
 .../log4j/chainsaw/favourites/Favourite.java    | 61 ------------
 .../chainsaw/favourites/FavouritesRegistry.java | 97 --------------------
 .../apache/log4j/chainsaw/help/HelpManager.java | 10 +-
 .../log4j/chainsaw/icons/LineIconFactory.java   |  8 +-
 .../chainsaw/layout/EventDetailLayout.java      |  1 -
 .../log4j/chainsaw/prefs/MRUFileList.java       |  1 -
 .../log4j/chainsaw/prefs/SettingsManager.java   |  2 +-
 .../receivers/PluginPropertyEditorPanel.java    |  1 -
 .../chainsaw/zeroconf/ZeroConfDeviceModel.java  |  3 -
 .../log4j/chainsaw/zeroconf/ZeroConfPlugin.java | 20 ----
 .../zeroconf/ZeroConfPreferenceModel.java       |  2 -
 25 files changed, 20 insertions(+), 277 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
index 04370a7..719094f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
@@ -17,7 +17,6 @@
 
 package org.apache.log4j.chainsaw;
 
-import java.awt.EventQueue;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
index ffe9543..5e3a6cf 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
@@ -251,7 +251,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
         new AbstractAction("Scroll to top") {
           public void actionPerformed(ActionEvent e) {
             if (logui.getCurrentLogPanel() != null) {
-              logui.getCurrentLogPanel().scrollToTop();;
+              logui.getCurrentLogPanel().scrollToTop();
             }
           }
         };

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/ExpressionRuleContext.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ExpressionRuleContext.java b/src/main/java/org/apache/log4j/chainsaw/ExpressionRuleContext.java
index 28ccd15..9f1723c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ExpressionRuleContext.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ExpressionRuleContext.java
@@ -28,7 +28,6 @@ import javax.swing.DefaultListModel;
 import javax.swing.JList;
 import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
-import javax.swing.JTextField;
 import javax.swing.ListModel;
 import javax.swing.text.JTextComponent;
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
index 1b6c518..7c8bc26 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
@@ -133,7 +133,7 @@ public class LogFilePatternLayoutBuilder
             } else if (converter instanceof FileLocationPatternConverter) {
                 buffer.append("FILE");
             } else if (converter instanceof PropertiesPatternConverter) {
-                PropertiesPatternConverter propertiesConverter = (PropertiesPatternConverter) converter;
+//                PropertiesPatternConverter propertiesConverter = (PropertiesPatternConverter) converter;
 //                String option = propertiesConverter.getOption();
 //                if (option != null && option.length() > 0) {
 //                    buffer.append("PROP(" + option + ")");

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 37f9431..4173b21 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -3851,7 +3851,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     private class EventTimeDeltaMatchThumbnail extends AbstractEventMatchThumbnail {
         public EventTimeDeltaMatchThumbnail() {
-            super("timedelta");
+            super();
             initializeLists();
         }
 
@@ -3931,7 +3931,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   //a listener receiving color updates needs to call configureColors on this class
     private class ColorizedEventAndSearchMatchThumbnail extends AbstractEventMatchThumbnail {
         public ColorizedEventAndSearchMatchThumbnail() {
-            super("colors");
+            super();
             configureColors();
         }
 
@@ -4042,7 +4042,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         protected List secondaryList = new ArrayList();
         protected final int maxEventHeight = 6;
 
-        AbstractEventMatchThumbnail(final String name) {
+        AbstractEventMatchThumbnail() {
             super();
             addMouseMotionListener(new MouseMotionAdapter() {
               public void mouseMoved(MouseEvent e) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LogPanelLoggerTreeModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelLoggerTreeModel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelLoggerTreeModel.java
index 6a70a45..2f486b3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelLoggerTreeModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelLoggerTreeModel.java
@@ -33,7 +33,6 @@ import javax.swing.tree.MutableTreeNode;
 
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
-import org.apache.log4j.chainsaw.helper.SwingHelper;
 
 
 /**
@@ -186,10 +185,6 @@ outerFor:
         public int compare(Object o1, Object o2) {
           return o1.toString().compareToIgnoreCase(o2.toString());
         }
-
-        public boolean equals(Object obj) {
-          return false;
-        }
       };
 
     private LogPanelTreeNode(String logName) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
index 85ed417..8634055 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferenceModel.java
@@ -33,8 +33,6 @@ import java.util.Properties;
 
 import javax.swing.table.TableColumn;
 
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
 import org.apache.log4j.chainsaw.prefs.SettingsManager;
 import org.apache.log4j.helpers.Constants;
 
@@ -46,7 +44,6 @@ import org.apache.log4j.helpers.Constants;
 public class LogPanelPreferenceModel implements Serializable{
   public static final String ISO8601 = "ISO8601";
   public static final Collection DATE_FORMATS;
-  private static final Logger logger = LogManager.getLogger(LogPanelPreferenceModel.class);
 
  private static final long serialVersionUID = 7526472295622776147L;
   static {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 6785335..e1a71f5 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -84,7 +84,6 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.EventListenerList;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
-import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.AppenderSkeleton;
@@ -127,7 +126,6 @@ import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.RepositorySelector;
 import org.apache.log4j.xml.DOMConfigurator;
 import org.apache.log4j.xml.XMLDecoder;
-import org.xml.sax.SAXException;
 
 
 /**
@@ -1815,8 +1813,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
 
     if (selectedTab instanceof LogPanel) {
       return (LogPanel) selectedTab;
-    } else {
-      //      System.out.println(selectedTab);
     }
 
     return null;
@@ -1856,33 +1852,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
   }
 
   /**
-   * Changes the currently used Look And Feel of the App
-   *
-   * @param lookAndFeelClassName
-   *                    The FQN of the LookANdFeel
-   */
-  private static void applyLookAndFeel(String lookAndFeelClassName) {
-    UIManager.put("swing.boldMetal", Boolean.FALSE);
-    if (
-      UIManager.getLookAndFeel().getClass().getName().equals(
-          lookAndFeelClassName)) {
-      return;
-    }
-
-    if (
-      (lookAndFeelClassName == null) || lookAndFeelClassName.trim().equals("")) {
-      lookAndFeelClassName = UIManager.getSystemLookAndFeelClassName();
-    }
-
-    try {
-      UIManager.setLookAndFeel(lookAndFeelClassName);
-
-    } catch (Exception e) {
-      e.printStackTrace();
-    }
-  }
-
-  /**
    * Causes the Welcome Panel to become visible, and shows the URL specified as
    * it's contents
    *

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
index ff01eed..b451709 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
@@ -159,7 +159,6 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
   private final LogPanel logPanel;
   private final RuleColorizer colorizer;
   private Rule ignoreExpressionRule;
-  private FilterModel filterModel;
   private boolean expandRootLatch = false;
   private String currentlySelectedLoggerName;
 
@@ -177,7 +176,6 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     this.preferenceModel = preferenceModel;
     this.logPanel = logPanel;
     this.colorizer = colorizer;
-    this.filterModel = filterModel;
 
     setLayout(new BorderLayout());
     ignoreExpressionEntryField.setPreferredSize(new Dimension(300, 150));
@@ -1831,11 +1829,6 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
         {
             super.firePropertyChange(propertyName, oldVal, newVal);
         }
-
-        public void firePropertyChange(PropertyChangeEvent evt)
-        {
-            super.firePropertyChange(evt);
-        }
     }
 
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
index 65113a1..30429a3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggingEventWrapper.java
@@ -18,7 +18,6 @@ package org.apache.log4j.chainsaw;
 
 import java.awt.Color;
 import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
 
@@ -67,10 +66,8 @@ public class LoggingEventWrapper {
 
   public void setProperty(String propName, String propValue) {
     loggingEvent.setProperty(propName, propValue);
-    if (id == 0) {
-      if (propName.equals(Constants.LOG4J_ID_KEY)) {
-        id = Integer.parseInt(propValue);
-      }
+    if (id == 0 && propName.equals(Constants.LOG4J_ID_KEY)) {
+      id = Integer.parseInt(propValue);
     }
     if (syncWrapper != null && !propName.equals(ChainsawConstants.MILLIS_DELTA_COL_NAME_LOWERCASE)) {
       syncWrapper.getLoggingEvent().setProperty(propName, propValue);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index b6029ff..bd3a921 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -22,11 +22,6 @@ import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
 import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.font.LineBreakMeasurer;
-import java.awt.font.TextLayout;
-import java.text.AttributedCharacterIterator;
-import java.text.AttributedString;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -443,11 +438,9 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     /**
      * Colourize background based on row striping if the event still has default foreground and background color
      */
-    if (background.equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) && foreground.equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND)) {
-      if ((row % 2) != 0) {
-        background = applicationPreferenceModel.getAlternatingColorBackgroundColor();
-        foreground = applicationPreferenceModel.getAlternatingColorForegroundColor();
-      }
+    if (background.equals(ChainsawConstants.COLOR_DEFAULT_BACKGROUND) && foreground.equals(ChainsawConstants.COLOR_DEFAULT_FOREGROUND) && (row % 2) != 0) {
+      background = applicationPreferenceModel.getAlternatingColorBackgroundColor();
+      foreground = applicationPreferenceModel.getAlternatingColorForegroundColor();
     }
 
     component.setBackground(background);
@@ -630,6 +623,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     useRelativeTimesToPrevious = false;
   }
 
+  /*
    private int calculateHeight(String string, int width, Map paramMap) {
      if (string.trim().length() == 0) {
          return ChainsawConstants.DEFAULT_ROW_HEIGHT;
@@ -646,6 +640,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
      }
      return Math.max(ChainsawConstants.DEFAULT_ROW_HEIGHT, (int) height);
     }
+    */
 
     private void setHighlightAttributesInternal(Object matchSet, StyledDocument styledDocument) {
         if (!highlightSearchMatchText) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java b/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
index 1cb19fa..a8209e2 100644
--- a/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/WelcomePanel.java
@@ -20,7 +20,6 @@ package org.apache.log4j.chainsaw;
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Dimension;
-import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.io.IOException;
 import java.net.URL;
@@ -36,7 +35,6 @@ import javax.swing.JPanel;
 import javax.swing.JScrollPane;
 import javax.swing.JToolBar;
 import javax.swing.SwingUtilities;
-import javax.swing.UIManager;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
 
@@ -64,7 +62,6 @@ public class WelcomePanel extends JPanel {
 
     if (helpURL != null) {
       textInfo.setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 5));
-      Font font = UIManager.getFont("Label.font");
 
       JScrollPane pane = new JScrollPane(textInfo);
       pane.setBorder(null);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
index 95a8b11..fcf7463 100644
--- a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
@@ -309,10 +309,8 @@ public class ColorPanel extends JPanel
       }
       for (Iterator iter = allLogPanelColorizers.entrySet().iterator();iter.hasNext();) {
           Map.Entry entry = (Map.Entry)iter.next();
-          if (!entry.getValue().equals(currentLogPanelColorizer)) {
-              if (logPanelColorizersModel.getIndexOf(entry.getKey()) == -1) {
-                logPanelColorizersModel.addElement(entry.getKey());
-              }
+          if (!entry.getValue().equals(currentLogPanelColorizer) && (logPanelColorizersModel.getIndexOf(entry.getKey()) == -1)) {
+              logPanelColorizersModel.addElement(entry.getKey());
           }
       }
       //update search and alternating colors, since they may have changed from another color panel

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/dnd/FileDnDTarget.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/dnd/FileDnDTarget.java b/src/main/java/org/apache/log4j/chainsaw/dnd/FileDnDTarget.java
index f72e2f3..647a92c 100644
--- a/src/main/java/org/apache/log4j/chainsaw/dnd/FileDnDTarget.java
+++ b/src/main/java/org/apache/log4j/chainsaw/dnd/FileDnDTarget.java
@@ -55,7 +55,6 @@ public class FileDnDTarget implements DropTargetListener{
 
     protected int acceptableActions = DnDConstants.ACTION_COPY;
 
-    private DropTarget dropTarget;
     private List fileList;
 
     private JComponent guiTarget;
@@ -68,7 +67,6 @@ public class FileDnDTarget implements DropTargetListener{
      */
     public FileDnDTarget(JComponent c) {
         this.guiTarget = c;
-        dropTarget = new DropTarget(this.guiTarget, this);
     }
     
     public void addDropTargetToComponent(JComponent c){

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/favourites/Favourite.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/favourites/Favourite.java b/src/main/java/org/apache/log4j/chainsaw/favourites/Favourite.java
deleted file mode 100644
index c681ce5..0000000
--- a/src/main/java/org/apache/log4j/chainsaw/favourites/Favourite.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.log4j.chainsaw.favourites;
-
-/**
- * A Fauvourite is just a named container of on object that can be used
- * as a basis (prototype) for the creation of exact copies.
- * 
- * Clients should use the FavouritesRegistry to create instances of this class
- * so that explicit checks can be performed about the suitability of the
- * prototype.
- * 
- * @author Paul Smith <ps...@apache.org>
- *
- */
-public final class Favourite {
-
-    private String name;
-    private Object prototype;
-
-    /**
-     * @param name
-     * @param object
-     */
-    Favourite(String name, Object prtotype) {
-        this.name = name;
-        this.prototype = prtotype;
-    }
-
-
-    /**
-     * @return Returns the name.
-     */
-    public final String getName() {
-
-        return name;
-    }
-
-    /**
-     * Returns the object that would be used as a basis to create new
-     * instances of that same object.
-     * @return Returns the prototype.
-     */
-    public final Object getPrototype() {
-      return prototype;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/favourites/FavouritesRegistry.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/favourites/FavouritesRegistry.java b/src/main/java/org/apache/log4j/chainsaw/favourites/FavouritesRegistry.java
deleted file mode 100644
index a85842e..0000000
--- a/src/main/java/org/apache/log4j/chainsaw/favourites/FavouritesRegistry.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.log4j.chainsaw.favourites;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
-/**
- *  A singleton class that is used as a Registry of instances of JavaBeans 
- * that are in a state that a user prefers.
- * 
- * @author Paul Smith <ps...@apache.org>
- *
- */
-public class FavouritesRegistry{
-  
-  private final List favourites = new ArrayList();
-  
-  /**
-   * Returns a Collection of Favourite instances whose getPrototype() method
-   * returns an object whose class is assignable from clazz, or more formally, such that
-   * clazz.isAssignableFrom(favourite.getPrototype().getClass())
-   * @param clazz
-   * @return favourites
-   */
-  public synchronized Collection getFavouritesByClass(Class clazz) {
-    throw new UnsupportedOperationException("Work In Progress");
-  }
-  
-  /**
-   * Adds a favourite to this Registry
-   * @param favourite
-   */
-  
-  public synchronized void addFavourite(Favourite favourite) {
-    throw new UnsupportedOperationException("Work In Progress");
-  }
-  
-  /**
-   * Returns an unmodifiable List of all the known Favourite instances
-   * @return favourites
-   */
-  public List getFavourites() {
-    return Collections.unmodifiableList(favourites);
-  }
-  
-  /**
-   * Creates a new Favourite instance after running throught some
-   * suitability checks to make sure the object class is ok to be used
-   * as a prototype.
-   * 
-   * @param name The name to use for the favourite
-   * @param prototype The object to register
-   * @throws IllegalArgumentException if the prototype does not conform
-   * to the necessary rules to be used as a prototype (see the package documentation).
-   * 
-   */
-  public void addFavourite(String name, Object prototype) {
-    favourites.add(createFavourite(name, prototype));
-  }
-  
-  private Favourite createFavourite(String name, Object prototype) {
-    checkSuitability(prototype);
-    return new Favourite(name, prototype);
-  }
-  
-  /**
-   * Checks the suitability of an object to make sure it conforms to all the rules
-   * for being a prototype,
-   * @param prototype
-   * @throws IllegalArgumentException if the prototype is not suitable
-   */
-  private void checkSuitability(Object prototype)  throws IllegalArgumentException{
-    // TODO Auto-generated method stub
-   throw new UnsupportedOperationException("Work in Progress"); 
-  }
-
-  private FavouritesRegistry() {
-    
-  }
-}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/help/HelpManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/help/HelpManager.java b/src/main/java/org/apache/log4j/chainsaw/help/HelpManager.java
index 6667184..eb928d8 100644
--- a/src/main/java/org/apache/log4j/chainsaw/help/HelpManager.java
+++ b/src/main/java/org/apache/log4j/chainsaw/help/HelpManager.java
@@ -74,14 +74,6 @@ public final class HelpManager {
     }
 
     /**
-     * @return URL
-     */
-    public final URL getHelpURL() {
-
-        return helpURL;
-    }
-
-    /**
      * The current Help URL that should be displayed, and is
      * a PropertyChangeListener supported property.
      *
@@ -90,7 +82,7 @@ public final class HelpManager {
      * of the event will be null)
      * @param helpURL
      */
-    public final void setHelpURL(URL helpURL) {
+    public void setHelpURL(URL helpURL) {
         this.helpURL = helpURL;
         firePropertyChange("helpURL", null, this.helpURL);
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/icons/LineIconFactory.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/icons/LineIconFactory.java b/src/main/java/org/apache/log4j/chainsaw/icons/LineIconFactory.java
index 7fe4f3e..fdf0b65 100644
--- a/src/main/java/org/apache/log4j/chainsaw/icons/LineIconFactory.java
+++ b/src/main/java/org/apache/log4j/chainsaw/icons/LineIconFactory.java
@@ -48,7 +48,7 @@ public final class LineIconFactory {
   private LineIconFactory() {
   }
 
-  public static final Icon createExpandIcon() {
+  public static Icon createExpandIcon() {
       int size = 8;
       int xOffSet = 0;
       int yOffSet = 0;
@@ -80,7 +80,7 @@ public final class LineIconFactory {
 
     return null;
   }
-  public static final Icon createCollapseIcon() {
+  public static Icon createCollapseIcon() {
       int size = 8;
       int xOffSet = 0;
       int yOffSet = 0;
@@ -109,11 +109,11 @@ public final class LineIconFactory {
     return null;
   }
 
-  public static final Icon createCloseIcon() {
+  public static Icon createCloseIcon() {
     return new CloseIcon(8, 0, 0);
   }
 
-  public static final Icon createBlankIcon() {
+  public static Icon createBlankIcon() {
     return new BlankIcon(16);
   }
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/layout/EventDetailLayout.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/layout/EventDetailLayout.java b/src/main/java/org/apache/log4j/chainsaw/layout/EventDetailLayout.java
index b907c1a..aff4120 100644
--- a/src/main/java/org/apache/log4j/chainsaw/layout/EventDetailLayout.java
+++ b/src/main/java/org/apache/log4j/chainsaw/layout/EventDetailLayout.java
@@ -177,7 +177,6 @@ public class EventDetailLayout extends Layout {
    * @return new LoggingEvent
    */
   private static LoggingEvent copyForHTML(LoggingEvent event) {
-    String fqnCategory = escape(event.getFQNOfLoggerClass());
     Logger logger = Logger.getLogger(event.getLoggerName());
     String threadName = event.getThreadName();
     Object msg = escape(event.getMessage().toString());

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/prefs/MRUFileList.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/prefs/MRUFileList.java b/src/main/java/org/apache/log4j/chainsaw/prefs/MRUFileList.java
index 2e3bea3..a389e88 100644
--- a/src/main/java/org/apache/log4j/chainsaw/prefs/MRUFileList.java
+++ b/src/main/java/org/apache/log4j/chainsaw/prefs/MRUFileList.java
@@ -33,7 +33,6 @@ import com.thoughtworks.xstream.io.xml.DomDriver;
 public class MRUFileList{
 
     private static MRUFileList log4jList = new MRUFileList();
-    private static MRUFileList jdk14List = new MRUFileList();
     private static final int DEFAULT_MRU_SIZE = 5;
     
     private List fileList = new ArrayList();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/prefs/SettingsManager.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/prefs/SettingsManager.java b/src/main/java/org/apache/log4j/chainsaw/prefs/SettingsManager.java
index 6c3560e..25f2069 100644
--- a/src/main/java/org/apache/log4j/chainsaw/prefs/SettingsManager.java
+++ b/src/main/java/org/apache/log4j/chainsaw/prefs/SettingsManager.java
@@ -79,7 +79,7 @@ public final class SettingsManager {
      * Returns the singleton instance of the SettingsManager
      * @return settings manager
      */
-    public static final SettingsManager getInstance() {
+    public static SettingsManager getInstance() {
         return instance;
     }
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
index 67a8a6e..c543216 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
@@ -18,7 +18,6 @@ package org.apache.log4j.chainsaw.receivers;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.Dimension;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
 import java.beans.BeanInfo;

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java
index 430a5f4..ee35394 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfDeviceModel.java
@@ -23,11 +23,8 @@ import java.util.List;
 import javax.jmdns.ServiceEvent;
 import javax.jmdns.ServiceInfo;
 import javax.jmdns.ServiceListener;
-import javax.swing.ImageIcon;
 import javax.swing.table.AbstractTableModel;
 
-import org.apache.log4j.chainsaw.icons.ChainsawIcons;
-
 public class ZeroConfDeviceModel extends AbstractTableModel implements ServiceListener {
 
     private List deviceList = new ArrayList();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
index e872940..369e9d8 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
@@ -18,7 +18,6 @@ package org.apache.log4j.chainsaw.zeroconf;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
-import java.awt.Container;
 import java.awt.event.ActionEvent;
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
@@ -36,7 +35,6 @@ import javax.jmdns.ServiceEvent;
 import javax.jmdns.ServiceInfo;
 import javax.jmdns.ServiceListener;
 import javax.swing.AbstractAction;
-import javax.swing.Icon;
 import javax.swing.ImageIcon;
 import javax.swing.JFrame;
 import javax.swing.JMenu;
@@ -44,7 +42,6 @@ import javax.swing.JMenuBar;
 import javax.swing.JMenuItem;
 import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
-import javax.swing.JTabbedPane;
 import javax.swing.JTable;
 import javax.swing.JToolBar;
 import javax.swing.SwingUtilities;
@@ -93,8 +90,6 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
 
     private static final Logger LOG = Logger.getLogger(ZeroConfPlugin.class);
 
-    private static final Icon DEVICE_DISCOVERED_ICON = new ImageIcon(ChainsawIcons.ANIM_RADIO_TOWER);
-
     private ZeroConfDeviceModel discoveredDevices = new ZeroConfDeviceModel();
 
     private JTable deviceTable = new JTable(discoveredDevices);
@@ -226,21 +221,6 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
     }
 
     /**
-     * Sets the icon of this parent container (a JTabbedPane, we hope
-     *
-     */
-    private void setIconIfNeeded() {
-        Container container = this.getParent();
-        if(container instanceof JTabbedPane) {
-            JTabbedPane tabbedPane = (JTabbedPane) container;
-            Icon icon = discoveredDevices.getRowCount()==0?null:DEVICE_DISCOVERED_ICON;
-            tabbedPane.setIconAt(tabbedPane.indexOfTab(getName()), icon);
-        }else {
-            LOG.warn("Parent is not a TabbedPane, not setting icon: " + container.getClass().getName());
-        }
-    }
-
-    /**
      * Attempts to find a JFrame container as a parent,and addse a "Connect to" menu
      *
      */

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/8fcf3755/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPreferenceModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPreferenceModel.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPreferenceModel.java
index 687664f..1ac13c4 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPreferenceModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPreferenceModel.java
@@ -16,7 +16,6 @@
  */
 package org.apache.log4j.chainsaw.zeroconf;
 
-import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
@@ -27,7 +26,6 @@ public class ZeroConfPreferenceModel {
     private List monitoredZones = new ArrayList();
     private Set autoConnectDevices = new HashSet();
     
-    private transient PropertyChangeSupport propertySupport = new PropertyChangeSupport(this);
 //   TODO expose addPropertyChangeListener
     
     public void addAutoConnectDevice(String deviceName) {


[48/50] [abbrv] logging-chainsaw git commit: Add support for a group property in LogFilePatternReceiver in order to allow logs from multiple cluster nodes to be combined in a single table by using GROUP as the event routing, and add support for the 'chai

Posted by rg...@apache.org.
Add support for a group property in LogFilePatternReceiver in order to allow logs from multiple cluster nodes to be combined in a single table by using GROUP as the event routing, and add support for the 'chainsaw' group for chainsaw-generated logs.  Also updated the valid characters in the filereceiver timestampformat for java 7.


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/e2021f8f
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/e2021f8f
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/e2021f8f

Branch: refs/heads/master
Commit: e2021f8fee8126263a999c15d0dc614263e01692
Parents: d838d7f
Author: Scott Deboy <sd...@apache.org>
Authored: Sun May 11 18:53:38 2014 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sun May 11 18:53:38 2014 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogUI.java   |  4 ++--
 .../vfs/VFSLogFilePatternReceiverBeanInfo.java  |  1 +
 .../org/apache/log4j/helpers/Constants.java     |  4 ++++
 .../log4j/varia/LogFilePatternReceiver.java     | 20 +++++++++++++++++++-
 .../varia/LogFilePatternReceiverBeanInfo.java   |  1 +
 5 files changed, 27 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e2021f8f/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index e99760e..d9adec1 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -367,10 +367,10 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     logUI.ensureChainsawAppenderHandlerAdded();
     logger = LogManager.getLogger(LogUI.class);
 
-    //set hostname & application properties which will cause Chainsaw and other apache-generated
+    //set hostname, application and group properties which will cause Chainsaw and other apache-generated
     //logging events to route (by default) to a tab named 'chainsaw-log'
     PropertyRewritePolicy policy = new PropertyRewritePolicy();
-    policy.setProperties("hostname=chainsaw,application=log");
+    policy.setProperties("hostname=chainsaw,application=log,group=chainsaw");
     
     RewriteAppender rewriteAppender = new RewriteAppender();
     rewriteAppender.setRewritePolicy(policy);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e2021f8f/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiverBeanInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiverBeanInfo.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiverBeanInfo.java
index 949965a..a99d248 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiverBeanInfo.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiverBeanInfo.java
@@ -46,6 +46,7 @@ public class VFSLogFilePatternReceiverBeanInfo extends SimpleBeanInfo {
           "filterExpression", VFSLogFilePatternReceiver.class),
           new PropertyDescriptor(
                   "promptForUserInfo", VFSLogFilePatternReceiver.class),
+        new PropertyDescriptor("group", VFSLogFilePatternReceiver.class),
       };
     } catch (Exception e) {
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e2021f8f/src/main/java/org/apache/log4j/helpers/Constants.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/helpers/Constants.java b/src/main/java/org/apache/log4j/helpers/Constants.java
index dbbbe59..2e181fa 100644
--- a/src/main/java/org/apache/log4j/helpers/Constants.java
+++ b/src/main/java/org/apache/log4j/helpers/Constants.java
@@ -47,6 +47,10 @@ public interface Constants {
      */
   String RECEIVER_NAME_KEY = "receiver";
     /**
+     * group string literal.
+     */
+  String GROUP_KEY = "group";
+    /**
      * log4jid string literal.
      */
   String LOG4J_ID_KEY = "log4jid";

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e2021f8f/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index f8f12eb..df91332 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -65,6 +65,7 @@ import org.apache.log4j.spi.ThrowableInformation;
  * - supports the parsing of multi-line messages and exceptions
  * - 'hostname' property set to URL host (or 'file' if not available)
  * - 'application' property set to URL path (or value of fileURL if not available) 
+ * - 'group' property can be set to associate multiple log file receivers
  *<p>
  * <b>Keywords:</b><br>
  * TIMESTAMP<br>
@@ -181,8 +182,9 @@ public class LogFilePatternReceiver extends Receiver {
   private boolean tailing;
   private String filterExpression;
   private long waitMillis = 2000; //default 2 seconds
+  private String group;
 
-  private static final String VALID_DATEFORMAT_CHARS = "GyMwWDdFEaHkKhmsSzZ";
+  private static final String VALID_DATEFORMAT_CHARS = "GyYMwWDdFEuaHkKhmsSzZX";
   private static final String VALID_DATEFORMAT_CHAR_PATTERN = "[" + VALID_DATEFORMAT_CHARS + "]";
 
   private Rule expressionRule;
@@ -347,6 +349,19 @@ public class LogFilePatternReceiver extends Receiver {
   }
 
     /**
+   * Mutator
+   */
+  public void setGroup(String group) { this.group = group; }
+
+
+    /**
+   * Accessor
+   *
+   * @return timestamp format
+   */
+  public String getGroup() { return group; }
+    
+    /**
    * Mutator.  Specify a pattern from {@link java.text.SimpleDateFormat}
    *
    * @param timestampFormat
@@ -960,6 +975,9 @@ public class LogFilePatternReceiver extends Receiver {
     properties.put(Constants.HOSTNAME_KEY, host);
     properties.put(Constants.APPLICATION_KEY, path);
     properties.put(Constants.RECEIVER_NAME_KEY, getName());
+    if (group != null) {
+        properties.put(Constants.GROUP_KEY, group);
+    }
 
     //all remaining entries in fieldmap are properties
     properties.putAll(fieldMap);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/e2021f8f/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
index f99f289..d7f0a8e 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiverBeanInfo.java
@@ -44,6 +44,7 @@ public class LogFilePatternReceiverBeanInfo extends SimpleBeanInfo {
         new PropertyDescriptor("appendNonMatches", LogFilePatternReceiver.class),
         new PropertyDescriptor("customLevelDefinitions", LogFilePatternReceiver.class),
         new PropertyDescriptor("useCurrentThread", LogFilePatternReceiver.class),
+        new PropertyDescriptor("group", LogFilePatternReceiver.class),
       };
     } catch (Exception e) {
     }


[20/50] [abbrv] logging-chainsaw git commit: Log file receiver configurations can now be loaded from both log4j.xml and log4j.properties configuration fileappender entries

Posted by rg...@apache.org.
Log file receiver configurations can now be loaded from both log4j.xml and log4j.properties configuration fileappender entries

Also reordered the receiver config panel entries and made loading events from a log4j config file the default option, reworded radio button text


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/cf258edd
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/cf258edd
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/cf258edd

Branch: refs/heads/master
Commit: cf258eddaaf3813e91e39cbce1fbcf442ef7d354
Parents: 910dc45
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Nov 6 18:47:24 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Nov 6 18:47:24 2010 +0000

----------------------------------------------------------------------
 .../chainsaw/LogFilePatternLayoutBuilder.java   | 149 ++++++++++++++-----
 .../java/org/apache/log4j/chainsaw/LogUI.java   |   4 -
 .../chainsaw/ReceiverConfigurationPanel.java    |  18 +--
 .../log4j/chainsaw/help/release-notes.html      |   4 +
 4 files changed, 126 insertions(+), 49 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cf258edd/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
index 1249863..1b6c518 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
@@ -17,19 +17,21 @@
 package org.apache.log4j.chainsaw;
 
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
 
-import org.apache.log4j.FileAppender;
 import org.apache.log4j.helpers.OptionConverter;
 import org.apache.log4j.pattern.ClassNamePatternConverter;
 import org.apache.log4j.pattern.DatePatternConverter;
@@ -145,7 +147,85 @@ public class LogFilePatternLayoutBuilder
         return buffer.toString();
     }
 
-  public static Map getAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
+  public static Map getAppenderConfiguration(File file) {
+    try {
+      return getXMLFileAppenderConfiguration(file);
+    } catch (IOException e) {
+      //ignore
+    } catch (ParserConfigurationException e) {
+      //ignore
+    } catch (SAXException e) {
+      //ignore
+    }
+    try {
+      return getPropertiesFileAppenderConfiguration(file);
+    } catch (Exception e) {
+      //ignore
+    }
+    //don't return null
+    return new HashMap();
+  }
+
+  public static Map getPropertiesFileAppenderConfiguration(File propertyFile) throws IOException, ParserConfigurationException, SAXException {
+    Map result = new HashMap();
+    String appenderPrefix = "log4j.appender";
+    Properties props = new Properties();
+    FileInputStream inputStream = null;
+    try {
+      inputStream = new FileInputStream(propertyFile);
+      props.load(inputStream);
+      Enumeration propertyNames = props.propertyNames();
+      Map appenders = new HashMap();
+      while (propertyNames.hasMoreElements()) {
+        String propertyName = propertyNames.nextElement().toString();
+        if (propertyName.startsWith(appenderPrefix)) {
+          String value = propertyName.substring(appenderPrefix.length() + 1);
+          if (value.indexOf(".") == -1) {
+            //no sub-values - this entry is the appender name & class
+            appenders.put(value, props.getProperty(propertyName).trim());
+          }
+        }
+      }
+      for (Iterator iter = appenders.entrySet().iterator();iter.hasNext();) {
+        Map.Entry appenderEntry = (Map.Entry)iter.next();
+        String appenderName = appenderEntry.getKey().toString();
+        String appenderClassName = appenderEntry.getValue().toString();
+        if (appenderClassName.toLowerCase().endsWith("fileappender")) {
+          String layout = props.getProperty(appenderPrefix + "." + appenderName + ".layout");
+          if (layout != null && layout.trim().equals("org.apache.log4j.PatternLayout")) {
+            String conversion = props.getProperty(appenderPrefix + "." + appenderName + ".layout.ConversionPattern");
+            String file = props.getProperty(appenderPrefix + "." + appenderName + ".File");
+            if (conversion != null && file != null) {
+              Map entry = new HashMap();
+              entry.put("file", file.trim());
+              entry.put("conversion", conversion.trim());
+              result.put(appenderName, entry);
+            }
+          }
+        }
+      }
+          /*
+          example:
+          log4j.appender.R=org.apache.log4j.RollingFileAppender
+          log4j.appender.R.File=${catalina.base}/logs/tomcat.log
+          log4j.appender.R.MaxFileSize=10MB
+          log4j.appender.R.MaxBackupIndex=10
+          log4j.appender.R.layout=org.apache.log4j.PatternLayout
+          log4j.appender.R.layout.ConversionPattern=%d - %p %t %c - %m%n
+           */
+    }
+    catch (IOException ioe) {
+    }
+    finally {
+      if (inputStream != null) {
+        inputStream.close();
+      }
+    }
+    //don't return null
+    return result;
+  }
+
+  private static Map getXMLFileAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
     InputStream stream = file.toURI().toURL().openStream();
     Map result = new HashMap();
     try {
@@ -163,50 +243,47 @@ public class LogFilePatternLayoutBuilder
         NamedNodeMap appenderAttributes = appender.getAttributes();
 //        Class appenderClass = Class.forName(map.getNamedItem("class").getNodeValue());
         Node appenderClass = appenderAttributes.getNamedItem("class");
-        try {
-          if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
-            //load the class or try to support custom subclasses that we don't have available in the classpath but end in 'FileAppender'
-            if (appenderClass.getNodeValue().toLowerCase().endsWith("fileappender") || FileAppender.class.isAssignableFrom(Class.forName(appenderClass.getNodeValue()))) {
-              String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
-              //subclass of FileAppender - add it
-              Map entry = new HashMap();
-              NodeList appenderChildren = appender.getChildNodes();
-              for (int j = 0; j < appenderChildren.getLength(); j++) {
-                Node appenderChild = appenderChildren.item(j);
-                if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
-                  Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
-                  if (fileNameNode != null && fileNameNode.getNodeValue().equals("file")) {
-                    Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
-                    if (fileValueNode != null) {
-                      entry.put("file", fileValueNode.getNodeValue());
-                    }
+        if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
+          //all log4j fileappenders end in fileappender..if a custom fileappender also ends in fileappender and uses the same dom nodes to be loaded,
+          //try to parse the nodes as well
+          if (appenderClass.getNodeValue().toLowerCase().endsWith("fileappender")) {
+            String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
+            //subclass of FileAppender - add it
+            Map entry = new HashMap();
+            NodeList appenderChildren = appender.getChildNodes();
+            for (int j = 0; j < appenderChildren.getLength(); j++) {
+              Node appenderChild = appenderChildren.item(j);
+              if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
+                Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
+                if (fileNameNode != null && fileNameNode.getNodeValue().equals("file")) {
+                  Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
+                  if (fileValueNode != null) {
+                    entry.put("file", fileValueNode.getNodeValue());
                   }
                 }
-                if (appenderChild.getNodeName().equals("layout") && appenderChild.hasAttributes()) {
-                  NamedNodeMap layoutAttributes = appenderChild.getAttributes();
-                  Node layoutNode = layoutAttributes.getNamedItem("class");
-                  if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
-                    NodeList layoutChildren = appenderChild.getChildNodes();
-                    for (int k = 0; k < layoutChildren.getLength(); k++) {
-                      Node layoutChild = layoutChildren.item(k);
-                      if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
-                        Node layoutName = layoutChild.getAttributes().getNamedItem("name");
-                        if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equals("ConversionPattern")) {
-                          Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
-                          if (conversionValue != null) {
-                            entry.put("conversion", conversionValue.getNodeValue());
-                          }
+              }
+              if (appenderChild.getNodeName().equals("layout") && appenderChild.hasAttributes()) {
+                NamedNodeMap layoutAttributes = appenderChild.getAttributes();
+                Node layoutNode = layoutAttributes.getNamedItem("class");
+                if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
+                  NodeList layoutChildren = appenderChild.getChildNodes();
+                  for (int k = 0; k < layoutChildren.getLength(); k++) {
+                    Node layoutChild = layoutChildren.item(k);
+                    if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
+                      Node layoutName = layoutChild.getAttributes().getNamedItem("name");
+                      if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equals("ConversionPattern")) {
+                        Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
+                        if (conversionValue != null) {
+                          entry.put("conversion", conversionValue.getNodeValue());
                         }
                       }
                     }
                   }
                 }
               }
-              result.put(appenderName, entry);
             }
+            result.put(appenderName, entry);
           }
-        } catch (Exception e) {
-          e.printStackTrace();
         }
       }
     } finally {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cf258edd/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index e8bf684..61e9bf3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1496,10 +1496,6 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                   }
                 } catch (IOException e1) {
                   e1.printStackTrace();
-                } catch (ParserConfigurationException e1) {
-                  e1.printStackTrace();
-                } catch (SAXException e1) {
-                  e1.printStackTrace();
                 }
               }
             } else if (receiverConfigurationPanel.getModel().isLoadConfig()) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cf258edd/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index a6c3715..c755963 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -139,17 +139,17 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        logFileReceiverRadioButton = new JRadioButton(" Load and tail events from a regular text log file ");
-        buttonGroup.add(logFileReceiverRadioButton);
-        add(logFileReceiverRadioButton, c);
+        log4jConfigReceiverRadioButton = new JRadioButton(" Use fileappender entries from a log4j config file ");
+        buttonGroup.add(log4jConfigReceiverRadioButton);
+        add(log4jConfigReceiverRadioButton, c);
 
         c = new GridBagConstraints();
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        log4jConfigReceiverRadioButton = new JRadioButton(" Use log4j.xml fileappender configuration ");
-        buttonGroup.add(log4jConfigReceiverRadioButton);
-        add(log4jConfigReceiverRadioButton, c);
+        logFileReceiverRadioButton = new JRadioButton(" Process a log file ");
+        buttonGroup.add(logFileReceiverRadioButton);
+        add(logFileReceiverRadioButton, c);
 
         c = new GridBagConstraints();
         c.gridx = 0;
@@ -163,7 +163,7 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
-        useExistingConfigurationRadioButton = new JRadioButton(" Use an existing Chainsaw configuration file ");
+        useExistingConfigurationRadioButton = new JRadioButton(" Use a Chainsaw config file ");
         buttonGroup.add(useExistingConfigurationRadioButton);
         add(useExistingConfigurationRadioButton, c);
 
@@ -204,8 +204,8 @@ class ReceiverConfigurationPanel extends JPanel {
         networkReceiverRadioButton.addActionListener(al);
         useExistingConfigurationRadioButton.addActionListener(al);
 
-        buttonGroup.setSelected(logFileReceiverRadioButton.getModel(), true);
-        updateEnabledState(logFileReceiverRadioButton);
+        buttonGroup.setSelected(log4jConfigReceiverRadioButton.getModel(), true);
+        updateEnabledState(log4jConfigReceiverRadioButton);
     }
 
     private JPanel buildDontWarnAndOKPanel() {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cf258edd/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index f267cea..59a0fb5 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,6 +10,10 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>6 Nov 2010</h2>
+<ul>
+<li>Log file receiver configurations can now be loaded from both log4j.xml and log4j.properties configuration fileappender entries</li>
+</ul>
 <h2>5 Nov 2010</h2>
 <ul>
 <li>Added ability to create log file receiver configurations from log4j xml configuration fileappender entries</li>


[49/50] [abbrv] logging-chainsaw git commit: Use UTF-8 encoding for VFS/LogFilePatternReceiver readers

Posted by rg...@apache.org.
Use UTF-8 encoding for VFS/LogFilePatternReceiver readers


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/c52dd714
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/c52dd714
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/c52dd714

Branch: refs/heads/master
Commit: c52dd714405bd337d27f68a0ec2fd0531df7966d
Parents: e2021f8
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Jun 14 08:10:13 2014 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Jun 14 08:10:13 2014 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java       | 9 ++++++---
 .../java/org/apache/log4j/varia/LogFilePatternReceiver.java | 2 +-
 2 files changed, 7 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/c52dd714/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
index 29dc146..1d7acc0 100644
--- a/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/chainsaw/vfs/VFSLogFilePatternReceiver.java
@@ -29,6 +29,7 @@ import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.Reader;
+import java.io.UnsupportedEncodingException;
 
 import javax.swing.JButton;
 import javax.swing.JDialog;
@@ -356,7 +357,7 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
 
                     fileObject = fileSystemManager.resolveFile(getFileURL(), opts);
                     if (fileObject.exists()) {
-                        reader = new InputStreamReader(fileObject.getContent().getInputStream());
+                        reader = new InputStreamReader(fileObject.getContent().getInputStream() , "UTF-8");
                         //now that we have a reader, remove additional portions of the file url (sftp passwords, etc.)
                         //check to see if the name is a URLFileName..if so, set file name to not include username/pass
                         if (fileObject.getName() instanceof URLFileName) {
@@ -369,6 +370,8 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                     }
                 } catch (FileSystemException fse) {
                     getLogger().info(loggableFileURL + " not available - may be due to incorrect credentials, but will re-attempt to load after waiting " + MISSING_FILE_RETRY_MILLIS + " millis", fse);
+                } catch (UnsupportedEncodingException e) {
+                    getLogger().info("UTF-8 not available", e);
                 }
                 if (reader == null) {
                     synchronized (this) {
@@ -419,7 +422,7 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                             }
                             //could have been truncated or appended to (don't do anything if same size)
                             if (fileObject.getContent().getSize() < lastFileSize) {
-                                reader = new InputStreamReader(fileObject.getContent().getInputStream());
+                                reader = new InputStreamReader(fileObject.getContent().getInputStream(), "UTF-8");
                                 getLogger().debug(getPath() + " was truncated");
                                 lastFileSize = 0; //seek to beginning of file
                                 lastFilePointer = 0;
@@ -427,7 +430,7 @@ public class VFSLogFilePatternReceiver extends LogFilePatternReceiver implements
                                 fileLarger = true;
                                 RandomAccessContent rac = fileObject.getContent().getRandomAccessContent(RandomAccessMode.READ);
                                 rac.seek(lastFilePointer);
-                                reader = new InputStreamReader(rac.getInputStream());
+                                reader = new InputStreamReader(rac.getInputStream(), "UTF-8");
                                 BufferedReader bufferedReader = new BufferedReader(reader);
                                 process(bufferedReader);
                                 lastFilePointer = rac.getFilePointer();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/c52dd714/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index df91332..3a39508 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -1046,7 +1046,7 @@ public class LogFilePatternReceiver extends Receiver {
             while (reader == null) {
                 getLogger().info("attempting to load file: " + getFileURL());
                 try {
-                    reader = new InputStreamReader(new URL(getFileURL()).openStream());
+                    reader = new InputStreamReader(new URL(getFileURL()).openStream(), "UTF-8");
                 } catch (FileNotFoundException fnfe) {
                     getLogger().info("file not available - will try again");
                     synchronized (this) {


[24/50] [abbrv] logging-chainsaw git commit: Updated the expression handling logic to no longer require spaces around operators & operands in expressions

Posted by rg...@apache.org.
Updated the expression handling logic to no longer require spaces around operators & operands in expressions


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/9784229a
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/9784229a
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/9784229a

Branch: refs/heads/master
Commit: 9784229ae054b3a5e1bff054e8af4aef3e136f37
Parents: a9a78bf
Author: Scott Deboy <sd...@apache.org>
Authored: Sun Nov 7 07:12:17 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sun Nov 7 07:12:17 2010 +0000

----------------------------------------------------------------------
 src/main/java/org/apache/log4j/chainsaw/LogUI.java            | 7 ++++++-
 .../org/apache/log4j/chainsaw/help/release-notes.html         | 1 +
 .../resources/org/apache/log4j/chainsaw/help/tutorial.html    | 1 -
 3 files changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9784229a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 61e9bf3..ce6154a 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -1032,7 +1032,12 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     getSettingsManager().addSettingsListener(this);
     getSettingsManager().addSettingsListener(MRUFileListPreferenceSaver.getInstance());
     getSettingsManager().addSettingsListener(receiversPanel);
-    getSettingsManager().loadSettings();
+    try {
+      //if an uncaught exception is thrown, allow the UI to continue to load
+      getSettingsManager().loadSettings();
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
     //app preferences have already been loaded (and configuration url possibly set to blank if being overridden)
     //but we need a listener so the settings will be saved on exit (added after loadsettings was called)
     getSettingsManager().addSettingsListener(new ApplicationPreferenceModelSaver(applicationPreferenceModel));

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9784229a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index c9799bc..681cfc0 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -12,6 +12,7 @@
 <h1>2.1</h1>
 <h2>6 Nov 2010</h2>
 <ul>
+<li>Updated the expression handling logic to no longer require spaces around operators & operands in expressions</li>
 <li>Log file receiver configurations can now be loaded from both log4j.xml and log4j.properties configuration fileappender entries</li>
 <li>Added multi-select capability to event table and 'copy selection' context menu item (multi-select by holding down alt key while selecting rows)</li>
 </ul>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/9784229a/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html b/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
index 0f54454..e9b3b5d 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
@@ -130,7 +130,6 @@ Expressions are used to define color and display rules in Chainsaw.  An expressi
 
 <ul>
 <li>Precedence can be controlled by applying parentheses to groups of expressions (usually used in combination with logical operators)</li>
-<li>All operators, operands and parentheses must be separated by spaces</li>
 <li>Single tick marks can be used to delimit multi-word operands</li>
 <li>Example: msg ~= <b>'my msg'</b></li>
 <li><b>NOTE:</b> A context menu is available anywhere you can enter an expression in order to assist in constructing expressions (use the right-mouse click or ctrl-space to activate the context menu) </li>


[07/50] [abbrv] logging-chainsaw git commit: Fixes to persistence of detail panel position, not updating look and feel if not set

Posted by rg...@apache.org.
Fixes to persistence of detail panel position, not updating look and feel if not set


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/a3dda155
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/a3dda155
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/a3dda155

Branch: refs/heads/master
Commit: a3dda1555bcc1febc0d55decbb3c77ebc88d4aeb
Parents: 3449713
Author: Scott Deboy <sd...@apache.org>
Authored: Tue Oct 26 04:45:07 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Tue Oct 26 04:45:07 2010 +0000

----------------------------------------------------------------------
 .../org/apache/log4j/chainsaw/LogPanel.java     | 49 +++++++++++---------
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 11 +++--
 2 files changed, 32 insertions(+), 28 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/a3dda155/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index d2bc5e3..189cac4 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -233,7 +233,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   private final RuleMediator tableRuleMediator = new RuleMediator(false);
   private final RuleMediator searchRuleMediator = new RuleMediator(true);
   private final EventDetailLayout detailLayout = new EventDetailLayout();
-  private double lastDetailPanelSplitLocation = DEFAULT_DETAIL_SPLIT_LOCATION;
   private double lastLogTreePanelSplitLocation = DEFAULT_LOG_TREE_SPLIT_LOCATION;
   private Point currentPoint;
   private JTable currentTable;
@@ -269,6 +268,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
   private boolean searchResultsDisplayed;
   private ColorizedEventAndSearchMatchThumbnail colorizedEventAndSearchMatchThumbnail;
   private EventTimeDeltaMatchThumbnail eventTimeDeltaMatchThumbnail;
+  private boolean isDetailPanelVisible;
 
   /**
    * Creates a new LogPanel object.  If a LogPanel with this identifier has
@@ -2268,9 +2268,9 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                     loadDefaultColumnSettings(event);
                 }
                 //ensure tablemodel cyclic flag is updated
+                //may be panel configs that don't have these values
                 tableModel.setCyclic(preferenceModel.isCyclic());
                 searchModel.setCyclic(preferenceModel.isCyclic());
-                //may be panel configs that don't have these values
                 lowerPanel.setDividerLocation(lowerPanelDividerLocation);
                 nameTreeAndMainPanelSplit.setDividerLocation(treeDividerLocation);
                 detailLayout.setConversionPattern(conversionPattern);
@@ -2296,9 +2296,12 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
             }
         }
     } else {
+        //not setting lower panel divider location here - will do that after the UI is visible
         loadDefaultColumnSettings(event);
     }
-
+    //ensure tablemodel cyclic flag is updated
+    tableModel.setCyclic(preferenceModel.isCyclic());
+    searchModel.setCyclic(preferenceModel.isCyclic());
     logTreePanel.ignore(preferenceModel.getHiddenLoggers());
     logTreePanel.setHiddenExpression(preferenceModel.getHiddenExpression());
     if (preferenceModel.getClearTableExpression() != null) {
@@ -2347,12 +2350,13 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     	FileWriter w = new FileWriter(xmlFile);
     	s = stream.createObjectOutputStream(w);
     	s.writeObject(preferenceModel);
-        if (lowerPanelDividerLocation == 0) {
-            //pick a reasonable default
-            s.writeInt((int) (lowerPanel.getSize().height * DEFAULT_DETAIL_SPLIT_LOCATION));
-        } else {
-            s.writeInt(lowerPanelDividerLocation);
-        }
+      if (isDetailPanelVisible) {
+        //use current size
+        s.writeInt(lowerPanel.getDividerLocation());
+      } else {
+        //use size when last hidden
+        s.writeInt(lowerPanelDividerLocation);
+      }
     	s.writeInt(nameTreeAndMainPanelSplit.getDividerLocation());
     	s.writeObject(detailLayout.getConversionPattern());
     	s.writeObject(undockedFrame.getLocation());
@@ -2701,34 +2705,33 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
    * Display the detail pane, using the last known divider location
    */
   private void showDetailPane() {
-    lowerPanel.setDividerSize(dividerSize);
-      if (lowerPanelDividerLocation != 0) {
-          lowerPanel.setDividerLocation(lowerPanelDividerLocation);
+    if (!isDetailPanelVisible) {
+      lowerPanel.setDividerSize(dividerSize);
+      if (lowerPanelDividerLocation == 0) {
+        lowerPanel.setDividerLocation(DEFAULT_DETAIL_SPLIT_LOCATION);
+        lowerPanelDividerLocation = lowerPanel.getDividerLocation();
       } else {
-          lowerPanel.setDividerLocation(lastDetailPanelSplitLocation);
+        lowerPanel.setDividerLocation(lowerPanelDividerLocation);
       }
       detailPanel.setVisible(true);
       detailPanel.repaint();
       lowerPanel.repaint();
+      isDetailPanelVisible = true;
+    }
   }
 
   /**
    * Hide the detail pane, holding the current divider location for later use
    */
   private void hideDetailPane() {
-    int currentSize = lowerPanel.getHeight() - lowerPanel.getDividerSize();
-
-    if (currentSize > 0) {
-      lastDetailPanelSplitLocation =
-        (double) lowerPanel.getDividerLocation() / currentSize;
-     }
-     if (lowerPanel.getDividerLocation() > 0) {
-        lowerPanelDividerLocation = lowerPanel.getDividerLocation();
-     }
-
+    //may be called not currently visible on initial setup to ensure panel is not visible..only update divider location if hiding when currently visible
+    if (isDetailPanelVisible) {
+      lowerPanelDividerLocation = lowerPanel.getDividerLocation();
+    }
     lowerPanel.setDividerSize(0);
     detailPanel.setVisible(false);
     lowerPanel.repaint();
+    isDetailPanelVisible = false;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/a3dda155/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index e85a974..984a421 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -286,8 +286,11 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     {
         public void run()
         {
-            loadLookAndFeelUsingPluginClassLoader(model.getLookAndFeelClassName());
-            createChainsawGUI(model, null);
+          String lookAndFeelClassName = model.getLookAndFeelClassName();
+          if (lookAndFeelClassName != null && !(lookAndFeelClassName.trim().equals(""))) {
+            loadLookAndFeelUsingPluginClassLoader(lookAndFeelClassName);
+          }
+          createChainsawGUI(model, null);
         }
     });
   }
@@ -1040,12 +1043,10 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
       initializationLock.notifyAll();
     }
 
-    
-    
     if (
       noReceiversDefined
         && applicationPreferenceModel.isShowNoReceiverWarning()) {
-      EventQueue.invokeLater(new Runnable() {
+      SwingHelper.invokeOnEDT(new Runnable() {
           public void run() {
               showReceiverConfigurationPanel();
           }


[08/50] [abbrv] logging-chainsaw git commit: Reverting commit adding support for 'basic' rendering in tablemodel

Posted by rg...@apache.org.
Reverting commit adding support for 'basic' rendering in tablemodel


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/ab85cf0d
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/ab85cf0d
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/ab85cf0d

Branch: refs/heads/master
Commit: ab85cf0df5bb39216133876cbb1ba113fe657814
Parents: a3dda15
Author: Scott Deboy <sd...@apache.org>
Authored: Tue Oct 26 06:31:49 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Tue Oct 26 06:31:49 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/TableColorizingRenderer.java | 179 +++----------------
 1 file changed, 24 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/ab85cf0d/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index 37c2b7e..209204d 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -188,17 +188,8 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     int colIndex = tableColumn.getModelIndex() + 1;
 
     //no event, use default renderer
-
-    JLabel basicComponent = null;
-    boolean basic = (!wrap && !highlightSearchMatchText && !logPanelPreferenceModel.isShowMillisDeltaAsGap());
-    if (basic || loggingEventWrapper == null) {
-      Component rendererComponent = super.getTableCellRendererComponent(table, value, false, false, row, col);
-      if (!(rendererComponent instanceof JLabel) || loggingEventWrapper == null) {
-        return rendererComponent;
-      }
-      basicComponent = (JLabel)rendererComponent;
-      basicComponent.setFont(levelTextPane.getFont());
-      setBasicComponentBorder(basicComponent, isSelected, table, col);
+    if (loggingEventWrapper == null) {
+        return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
     }
     long delta = 0;
     if (row > 0) {
@@ -212,9 +203,6 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     switch (colIndex) {
     case ChainsawColumns.INDEX_THROWABLE_COL_NAME:
       if (value instanceof String[] && ((String[])value).length > 0){
-        if (basic) {
-          basicComponent.setText(((String[])value)[0]);
-        } else {
           Style tabStyle = singleLineTextPane.getLogicalStyle();
           StyleConstants.setTabSet(tabStyle, tabs);
           //set the 1st tab at position 3
@@ -227,20 +215,11 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
           } else {
               singleLineTextPane.setText(((String[])value)[0]);
           }
-        }
       } else {
-        if (basic) {
-          basicComponent.setText("");
-        } else {
-          singleLineTextPane.setText("");
-        }
-      }
-      if (basic) {
-        component = basicComponent;
-      } else {
-        layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
-        component = generalPanel;
+        singleLineTextPane.setText("");
       }
+      layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
+      component = generalPanel;
       break;
     case ChainsawColumns.INDEX_LOGGER_COL_NAME:
       String logger = value.toString();
@@ -252,88 +231,49 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
           break;
         }
       }
-      if (basic) {
-        basicComponent.setText(logger.substring(startPos + 1));
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(logger.substring(startPos + 1));
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LOGGER_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
       break;
     case ChainsawColumns.INDEX_ID_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.PROP_FIELD + "LOG4JID"), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_CLASS_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.CLASS_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_FILE_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.FILE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_LINE_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LINE_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_NDC_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.NDC_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_THREAD_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.THREAD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_TIMESTAMP_COL_NAME:
         //timestamp matches contain the millis..not the display text..just highlight if we have a match for the timestamp field
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         Set timestampMatches = (Set)matches.get(LoggingEventFieldResolver.TIMESTAMP_FIELD);
         if (timestampMatches != null && timestampMatches.size() > 0) {
             singleLineTextPane.setText(value.toString());
@@ -343,26 +283,16 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_METHOD_COL_NAME:
-      if (basic) {
-        basicComponent.setText(value.toString());
-        component = basicComponent;
-      } else {
         singleLineTextPane.setText(value.toString());
         setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.METHOD_FIELD), (StyledDocument) singleLineTextPane.getDocument());
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     case ChainsawColumns.INDEX_LOG4J_MARKER_COL_NAME:
     case ChainsawColumns.INDEX_MESSAGE_COL_NAME:
         String thisString = value.toString().trim();
-      if (basic) {
-        basicComponent.setText(thisString);
-        component = basicComponent;
-      } else {
         JTextPane textPane = wrap ? multiLineTextPane : singleLineTextPane;
         JComponent textPaneContainer = wrap ? multiLinePanel : generalPanel;
         textPane.setText(thisString);
@@ -443,52 +373,28 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
 
         component = textPaneContainer;
-      }
         break;
     case ChainsawColumns.INDEX_LEVEL_COL_NAME:
       if (levelUseIcons) {
-        if (basic) {
-          basicComponent.setText("");
-          basicComponent.setIcon((Icon)iconMap.get(value.toString()));
-          if (!toolTipsVisible) {
-            basicComponent.setToolTipText(value.toString());
-          }
-        } else {
-          levelTextPane.setText("");
-          levelTextPane.insertIcon((Icon) iconMap.get(value.toString()));
-          if (!toolTipsVisible) {
-            levelTextPane.setToolTipText(value.toString());
-          }
+        levelTextPane.setText("");
+        levelTextPane.insertIcon((Icon) iconMap.get(value.toString()));
+        if (!toolTipsVisible) {
+          levelTextPane.setToolTipText(value.toString());
         }
       } else {
-        if (basic) {
-          basicComponent.setText(value.toString());
-          if (!toolTipsVisible) {
-              basicComponent.setToolTipText(null);
-          }
-        } else {
-          levelTextPane.setText(value.toString());
-          setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LEVEL_FIELD), (StyledDocument) levelTextPane.getDocument());
-          if (!toolTipsVisible) {
-              levelTextPane.setToolTipText(null);
-          }
+        levelTextPane.setText(value.toString());
+        setHighlightAttributesInternal(matches.get(LoggingEventFieldResolver.LEVEL_FIELD), (StyledDocument) levelTextPane.getDocument());
+        if (!toolTipsVisible) {
+            levelTextPane.setToolTipText(null);
         }
       }
       if (toolTipsVisible) {
-        if (basic) {
-          basicComponent.setToolTipText(label.getToolTipText());
-        } else {
           levelTextPane.setToolTipText(label.getToolTipText());
-        }
-      }
-      if (basic) {
-        component = basicComponent;
-      } else {
-        levelTextPane.setForeground(label.getForeground());
-        levelTextPane.setBackground(label.getBackground());
-        layoutRenderingPanel(levelPanel, levelTextPane, delta, isSelected, width, col, table);
-        component = levelPanel;
       }
+      levelTextPane.setForeground(label.getForeground());
+      levelTextPane.setBackground(label.getBackground());
+      layoutRenderingPanel(levelPanel, levelTextPane, delta, isSelected, width, col, table);
+      component = levelPanel;
       break;
 
     //remaining entries are properties
@@ -507,26 +413,13 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         if (thisProp != null) {
             String propKey = LoggingEventFieldResolver.PROP_FIELD + thisProp.toUpperCase();
             Set propKeyMatches = (Set)matches.get(propKey);
-            String propertyValue = loggingEventWrapper.getLoggingEvent().getProperty(thisProp);
-          if (basic) {
-            basicComponent.setText(propertyValue);
-          } else {
-            singleLineTextPane.setText(propertyValue);
+            singleLineTextPane.setText(loggingEventWrapper.getLoggingEvent().getProperty(thisProp));
             setHighlightAttributesInternal(propKeyMatches, (StyledDocument) singleLineTextPane.getDocument());
-          }
         } else {
-          if (basic) {
-            basicComponent.setText("");
-          } else {
             singleLineTextPane.setText("");
-          }
         }
-      if (basic) {
-        component = basicComponent;
-      } else {
         layoutRenderingPanel(generalPanel, singleLineTextPane, delta, isSelected, width, col, table);
         component = generalPanel;
-      }
         break;
     }
 
@@ -561,40 +454,16 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
     component.setForeground(foreground);
 
     //update the background & foreground of the jtextpane using styles
-    if (!basic) {
-      if (multiLineTextPane != null)
-      {
-          updateColors(multiLineTextPane, background, foreground);
-      }
-      updateColors(levelTextPane, background, foreground);
-      updateColors(singleLineTextPane, background, foreground);
+    if (multiLineTextPane != null)
+    {
+        updateColors(multiLineTextPane, background, foreground);
     }
-    return component;
-  }
+    updateColors(levelTextPane, background, foreground);
+    updateColors(singleLineTextPane, background, foreground);
 
-  private void setBasicComponentBorder(JComponent component, boolean isSelected, JTable table, int col) {
-    setComponentBorder(component, isSelected, table, col, 0);
+    return component;
   }
 
-  private void setComponentBorder(JComponent component, boolean isSelected, JTable table, int col, long delta) {
-    if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
-      if (col == 0) {
-        component.setBorder(getLeftBorder(isSelected, delta));
-      } else if (col == table.getColumnCount() - 1) {
-        component.setBorder(getRightBorder(isSelected, delta));
-      } else {
-        component.setBorder(getMiddleBorder(isSelected, delta));
-      }
-    } else {
-        if (col == 0) {
-          component.setBorder(getLeftBorder(isSelected, 0));
-        } else if (col == table.getColumnCount() - 1) {
-          component.setBorder(getRightBorder(isSelected, 0));
-        } else {
-          component.setBorder(getMiddleBorder(isSelected, 0));
-        }
-      }
-  }
     private void layoutRenderingPanel(JComponent container, JComponent bottomComponent, long delta, boolean isSelected,
                                       int width, int col, JTable table) {
         container.removeAll();


[06/50] [abbrv] logging-chainsaw git commit: Replace 'search' in the UI with 'find' Syncing addition & removal of entries in the refine focus & find combo boxes

Posted by rg...@apache.org.
Replace 'search' in the UI with 'find'
Syncing addition & removal of entries in the refine focus & find combo boxes



Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/34497133
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/34497133
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/34497133

Branch: refs/heads/master
Commit: 344971335cfdf8005de1d920a3b21d748ef120d3
Parents: 622fc25
Author: Scott Deboy <sd...@apache.org>
Authored: Mon Oct 25 05:00:03 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Mon Oct 25 05:00:03 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/ChainsawStatusBar.java       |  4 +-
 .../log4j/chainsaw/ChainsawToolBarAndMenus.java |  8 ++--
 .../org/apache/log4j/chainsaw/LogPanel.java     | 48 +++++++++++++-------
 .../log4j/chainsaw/LogPanelPreferencePanel.java |  4 +-
 .../log4j/chainsaw/LoggerNameTreePanel.java     | 10 ++--
 .../apache/log4j/chainsaw/color/ColorPanel.java |  2 +-
 .../log4j/chainsaw/help/release-notes.html      |  6 +--
 .../apache/log4j/chainsaw/help/tutorial.html    | 12 ++---
 8 files changed, 54 insertions(+), 40 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/ChainsawStatusBar.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawStatusBar.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawStatusBar.java
index 55d9f29..ddaaf73 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawStatusBar.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawStatusBar.java
@@ -104,7 +104,7 @@ public class ChainsawStatusBar extends JPanel {
     searchMatchLabel.setToolTipText("<# viewable events>:<# total events>");
     searchMatchLabel.setMinimumSize(
     new Dimension(
-    searchMatchLabel.getFontMetrics(eventCountLabel.getFont()).stringWidth("Search matches: 999999999999") + 5,
+    searchMatchLabel.getFontMetrics(eventCountLabel.getFont()).stringWidth("Find matches: 999999999999") + 5,
             (int) searchMatchLabel.getPreferredSize().getHeight()));
 
     receivedConnectionlabel.setBorder(statusBarComponentBorder);
@@ -273,7 +273,7 @@ public class ChainsawStatusBar extends JPanel {
           if (searchMatchCount == 0) {
             searchMatchLabel.setText("");
           } else {
-            searchMatchLabel.setText("Search matches: " + searchMatchCount);
+            searchMatchLabel.setText("Find matches: " + searchMatchCount);
           }
       }
   }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
index 9f5165a..ffe9543 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
@@ -274,7 +274,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
            }
          };
 
-       action.putValue(Action.SHORT_DESCRIPTION, "Searches for the next marker from the current location");
+       action.putValue(Action.SHORT_DESCRIPTION, "Find the next marker from the current location");
        action.putValue("enabled", Boolean.TRUE);
        action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke("F2"));
@@ -292,7 +292,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
           }
         };
 
-      action.putValue(Action.SHORT_DESCRIPTION, "Searches for the previous marker from the current location");
+      action.putValue(Action.SHORT_DESCRIPTION, "Find the previous marker from the current location");
       action.putValue("enabled", Boolean.TRUE);
       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
       action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  InputEvent.SHIFT_MASK));
@@ -892,7 +892,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
             }
           }
         };
-        action.putValue(Action.SHORT_DESCRIPTION, "Searches for the next colorized event from the current location");
+        action.putValue(Action.SHORT_DESCRIPTION, "Find the next colorized event from the current location");
         action.putValue("enabled", Boolean.TRUE);
         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
         action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
@@ -911,7 +911,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
             }
           }
         };
-        action.putValue(Action.SHORT_DESCRIPTION, "Searches for the next colorized event from the current location");
+        action.putValue(Action.SHORT_DESCRIPTION, "Find the next colorized event from the current location");
         action.putValue("enabled", Boolean.TRUE);
         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
         action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index ea80971..d2bc5e3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -79,6 +79,7 @@ import javax.swing.Box;
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
 import javax.swing.ComboBoxEditor;
+import javax.swing.ComboBoxModel;
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
 import javax.swing.JCheckBoxMenuItem;
@@ -288,12 +289,13 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     String prototypeValue = "1231231231231231231231";
 
     filterCombo = new AutoFilterComboBox();
+    findCombo = new AutoFilterComboBox();
+
     filterCombo.setPrototypeDisplayValue(prototypeValue);
-    buildCombo(filterCombo, true);
+    buildCombo(filterCombo, true, findCombo.model);
 
-    findCombo = new AutoFilterComboBox();
     findCombo.setPrototypeDisplayValue(prototypeValue);
-    buildCombo(findCombo, false);
+    buildCombo(findCombo, false, filterCombo.model);
 
     final Map columnNameKeywordMap = new HashMap();
     columnNameKeywordMap.put(ChainsawConstants.CLASS_COL_NAME, LoggingEventFieldResolver.CLASS_FIELD);
@@ -1105,20 +1107,28 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     upperPanel.add(filterCombo);
     upperPanel.add(Box.createHorizontalStrut(3));
 
+    final JTextField filterText =(JTextField) filterCombo.getEditor().getEditorComponent();
+    final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
+
+
     //Adding a button to clear filter expressions which are currently remembered by Chainsaw...
     final JButton removeFilterButton = new JButton(" Remove ");
-    final JTextField filterText =(JTextField) filterCombo.getEditor().getEditorComponent();
+
     removeFilterButton.setToolTipText("Click here to remove the selected expression from the list");
     removeFilterButton.addActionListener(
             new AbstractAction() {
                 public void actionPerformed(ActionEvent e){
                 	Object selectedItem = filterCombo.getSelectedItem();
                     if (e.getSource() == removeFilterButton && selectedItem != null && !selectedItem.toString().trim().equals("")){
-                        //don't just remove the entry from the store, clear the field
-                        int index = filterCombo.getSelectedIndex();
-                        filterText.setText(null);
-                        filterCombo.setSelectedIndex(-1);
-                        filterCombo.removeItemAt(index);
+                      //don't just remove the entry from the store, clear the field
+                      int index = filterCombo.getSelectedIndex();
+                      filterText.setText(null);
+                      filterCombo.setSelectedIndex(-1);
+                      filterCombo.removeItemAt(index);
+                      if (!(findCombo.getSelectedItem() != null && findCombo.getSelectedItem().equals(selectedItem))) {
+                        //now remove the entry from the other model
+                        ((AutoFilterComboBox.AutoFilterComboBoxModel)findCombo.getModel()).removeElement(selectedItem);
+                      }
                     }
                 }
             }
@@ -1162,18 +1172,21 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     
     //Adding a button to clear filter expressions which are currently remembered by Chainsaw...
     final JButton removeFindButton = new JButton(" Remove ");
-    final JTextField findText =(JTextField) findCombo.getEditor().getEditorComponent();
     removeFindButton.setToolTipText("Click here to remove the selected expression from the list");
     removeFindButton.addActionListener(
             new AbstractAction() {
                 public void actionPerformed(ActionEvent e){
                 	Object selectedItem = findCombo.getSelectedItem();
                     if (e.getSource() == removeFindButton && selectedItem != null && !selectedItem.toString().trim().equals("")){
-                        //don't just remove the entry from the store, clear the field
-                        int index = findCombo.getSelectedIndex();
-                        findText.setText(null);
-                        findCombo.setSelectedIndex(-1);
-                        findCombo.removeItemAt(index);
+                      //don't just remove the entry from the store, clear the field
+                      int index = findCombo.getSelectedIndex();
+                      findText.setText(null);
+                      findCombo.setSelectedIndex(-1);
+                      findCombo.removeItemAt(index);
+                      if (!(filterCombo.getSelectedItem() != null && filterCombo.getSelectedItem().equals(selectedItem))) {
+                        //now remove the entry from the other model if it wasn't selected
+                        ((AutoFilterComboBox.AutoFilterComboBoxModel)filterCombo.getModel()).removeElement(selectedItem);
+                      }
                     }
                 }
             }
@@ -1796,7 +1809,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
      class ClearSearch extends AbstractAction {
        public ClearSearch() {
-         super("Clear search field");
+         super("Clear find field");
        }
           public void actionPerformed(ActionEvent e) {
             findCombo.setSelectedItem(null);
@@ -1959,7 +1972,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     return action;
   }
 
-  private  void buildCombo(final JComboBox combo, boolean isFiltering) {
+  private  void buildCombo(final AutoFilterComboBox combo, boolean isFiltering, final AutoFilterComboBox.AutoFilterComboBoxModel otherModel) {
     //add (hopefully useful) default filters
     combo.addItem("LEVEL == TRACE");
     combo.addItem("LEVEL >= DEBUG");
@@ -1987,6 +2000,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                     ExpressionRule.getRule(item.toString());
                     //add entry as first row of the combo box
                     combo.insertItemAt(item, 0);
+                    otherModel.insertElementAt(item, 0);
                   }
                 //valid expression, reset background color in case we were previously an invalid expression
                 filterText.setBackground(UIManager.getColor("TextField.background"));

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
index 254b59c..6967785 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanelPreferencePanel.java
@@ -531,8 +531,8 @@ public class LogPanelPreferencePanel extends AbstractPreferencePanel
     private final JCheckBox loggerTreePanel =
       new JCheckBox("Show Logger Tree");
     private final JCheckBox wrapMessage = new JCheckBox("Wrap message field (display multi-line rows) ");
-    private final JCheckBox searchResultsVisible = new JCheckBox("Display search results in details panel ");
-    private final JCheckBox highlightSearchMatchText = new JCheckBox("Highlight search match text ");
+    private final JCheckBox searchResultsVisible = new JCheckBox("Display find results in details panel ");
+    private final JCheckBox highlightSearchMatchText = new JCheckBox("Highlight find match text ");
     private final JCheckBox scrollToBottom =
       new JCheckBox("Scroll to bottom (view tracks with new events)");
     private final JCheckBox showMillisDeltaAsGap =

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
index 64fe415..f5ac429 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LoggerNameTreePanel.java
@@ -829,7 +829,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
       action.putValue(Action.NAME, "Find next");
       action.putValue(
         Action.SHORT_DESCRIPTION,
-        "Search using the selected node");
+        "Find using the selected node");
       action.setEnabled(false);
 
       return action;
@@ -941,10 +941,10 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
           }
         };
 
-      action.putValue(Action.NAME, "Clear search field");
+      action.putValue(Action.NAME, "Clear find field");
       action.putValue(
         Action.SHORT_DESCRIPTION,
-        "Clear the search field");
+        "Clear the find field");
       action.setEnabled(false);
 
       return action;
@@ -1238,7 +1238,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     {
       focusOnAction.putValue(Action.NAME, "Focus On...");
       hideAction.putValue(Action.NAME, "Ignore...");
-      findNextAction.putValue(Action.NAME, "Search for...");
+      findNextAction.putValue(Action.NAME, "Find...");
       setRefineFocusAction.putValue(Action.NAME, "Set refine focus field");
       updateRefineFocusAction.putValue(Action.NAME, "Add to refine focus field");
       defineColorRuleForLoggerAction.putValue(Action.NAME, "Define color rule");
@@ -1247,7 +1247,7 @@ final class LoggerNameTreePanel extends JPanel implements LoggerNameListener
     {
       focusOnAction.putValue(Action.NAME, "Focus On '" + logger + "'");
       hideAction.putValue(Action.NAME, "Ignore '" + logger + "'");
-      findNextAction.putValue(Action.NAME, "Search for '" + logger + "'");
+      findNextAction.putValue(Action.NAME, "Find '" + logger + "'");
       setRefineFocusAction.putValue(Action.NAME, "Set refine focus field to '" + logger + "'");
       updateRefineFocusAction.putValue(Action.NAME, "Add '" + logger + "' to 'refine focus' field");
       defineColorRuleForLoggerAction.putValue(Action.NAME, "Define color rule for '" + logger + "'");

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
index 184ace4..7dc0911 100644
--- a/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/color/ColorPanel.java
@@ -303,7 +303,7 @@ public class ColorPanel extends JPanel
       JPanel panel = new JPanel();
       panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
 
-      JLabel defineSearchColorsLabel = new JLabel("Search colors");
+      JLabel defineSearchColorsLabel = new JLabel("Find colors");
 
       panel.add(defineSearchColorsLabel);
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 3457d51..ed61f2c 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -17,7 +17,7 @@
 </ul>
 <h2>13 Oct 2010</h2>
 <ul>
-<li>Added log panel preference to display search results in the detail panel.  When the preference is enabled and a search is performed, the matching rows are displayed in a table in the details panel.  Clicking on a row in that table selects the row in the main event table.</li>
+<li>Added log panel preference to display find results in the detail panel.  When the preference is enabled and a search is performed, the matching rows are displayed in a table in the details panel.  Clicking on a row in that table selects the row in the main event table.</li>
 </ul>
 <h2>22 Sep 2010</h2>
 <ul>
@@ -25,9 +25,9 @@
 </ul>
 <h2>15 Sep 2010</h2>
 <ul>
-<li>New feature: Clickable thumbnail bar on the left shows time delta to prior displayed event if the time delta is > 1 second (behaves similarly to the thumbnail bar on the right which shows colors and search matches, but represents the time delta between events).  A bigger delta is represented as a wider line.</li>
+<li>New feature: Clickable thumbnail bar on the left shows time delta to prior displayed event if the time delta is > 1 second (behaves similarly to the thumbnail bar on the right which shows colors and find matches, but represents the time delta between events).  A bigger delta is represented as a wider line.</li>
 <li>Updated table rendering logic when in line-wrap mode</li>
-<li>Updated row selection logic (goto/search) to make sure event is on the screen</li>
+<li>Updated row selection logic (goto/find) to make sure event is on the screen</li>
 <li>Capped the event time delta rendering in the table to a max of 50 pixels tall</li>
 </ul>
 <h2>13 Sep 2010</h2>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/34497133/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html b/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
index 79374fe..0f54454 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/tutorial.html
@@ -216,16 +216,16 @@ Example: to display only events which are greater than or equal to level INFO, u
 <tr><td>To display events occurring at 23:55:12 on the 19th of June (all events generated during that second, regardless of millisecond value)</td><td><b>TIMESTAMP == '2004/06/19 23:55:12'</b></td></tr>
 </table>
 
-<A NAME="search"><h3>Search</h3>
+<A NAME="search"><h3>Find</h3>
 <p>
-<b>How to search:</b></p>
+<b>How to find:</b></p>
 <ul>
-<li><b>Enter an expression</b> in the text field of the main Chainsaw toolbar (a log panel must be selected)</li>
-<li>Click the <b>down arrow icon</b> or press <b>F3</b> to search forward</li>
-<li>Click the <b>up arrow icon</b> or press <b>Shift+F3</b> to search backward</li>
+<li><b>Enter an expression</b> in the Find field</li>
+<li>Click the <b>down arrow icon</b> or press <b>F3</b> or <b>enter</b> to search forward from the currently selected row</li>
+<li>Click the <b>up arrow icon</b> or press <b>Shift+F3</b> to search backward from the currently selected row</li>
 <li>The first matching row becomes selected, with matching rows displayed with white text on a black background</li>
 <li>Subsequent forward or backward searches will navigate to the next match</li>
-<li>To <b>clear the search highlighting</b>, clear the text field and press <b>F3</b>)</li>
+<li>To <b>clear the find highlighting</b>, clear the text field and press <b>F3</b> or <b>enter</b></li>
 </ul>
 <p>
 <A NAME="display_filter"><h3>Display filters (refine focus)</h3>


[19/50] [abbrv] logging-chainsaw git commit: Added ability to create log file receiver configurations from log4j xml configuration fileappender entries

Posted by rg...@apache.org.
Added ability to create log file receiver configurations from log4j xml configuration fileappender entries

Parses the xml configuration and the patternLayout and date specifiers and creates LogFilePatternReceiver entries



Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/910dc454
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/910dc454
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/910dc454

Branch: refs/heads/master
Commit: 910dc45429c1503257655860e762dfaae2c963fb
Parents: e6f85a2
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Nov 5 08:26:33 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Nov 5 08:26:33 2010 +0000

----------------------------------------------------------------------
 .../chainsaw/LogFilePatternLayoutBuilder.java   | 118 ++++++++++++++++++-
 .../java/org/apache/log4j/chainsaw/LogUI.java   |  43 +++++++
 .../chainsaw/ReceiverConfigurationPanel.java    |  81 +++++++++++++
 .../log4j/chainsaw/help/release-notes.html      |   5 +
 4 files changed, 246 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/910dc454/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
index ccf1e7c..1249863 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
@@ -16,13 +16,23 @@
  */
 package org.apache.log4j.chainsaw;
 
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.FileAppender;
 import org.apache.log4j.helpers.OptionConverter;
 import org.apache.log4j.pattern.ClassNamePatternConverter;
+import org.apache.log4j.pattern.DatePatternConverter;
 import org.apache.log4j.pattern.FileLocationPatternConverter;
 import org.apache.log4j.pattern.FullLocationPatternConverter;
 import org.apache.log4j.pattern.LevelPatternConverter;
@@ -39,6 +49,14 @@ import org.apache.log4j.pattern.PropertiesPatternConverter;
 import org.apache.log4j.pattern.RelativeTimePatternConverter;
 import org.apache.log4j.pattern.SequenceNumberPatternConverter;
 import org.apache.log4j.pattern.ThreadPatternConverter;
+import org.apache.log4j.xml.Log4jEntityResolver;
+import org.apache.log4j.xml.SAXErrorHandler;
+import org.w3c.dom.Document;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
 
 public class LogFilePatternLayoutBuilder
 {
@@ -52,11 +70,39 @@ public class LogFilePatternLayoutBuilder
         return getFormatFromConverters(converters);
     }
 
+    public static String getTimeStampFormat(String patternLayout) {
+      int basicIndex = patternLayout.indexOf("%d");
+      if (basicIndex < 0) {
+        return null;
+      }
+
+      int index = patternLayout.indexOf("%d{");
+      //%d - default
+      if (index < 0) {
+        return "yyyy-MM-dd HH:mm:ss,SSS";
+      }
+
+      int length = patternLayout.substring(index).indexOf("}");
+      String timestampFormat = patternLayout.substring(index + "%d{".length(), index + length);
+      if (timestampFormat.equals("ABSOLUTE")) {
+        return "HH:mm:ss,SSS";
+      }
+      if (timestampFormat.equals("ISO8601")) {
+        return "yyyy-MM-dd HH:mm:ss,SSS";
+      }
+      if (timestampFormat.equals("DATE")) {
+        return "dd MMM yyyy HH:mm:ss,SSS";
+      }
+      return timestampFormat;
+    }
+  
     private static String getFormatFromConverters(List converters) {
         StringBuffer buffer = new StringBuffer();
         for (Iterator iter = converters.iterator();iter.hasNext();) {
             LoggingEventPatternConverter converter = (LoggingEventPatternConverter)iter.next();
-            if (converter instanceof MessagePatternConverter) {
+            if (converter instanceof DatePatternConverter) {
+              buffer.append("TIMESTAMP");
+            } else if (converter instanceof MessagePatternConverter) {
                 buffer.append("MESSAGE");
             } else if (converter instanceof LoggerPatternConverter) {
                 buffer.append("LOGGER");
@@ -98,4 +144,74 @@ public class LogFilePatternLayoutBuilder
         }
         return buffer.toString();
     }
+
+  public static Map getAppenderConfiguration(File file) throws IOException, ParserConfigurationException, SAXException {
+    InputStream stream = file.toURI().toURL().openStream();
+    Map result = new HashMap();
+    try {
+      InputSource src = new InputSource(stream);
+      src.setSystemId(file.toURI().toURL().toString());
+      DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+      DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new Log4jEntityResolver());
+      Document doc = docBuilder.parse(src);
+      NodeList appenders = doc.getElementsByTagName("appender");
+      for (int i = 0; i < appenders.getLength(); i++) {
+        Node appender = appenders.item(i);
+        NamedNodeMap appenderAttributes = appender.getAttributes();
+//        Class appenderClass = Class.forName(map.getNamedItem("class").getNodeValue());
+        Node appenderClass = appenderAttributes.getNamedItem("class");
+        try {
+          if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
+            //load the class or try to support custom subclasses that we don't have available in the classpath but end in 'FileAppender'
+            if (appenderClass.getNodeValue().toLowerCase().endsWith("fileappender") || FileAppender.class.isAssignableFrom(Class.forName(appenderClass.getNodeValue()))) {
+              String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
+              //subclass of FileAppender - add it
+              Map entry = new HashMap();
+              NodeList appenderChildren = appender.getChildNodes();
+              for (int j = 0; j < appenderChildren.getLength(); j++) {
+                Node appenderChild = appenderChildren.item(j);
+                if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
+                  Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
+                  if (fileNameNode != null && fileNameNode.getNodeValue().equals("file")) {
+                    Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
+                    if (fileValueNode != null) {
+                      entry.put("file", fileValueNode.getNodeValue());
+                    }
+                  }
+                }
+                if (appenderChild.getNodeName().equals("layout") && appenderChild.hasAttributes()) {
+                  NamedNodeMap layoutAttributes = appenderChild.getAttributes();
+                  Node layoutNode = layoutAttributes.getNamedItem("class");
+                  if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
+                    NodeList layoutChildren = appenderChild.getChildNodes();
+                    for (int k = 0; k < layoutChildren.getLength(); k++) {
+                      Node layoutChild = layoutChildren.item(k);
+                      if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
+                        Node layoutName = layoutChild.getAttributes().getNamedItem("name");
+                        if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equals("ConversionPattern")) {
+                          Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
+                          if (conversionValue != null) {
+                            entry.put("conversion", conversionValue.getNodeValue());
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+              result.put(appenderName, entry);
+            }
+          }
+        } catch (Exception e) {
+          e.printStackTrace();
+        }
+      }
+    } finally {
+      stream.close();
+    }
+    return result;
+  }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/910dc454/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index da000ca..e8bf684 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -84,6 +84,7 @@ import javax.swing.event.ChangeListener;
 import javax.swing.event.EventListenerList;
 import javax.swing.event.HyperlinkEvent;
 import javax.swing.event.HyperlinkListener;
+import javax.xml.parsers.ParserConfigurationException;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.AppenderSkeleton;
@@ -126,6 +127,7 @@ import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.RepositorySelector;
 import org.apache.log4j.xml.DOMConfigurator;
 import org.apache.log4j.xml.XMLDecoder;
+import org.xml.sax.SAXException;
 
 
 /**
@@ -1459,6 +1461,47 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
                 MessageCenter.getInstance().getLogger().info(
                   "An error occurred creating your Receiver");
               }
+            } else if (receiverConfigurationPanel.getModel().isLog4jConfig()) {
+              File log4jConfigFile = receiverConfigurationPanel.getModel().getLog4jConfigFile();
+              if (log4jConfigFile != null) {
+                try {
+                  Map entries = LogFilePatternLayoutBuilder.getAppenderConfiguration(log4jConfigFile);
+                  for (Iterator iter = entries.entrySet().iterator();iter.hasNext();) {
+                    try {
+                      Map.Entry entry = (Map.Entry)iter.next();
+                      String name = (String) entry.getKey();
+                      Map values = (Map) entry.getValue();
+                      //values: conversion, file
+                      String conversionPattern = values.get("conversion").toString();
+                      File file = new File(values.get("file").toString());
+                      URL fileURL = file.toURI().toURL();
+                      String timestampFormat = LogFilePatternLayoutBuilder.getTimeStampFormat(conversionPattern);
+                      String receiverPattern = LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(conversionPattern);
+                      VFSLogFilePatternReceiver fileReceiver = new VFSLogFilePatternReceiver();
+                      fileReceiver.setName(name);
+                      fileReceiver.setAutoReconnect(true);
+                      fileReceiver.setContainer(LogUI.this);
+                      fileReceiver.setAppendNonMatches(true);
+                      fileReceiver.setFileURL(fileURL.toURI().toString());
+                      fileReceiver.setTailing(true);
+                      fileReceiver.setLogFormat(receiverPattern);
+                      fileReceiver.setTimestampFormat(timestampFormat);
+                      fileReceiver.setThreshold(Level.TRACE);
+                      pluginRegistry.addPlugin(fileReceiver);
+                      fileReceiver.activateOptions();
+                      receiversPanel.updateReceiverTreeInDispatchThread();
+                    } catch (URISyntaxException e1) {
+                      e1.printStackTrace();
+                    }
+                  }
+                } catch (IOException e1) {
+                  e1.printStackTrace();
+                } catch (ParserConfigurationException e1) {
+                  e1.printStackTrace();
+                } catch (SAXException e1) {
+                  e1.printStackTrace();
+                }
+              }
             } else if (receiverConfigurationPanel.getModel().isLoadConfig()) {
                   configURL = receiverConfigurationPanel.getModel().getConfigToLoad();
             } else if (receiverConfigurationPanel.getModel().isLogFileReceiverConfig()) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/910dc454/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index 1f94570..a6c3715 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -30,6 +30,7 @@ import java.awt.event.FocusEvent;
 import java.awt.event.FocusListener;
 import java.io.File;
 import java.net.MalformedURLException;
+import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 
@@ -74,6 +75,10 @@ class ReceiverConfigurationPanel extends JPanel {
     private DefaultComboBoxModel networkReceiverClassNameComboBoxModel;
     private DefaultComboBoxModel networkReceiverPortComboBoxModel;
 
+    //log4j config receiver widgets
+    private JButton browseLog4jConfigButton;
+    private JTextField log4jConfigURLTextField;
+
     //logfile receiver widgets
     private JButton browseLogFileButton;
     private JComboBox logFileFormatTypeComboBox;
@@ -97,6 +102,7 @@ class ReceiverConfigurationPanel extends JPanel {
     private JButton cancelButton;
 
     //radiobutton widgets
+    private JRadioButton log4jConfigReceiverRadioButton;
     private JRadioButton logFileReceiverRadioButton;
     private JRadioButton networkReceiverRadioButton;
     private JRadioButton useExistingConfigurationRadioButton;
@@ -106,6 +112,7 @@ class ReceiverConfigurationPanel extends JPanel {
 
     private final JPanel networkReceiverPanel = buildNetworkReceiverPanel();
     private final JPanel logFileReceiverPanel = buildLogFileReceiverPanel();
+    private final JPanel log4jConfigReceiverPanel = buildLog4jConfigReceiverPanel();
     private final JPanel useExistingConfigurationPanel = buildUseExistingConfigurationPanel();
     private final JPanel dontWarnAndOKPanel = buildDontWarnAndOKPanel();
     private final JPanel bottomDescriptionPanel = buildBottomDescriptionPanel();
@@ -140,6 +147,14 @@ class ReceiverConfigurationPanel extends JPanel {
         c.gridx = 0;
         c.gridy = yPos++;
         c.fill = GridBagConstraints.HORIZONTAL;
+        log4jConfigReceiverRadioButton = new JRadioButton(" Use log4j.xml fileappender configuration ");
+        buttonGroup.add(log4jConfigReceiverRadioButton);
+        add(log4jConfigReceiverRadioButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = yPos++;
+        c.fill = GridBagConstraints.HORIZONTAL;
         networkReceiverRadioButton = new JRadioButton(" Receive events from the network ");
         buttonGroup.add(networkReceiverRadioButton);
         add(networkReceiverRadioButton, c);
@@ -185,6 +200,7 @@ class ReceiverConfigurationPanel extends JPanel {
             };
 
         logFileReceiverRadioButton.addActionListener(al);
+        log4jConfigReceiverRadioButton.addActionListener(al);
         networkReceiverRadioButton.addActionListener(al);
         useExistingConfigurationRadioButton.addActionListener(al);
 
@@ -332,6 +348,52 @@ class ReceiverConfigurationPanel extends JPanel {
         return panel;
     }
 
+    private JPanel buildLog4jConfigReceiverPanel() {
+        log4jConfigURLTextField = new JTextField();
+        browseLog4jConfigButton = new JButton(new AbstractAction(" Open File... ") {
+                    public void actionPerformed(ActionEvent e) {
+                        try {
+
+                            URL url = browseConfig();
+
+                            if (url != null) {
+                                log4jConfigURLTextField.setText(url.toExternalForm());
+                            }
+                        } catch (Exception ex) {
+                            logger.error(
+                                "Error browsing for log4j config file", ex);
+                        }
+                    }
+                });
+
+        browseLog4jConfigButton.setToolTipText(
+            "Shows a File Open dialog to allow you to find a log4j configuration file");
+        JPanel panel = new JPanel(new GridBagLayout());
+        GridBagConstraints c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 0;
+        c.gridwidth = 2;
+        c.anchor = GridBagConstraints.LINE_START;
+        c.insets = new Insets(0, 0, 5, 0);
+        panel.add(browseLog4jConfigButton, c);
+
+        c = new GridBagConstraints();
+        c.gridx = 0;
+        c.gridy = 1;
+        c.insets = new Insets(0, 5, 0, 5);
+        panel.add(new JLabel(" log4j configuration file URL "), c);
+
+        c = new GridBagConstraints();
+        c.gridx = 1;
+        c.gridy = 1;
+        c.weightx = 0.5;
+        c.fill = GridBagConstraints.HORIZONTAL;
+        panel.add(log4jConfigURLTextField, c);
+
+
+        return panel;
+    }
+
     private JPanel buildLogFileReceiverPanel() {
         JPanel panel = new JPanel(new GridBagLayout());
         browseLogFileButton = new JButton(new AbstractAction(" Open File... ") {
@@ -566,6 +628,9 @@ class ReceiverConfigurationPanel extends JPanel {
         if (component == logFileReceiverRadioButton) {
             lowerPanel.add(logFileReceiverPanel, BorderLayout.NORTH);
         }
+        if (component == log4jConfigReceiverRadioButton) {
+            lowerPanel.add(log4jConfigReceiverPanel, BorderLayout.NORTH);
+        }
         lowerPanel.revalidate();
         lowerPanel.repaint();
     }
@@ -683,6 +748,10 @@ class ReceiverConfigurationPanel extends JPanel {
             return !cancelled && logFileReceiverRadioButton.isSelected();
         }
 
+        boolean isLog4jConfig() {
+            return !cancelled && log4jConfigReceiverRadioButton.isSelected();
+        }
+
         URL getConfigToLoad() {
 
             try
@@ -767,5 +836,17 @@ class ReceiverConfigurationPanel extends JPanel {
         public boolean isCancelled() {
           return cancelled;
         }
+
+    public File getLog4jConfigFile() {
+      try {
+        URL newConfigurationURL = new URL(log4jConfigURLTextField.getText());
+        return new File(newConfigurationURL.toURI());
+      } catch (URISyntaxException e) {
+        e.printStackTrace();
+      } catch (MalformedURLException e) {
+        e.printStackTrace();
+      }
+      return null;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/910dc454/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 803563d..f267cea 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,6 +10,11 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
+<h2>5 Nov 2010</h2>
+<ul>
+<li>Added ability to create log file receiver configurations from log4j xml configuration fileappender entries</li>
+<li>Added ability to save the receiver configuration from the receiver modification panel</li>
+</ul>
 <h2>4 Nov 2010</h2>
 <ul>
 <li>Added ability to save the receiver configuration defined through the initial receiver configuration panel with a user-specified file path and name</li>


[41/50] [abbrv] logging-chainsaw git commit: Bug 53771 - Fix Java 7 Gump-reported compilation failure

Posted by rg...@apache.org.
Bug 53771 - Fix Java 7 Gump-reported compilation failure


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/ef6872d3
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/ef6872d3
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/ef6872d3

Branch: refs/heads/master
Commit: ef6872d3875eab266a9a5e51ebfb775c27633fb2
Parents: d421472
Author: Scott Deboy <sd...@apache.org>
Authored: Fri Aug 24 05:38:48 2012 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri Aug 24 05:38:48 2012 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/messages/MessageCenter.java    | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/ef6872d3/src/main/java/org/apache/log4j/chainsaw/messages/MessageCenter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/messages/MessageCenter.java b/src/main/java/org/apache/log4j/chainsaw/messages/MessageCenter.java
index 88deec3..3ca0c20 100644
--- a/src/main/java/org/apache/log4j/chainsaw/messages/MessageCenter.java
+++ b/src/main/java/org/apache/log4j/chainsaw/messages/MessageCenter.java
@@ -224,8 +224,7 @@ public class MessageCenter {
    * 
    * @author Paul Smith <ps...@apache.org>
    */
-  private static class LayoutListCellRenderer extends DefaultListCellRenderer
-    implements ListCellRenderer {
+  private static class LayoutListCellRenderer extends DefaultListCellRenderer {
     private Layout layout;
 
     /**


[46/50] [abbrv] logging-chainsaw git commit: Enable tailing by default when a fileappender multicastdns advertisement is processed

Posted by rg...@apache.org.
Enable tailing by default when a fileappender multicastdns advertisement is processed


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/c85387ff
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/c85387ff
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/c85387ff

Branch: refs/heads/master
Commit: c85387ff8c301188c9d348e22f1128ea94a0dc01
Parents: e041d48
Author: Scott Deboy <sd...@apache.org>
Authored: Fri May 10 15:24:53 2013 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri May 10 15:24:53 2013 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java     | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/c85387ff/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
index 9fedd69..89574d2 100644
--- a/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
+++ b/src/main/java/org/apache/log4j/chainsaw/zeroconf/ZeroConfPlugin.java
@@ -531,6 +531,7 @@ public class ZeroConfPlugin extends GUIPluginSkeleton {
                 receiver.setLogFormat(LogFilePatternLayoutBuilder.getLogFormatFromPatternLayout(info.getPropertyString("format")));
                 receiver.setTimestampFormat(LogFilePatternLayoutBuilder.getTimeStampFormat(info.getPropertyString("format")));
                 receiver.setName(name + "-receiver");
+                receiver.setTailing(true);
                 return receiver;
             }
         }


[05/50] [abbrv] logging-chainsaw git commit: replaced alt and ctrl keyboard masks where appropriate with Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) calls

Posted by rg...@apache.org.
replaced alt and ctrl keyboard masks where appropriate with Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()) calls

Added cmd-F and cmd-R to set focus in find and refine focus comboboxes, respectively, and cmd-shift-F and cmd-shift-R to clear those fields

Added keyboard shortcuts to release notes.




Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/622fc259
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/622fc259
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/622fc259

Branch: refs/heads/master
Commit: 622fc259013d2af1214e88fcf7c280276a09edb9
Parents: 5343147
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Oct 23 06:27:25 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Oct 23 06:27:25 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/ChainsawToolBarAndMenus.java | 25 +++----
 .../org/apache/log4j/chainsaw/FileMenu.java     |  6 +-
 .../apache/log4j/chainsaw/FileSaveAction.java   |  4 +-
 .../org/apache/log4j/chainsaw/LogPanel.java     | 71 ++++++++++++++++----
 .../java/org/apache/log4j/chainsaw/LogUI.java   |  6 +-
 .../org/apache/log4j/chainsaw/WelcomePanel.html | 52 ++++++++------
 .../log4j/chainsaw/help/release-notes.html      | 27 ++++----
 7 files changed, 123 insertions(+), 68 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
index 51c8a79..9f5165a 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawToolBarAndMenus.java
@@ -20,6 +20,7 @@ package org.apache.log4j.chainsaw;
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.Insets;
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.InputEvent;
@@ -213,7 +214,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
     action.putValue(
       Action.ACCELERATOR_KEY,
-      KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK));
+      KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
     action.putValue(
       Action.SMALL_ICON, new ImageIcon(ChainsawIcons.WINDOW_ICON));
 
@@ -238,7 +239,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
      action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_B));
      action.putValue(
        Action.ACCELERATOR_KEY,
-       KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK));
+       KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
      action.putValue(
        Action.SMALL_ICON, new ImageIcon(ChainsawIcons.SCROLL_TO_BOTTOM));
 
@@ -258,7 +259,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
       action.putValue(Action.SHORT_DESCRIPTION, "Scroll to top");
       action.putValue("enabled", Boolean.TRUE);
       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
-      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A,  InputEvent.CTRL_MASK));
+      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_A,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
 
       return action;
     }
@@ -312,7 +313,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
       action.putValue(Action.SHORT_DESCRIPTION, "Toggle marker for selected row");
       action.putValue("enabled", Boolean.TRUE);
       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
-      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  InputEvent.CTRL_MASK));
+      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
 
       return action;
     }
@@ -330,7 +331,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
       action.putValue(Action.SHORT_DESCRIPTION, "Removes all markers");
       action.putValue("enabled", Boolean.TRUE);
       action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_R));
-      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK));
+      action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F2,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK));
 
       return action;
     }
@@ -376,7 +377,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_C));
     action.putValue(
       Action.ACCELERATOR_KEY,
-      KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.CTRL_MASK));
+      KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
     action.putValue(
       Action.SHORT_DESCRIPTION, "Removes all the events from the current view");
     action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.DELETE));
@@ -696,7 +697,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
     action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_D));
     action.putValue(
       Action.ACCELERATOR_KEY,
-      KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_MASK));
+      KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
     action.putValue(Action.SHORT_DESCRIPTION, "Hides/Shows the Detail Pane");
     action.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.INFO));
 
@@ -753,14 +754,14 @@ class ChainsawToolBarAndMenus implements ChangeListener {
     detailPaneButton.getActionMap().put(
       toggleDetailPaneAction.getValue(Action.NAME), toggleDetailPaneAction);
     detailPaneButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-      KeyStroke.getKeyStroke(KeyEvent.VK_D, InputEvent.ALT_MASK),
+      KeyStroke.getKeyStroke(KeyEvent.VK_D, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
       toggleDetailPaneAction.getValue(Action.NAME));
 
     logTreePaneButton.setAction(toggleLogTreeAction);
     logTreePaneButton.getActionMap().put(
       toggleLogTreeAction.getValue(Action.NAME), toggleLogTreeAction);
     logTreePaneButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-      KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK),
+      KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
       toggleLogTreeAction.getValue(Action.NAME));
     logTreePaneButton.setText(null);
 
@@ -768,7 +769,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
     scrollToBottomButton.getActionMap().put(
       toggleScrollToBottomAction.getValue(Action.NAME), toggleScrollToBottomAction);
     scrollToBottomButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-      KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK),
+      KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
       toggleScrollToBottomAction.getValue(Action.NAME));
     scrollToBottomButton.setText(null);
 
@@ -894,7 +895,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
         action.putValue(Action.SHORT_DESCRIPTION, "Searches for the next colorized event from the current location");
         action.putValue("enabled", Boolean.TRUE);
         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_N));
-        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK));
+        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_N, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
 
       return action;
     }
@@ -913,7 +914,7 @@ class ChainsawToolBarAndMenus implements ChangeListener {
         action.putValue(Action.SHORT_DESCRIPTION, "Searches for the next colorized event from the current location");
         action.putValue("enabled", Boolean.TRUE);
         action.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_P));
-        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK));
+        action.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_P, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
 
       return action;
     }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/FileMenu.java b/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
index 24abde8..7420251 100644
--- a/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
+++ b/src/main/java/org/apache/log4j/chainsaw/FileMenu.java
@@ -21,8 +21,8 @@
 */
 package org.apache.log4j.chainsaw;
 
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
-import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.net.URL;
 import java.util.Iterator;
@@ -75,7 +75,7 @@ class FileMenu extends JMenu {
 
       loadLog4JAction.putValue(
         Action.ACCELERATOR_KEY,
-        KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_MASK));
+        KeyStroke.getKeyStroke(KeyEvent.VK_O, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
       loadLog4JAction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_L));
       loadLog4JAction.putValue(Action.SHORT_DESCRIPTION, "Loads events from a local XMLLayout-formatted file ");
       loadLog4JAction.putValue(Action.SMALL_ICON, new ImageIcon(ChainsawIcons.FILE_OPEN));
@@ -112,7 +112,7 @@ class FileMenu extends JMenu {
 
     exitAction.putValue(
       Action.ACCELERATOR_KEY,
-      KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK));
+      KeyStroke.getKeyStroke(KeyEvent.VK_X, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
     exitAction.putValue(Action.SHORT_DESCRIPTION, "Exits the Application");
     exitAction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
     exitAction.putValue(Action.NAME, "Exit");

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java b/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
index 9357fb7..9fe7a55 100644
--- a/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
+++ b/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
@@ -17,8 +17,8 @@
 
 package org.apache.log4j.chainsaw;
 
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
-import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
@@ -66,7 +66,7 @@ class FileSaveAction extends AbstractAction {
 
     putValue(
       Action.ACCELERATOR_KEY,
-      KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
+      KeyStroke.getKeyStroke(KeyEvent.VK_S, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
     putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_S));
     putValue(
       Action.SHORT_DESCRIPTION, "Saves displayed events for the current tab");

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index e2d388a..ea80971 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -706,19 +706,19 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     //we've mapped f2, shift f2 and ctrl-f2 to marker-related actions, unmap them from the table
     table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("F2"), "none");
     table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.SHIFT_MASK), "none");
-    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK), "none");
-    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "none");
+    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
+    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK), "none");
 
     //we're also mapping ctrl-a to scroll-to-top, unmap from the table
-    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK), "none");
+    table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
         
     searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("F2"), "none");
     searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.SHIFT_MASK), "none");
-    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK), "none");
-    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, InputEvent.CTRL_MASK | InputEvent.SHIFT_MASK), "none");
+    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
+    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_F2, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask() | InputEvent.SHIFT_MASK), "none");
 
     //we're also mapping ctrl-a to scroll-to-top, unmap from the table
-    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK), "none");
+    searchTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_A, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()), "none");
 
     //add a listener to update the 'refine focus'
     tableModel.addNewKeyListener(new NewKeyListener() {
@@ -1099,8 +1099,6 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     final JLabel filterLabel = new JLabel("Refine focus on: ");
     filterLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD));
-    filterLabel.setDisplayedMnemonic('k');
-    filterLabel.setLabelFor(filterCombo);
 
     upperPanel.add(filterLabel);
     upperPanel.add(Box.createHorizontalStrut(3));
@@ -1129,10 +1127,8 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     //add some space between refine focus and search sections of the panel
     upperPanel.add(Box.createHorizontalStrut(25));
 
-    final JLabel findLabel = new JLabel("Search: ");
+    final JLabel findLabel = new JLabel("Find: ");
     findLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD));
-    findLabel.setDisplayedMnemonic('j');
-    findLabel.setLabelFor(findCombo);
 
     upperPanel.add(findLabel);
     upperPanel.add(Box.createHorizontalStrut(3));
@@ -1184,6 +1180,53 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     );
     upperPanel.add(removeFindButton);
 
+    //define search and refine focus selection and clear actions
+    Action findFocusAction = new AbstractAction() {
+      public void actionPerformed(ActionEvent actionEvent) {
+        findCombo.requestFocus();
+      }
+    };
+
+    Action filterFocusAction = new AbstractAction() {
+      public void actionPerformed(ActionEvent actionEvent) {
+        filterCombo.requestFocus();
+      }
+    };
+
+    Action findClearAction = new AbstractAction() {
+      public void actionPerformed(ActionEvent actionEvent) {
+        findCombo.setSelectedIndex(-1);
+        findNext();
+      }
+    };
+
+    Action filterClearAction = new AbstractAction() {
+      public void actionPerformed(ActionEvent actionEvent) {
+        setRefineFocusText("");
+        filterCombo.refilter();
+      }
+    };
+
+    //now add them to the action and input maps for the logpanel
+        KeyStroke ksFindFocus =
+      KeyStroke.getKeyStroke(KeyEvent.VK_F, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+    KeyStroke ksFilterFocus =
+      KeyStroke.getKeyStroke(KeyEvent.VK_R, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+        KeyStroke ksFindClear =
+      KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.SHIFT_MASK |Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+    KeyStroke ksFilterClear =
+      KeyStroke.getKeyStroke(KeyEvent.VK_R,  InputEvent.SHIFT_MASK | Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
+
+    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFindFocus, "FindFocus");
+    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFilterFocus, "FilterFocus");
+    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFindClear, "FindClear");
+    getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ksFilterClear, "FilterClear");
+
+    getActionMap().put("FindFocus", findFocusAction);
+    getActionMap().put("FilterFocus", filterFocusAction);
+    getActionMap().put("FindClear", findClearAction);
+    getActionMap().put("FilterClear", filterClearAction);
+
     /*
      * Detail pane definition
      */
@@ -2767,7 +2810,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       dockToggleLogTreeAction.putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_T));
       dockToggleLogTreeAction.putValue(
         Action.ACCELERATOR_KEY,
-        KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.ALT_MASK));
+        KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
       dockToggleLogTreeAction.putValue(
         Action.SMALL_ICON, new ImageIcon(ChainsawIcons.WINDOW_ICON));
 
@@ -2797,7 +2840,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
 
     final SmallButton dockClearButton = new SmallButton(undockedClearAction);
     dockClearButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-      KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.CTRL_MASK),
+      KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
       undockedClearAction.getValue(Action.NAME));
     dockClearButton.getActionMap().put(
       undockedClearAction.getValue(Action.NAME), undockedClearAction);
@@ -2827,7 +2870,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
       });
 
       toggleScrollToBottomButton.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-  	      KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.CTRL_MASK),
+  	      KeyStroke.getKeyStroke(KeyEvent.VK_B, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
   	      dockToggleScrollToBottomAction.getValue(Action.NAME));
   	    toggleScrollToBottomButton.getActionMap().put(
   	      dockToggleScrollToBottomAction.getValue(Action.NAME), dockToggleScrollToBottomAction);

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index 30a0abf..e85a974 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -798,11 +798,11 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
     });
 
     KeyStroke ksRight =
-      KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Event.CTRL_MASK);
+      KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
     KeyStroke ksLeft =
-      KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Event.CTRL_MASK);
+      KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
     KeyStroke ksGotoLine =
-      KeyStroke.getKeyStroke(KeyEvent.VK_G,  Event.CTRL_MASK);
+      KeyStroke.getKeyStroke(KeyEvent.VK_G,  Toolkit.getDefaultToolkit().getMenuShortcutKeyMask());
 
     getTabbedPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
       ksRight, "MoveRight");

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html b/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
index 96d371a..eafcb52 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/WelcomePanel.html
@@ -22,7 +22,7 @@
 </HEAD>
 
 <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?">
-<p><a name="TheTop"></a><table border="0" cellpadding="0" cellspacing="0" width="100%">
+<a name="TheTop"></a><table border="0" cellpadding="0" cellspacing="0" width="100%">
 	<tr valign="top">
 		<td><b><font size="+2">Chainsaw v2</font></b> - brought to you by the Log4j Dev team</td>
 		<!--<td rowspan="2" align="right"><img align="top" src="logo.jpg" border="0" alt="Log4j Logo"></td>-->
@@ -31,7 +31,7 @@
     <tr>
         <td><b>Release notes and tutorial are available from the Help menu</b></td>
     </tr>
-</table></p>
+</table>
 <!-- Removing this until we can work out why the Anchor tags don't work in Swing... -->
 <!--
 <table border="1" cellspacing="2" cellpadding="2">
@@ -44,7 +44,7 @@
 <p><table border="0" cellspacing="2" cellpadding="2" >
 <tr><td colspan="6" class="TableTitle" bgcolor="#000089"><font color="white">Hot Keys</font></td></tr>
 <tr valign="top">
-	<td nowrap class="HotKey">CTRL-LEFT</td>
+	<td nowrap class="HotKey">CMD-LEFT</td>
 	<td width="50" align="center">-</td>
 	<td>Activate a tab to the left</td>
     <td nowrap class="HotKey">CTRL-RIGHT</td>
@@ -60,18 +60,18 @@
     <td>Find previous</td>
 </tr>
 <tr valign="top">
-    <td nowrap class="HotKey">CTRL-A</td>
+    <td nowrap class="HotKey">CMD-A</td>
     <td width="50" align="center">-</td>
     <td>Scroll to top</td>
-    <td nowrap class="HotKey">CTRL-B</td>
+    <td nowrap class="HotKey">CMD-B</td>
     <td width="50" align="center">-</td>
     <td>Scroll to bottom</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
-    <td nowrap class="HotKey">CTRL-F2 or double-click on a row</td>
+    <td nowrap class="HotKey">CMD-F2 or double-click on a row</td>
     <td width="50" align="center">-</td>
     <td>Define a 'marker' (add a note to a row)</td>
-    <td nowrap class="HotKey">CTRL-SHIFT-F2</td>
+    <td nowrap class="HotKey">CMD-SHIFT-F2</td>
     <td width="50" align="center">-</td>
     <td>Clear all markers</td>
 </tr>
@@ -84,34 +84,42 @@
     <td>Find previous marker</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
-    <td nowrap class="HotKey">ALT-J</td>
+    <td nowrap class="HotKey">CMD-F</td>
     <td width="50" align="center">-</td>
-    <td>Set focus in 'search' field</td>
-    <td nowrap class="HotKey">ALT-K</td>
+    <td>Set focus in 'find' field</td>
+    <td nowrap class="HotKey">CMD-R</td>
     <td width="50" align="center">-</td>
     <td>Set focus in 'refine focus' field</td>
 </tr>
+<tr valign="top" bgcolor="#EEEEEE">
+    <td nowrap class="HotKey">CMD--SHIFT-F</td>
+    <td width="50" align="center">-</td>
+    <td>Clear 'find' field</td>
+    <td nowrap class="HotKey">CMD-SHIFT-R</td>
+    <td width="50" align="center">-</td>
+    <td>Clear 'refine focus' field</td>
+</tr>
 <tr valign="top" >
-	<td nowrap class="HotKey">CTRL-S</td>
+	<td nowrap class="HotKey">CMD-S</td>
 	<td width="50" align="center">-</td>
 	<td>Save displayed events</td>
-    <td nowrap class="HotKey">CTRL-O</td>
+    <td nowrap class="HotKey">CMD-O</td>
     <td width="50" align="center">-</td>
     <td>Load file of XML events</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
-    <td nowrap class="HotKey">ALT-C or CTRL-BACKSPACE</td>
+    <td nowrap class="HotKey">CMD-BACKSPACE</td>
     <td width="50" align="center">-</td>
     <td>Purges current panels events</td>
-	<td nowrap class="HotKey">ALT-P or F12</td>
+	<td nowrap class="HotKey">F12</td>
 	<td width="50" align="center">-</td>
 	<td>Pause display</td>
 </tr>
 <tr valign="top">
-	<td nowrap class="HotKey">ALT-D</td>
+	<td nowrap class="HotKey">CMD-D</td>
 	<td width="50" align="center">-</td>
 	<td>Show/Hide the Detail pane</td>
-	<td nowrap class="HotKey">ALT-T</td>
+	<td nowrap class="HotKey">CMD-T</td>
 	<td width="50" align="center">-</td>
 	<td>Show/Hide the Logger Tree pane</td>
 </tr>
@@ -124,20 +132,20 @@
     <td>Show Receivers Dialog</td>
 </tr>
 <tr valign="top">
-    <td nowrap class="HotKey">CTRL-N</td>
+    <td nowrap class="HotKey">CMD-N</td>
     <td width="50" align="center">-</td>
     <td>Go to next colored row</td>
-    <td nowrap class="HotKey">CTRL-P</td>
+    <td nowrap class="HotKey">CMD-P</td>
     <td width="50" align="center">-</td>
     <td>Go to previous colored row</td>
 </tr>
 <tr valign="top" bgcolor="#EEEEEE">
-    <td nowrap class="HotKey">CTRL-G</td>
+    <td nowrap class="HotKey">CMD-G</td>
     <td width="50" align="center">-</td>
     <td>Go to line</td>
-	<td nowrap class="HotKey">ALT-X</td>
-	<td width="50" align="center">-</td>
-	<td>Exits the Application</td>
+	<td></td>
+	<td></td>
+	<td></td>
 </tr>
 </table></P>
 <!--<p><a href="#TheTop">Back to top</a></p>-->

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/622fc259/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index bbdc8c6..3457d51 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -10,14 +10,19 @@
 <b>NOTE:</b> The mechanism and format used to persist settings in Chainsaw is subject to change.  If you are experiencing problems displaying events in Chainsaw, please delete everything in the $user.dir/.chainsaw directory and restart Chainsaw.
 <br>
 <h1>2.1</h1>
-<h2>20 Sep 2010</h2>
+<h2>22 Oct 2010</h2>
 <ul>
-<li>Changed 'Wrap message field' preference default to true</li>
+<li>Updated keyboard shortcuts to use system-specific option (Apple command key, Windows control key)</li>
+<li>Adding new find and refine-focus key accelerators (Option-F focuses on Find field, option-R focuses on refine focus field</li>
 </ul>
 <h2>13 Oct 2010</h2>
 <ul>
 <li>Added log panel preference to display search results in the detail panel.  When the preference is enabled and a search is performed, the matching rows are displayed in a table in the details panel.  Clicking on a row in that table selects the row in the main event table.</li>
 </ul>
+<h2>22 Sep 2010</h2>
+<ul>
+<li>Changed 'Wrap message field' preference default to true</li>
+</ul>
 <h2>15 Sep 2010</h2>
 <ul>
 <li>New feature: Clickable thumbnail bar on the left shows time delta to prior displayed event if the time delta is > 1 second (behaves similarly to the thumbnail bar on the right which shows colors and search matches, but represents the time delta between events).  A bigger delta is represented as a wider line.</li>
@@ -72,7 +77,7 @@
 </ul>
 <h2>13 Jun 2010</h2>
 <ul>
-<li>When mouse is moved into the thumbnail bar, event details for the closest event w/a color rule or search match is displayed as a tooltip (enabled by default, configurable via Tab Preferences dialog, Visuals section).</li>
+<li>When mouse is moved into the thumbnail bar, event details for the closest event w/a color rule or find match is displayed as a tooltip (enabled by default, configurable via Tab Preferences dialog, Visuals section).</li>
 <li>If the 'You have no Receivers defined' dialog is displayed, a configuration URL is provided and the 'don't show me this again' checkbox is selected, the provided configuration URL is set as the Auto Config URL in application-wide preferences and used from then on when Chainsaw starts.</li>
 <li>Added ability to ignore a (possibly compound) expression, similar to ignoring loggers (available in the logger tree below hidden loggers).  Ignored expression is persisted on a per-tab basis.</li>
 </ul>
@@ -103,11 +108,11 @@
 </ul>
 <h2>11 May 2010</h2>
 <ul>
-<li>Added search and alternating row color global preferences (updated from color settings window)</li>
+<li>Added find and alternating row color global preferences (updated from color settings window)</li>
 </ul>
 <h2>9 May 2010</h2>
 <ul>
-<li>Added preference to display matching search text in the table as bold (on by default)</li>
+<li>Added preference to display matching find text in the table as bold (on by default)</li>
 </ul>
 <h2>2 May 2010</h2>
 <ul>
@@ -119,13 +124,13 @@
 </ul>
 <h2>7 Apr 2010</h2>
 <ul>
-<li>Forward and backward search, as well as forward and backward next-color search now wrap.</li>
-<li>Added display of matching search count in status bar.</li>
+<li>Forward and backward find, as well as forward and backward next-color find now wrap.</li>
+<li>Added display of matching find count in status bar.</li>
 </ul>
 <h2>6 Apr 2010</h2>
 <ul>
 <li>Added default color rule support (ability to assign a tab's color rules as the default color rules for new tabs).  Default color rules can be applied to pre-existing tabs via the 'apply a tabs colors' drop down box in the color rule dialog.</li>
-<li>Pressing enter in the search box now initiates a search.</li>
+<li>Pressing enter in the find box now initiates a find.</li>
 <li>Updated thumbnail rendering logic to display warnings, errors, fatal events and events with markers more prominently than other events.</li>
 </ul>
 <h2>3 Apr 2010</h2>
@@ -146,7 +151,7 @@ just creates a text file containing the xml events.
 <h2>1 Apr 2010</h2>
 <ul>
 <li>Updated thumbnail bar to display all events with a defined color (will include the default color rules for marker, warning, error & fatal events).</li>
-<li>Added search matches to thumbnail bar (will display black in the left half of the row if the row matches the search expression).</li>
+<li>Added find matches to thumbnail bar (will display black in the left half of the row if the row matches the find expression).</li>
 <li>Added ctrl-n to go to next colorized event, ctrl-p to go to previous colorized event.</li>
 </ul>
 <h2>27 Mar 2010</h2>
@@ -172,8 +177,6 @@ Changed 'default' detail pane layout to hide some fields, added 'full' detail pa
 <li>
 New color rule: any row with a value in the 'log4j.marker' field will display as light green
 </li>
-<li>
-Added keyboard mnemonics to search field (alt-j) and refine focus field (alt-k), added shortcuts to Welcome page</li>
 </ul>
 <h2>16 Mar 2010</h2>
 <ul>
@@ -209,7 +212,7 @@ LogPanel context menu now provides 'Show times relative to this row' and 'Hide r
 <h2>22 Feb 2010</h2>
 <ul>
 <li>Implemented marker support (ability to add notes to rows).  Double click a row to toggle on or off a default note, or click in a row to define a custom note.  Navigate between markers with F2/Shift F2.
-    If you want to use these markers to colorize or build custom search expressions, use the column key PROP.log4j.marker.
+    If you want to use these markers to colorize or build custom find expressions, use the column key PROP.log4j.marker.
     Markers are saved and reloaded through the file-save as and file-load log4j file menus.
 </li>
 <li>Auto-configuration URL field now remembers the 10 most recent configuration files and provides a 'browse' button to load a configuration file without typing the URL.


[22/50] [abbrv] logging-chainsaw git commit: Re-add listener removed in last commit

Posted by rg...@apache.org.
Re-add listener removed in last commit


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/b108e6a0
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/b108e6a0
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/b108e6a0

Branch: refs/heads/master
Commit: b108e6a0d0ed352186e69b822e27757a4456d10e
Parents: 9f01847
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Nov 6 23:48:15 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Nov 6 23:48:15 2010 +0000

----------------------------------------------------------------------
 src/main/java/org/apache/log4j/chainsaw/LogPanel.java | 10 ++++++++++
 1 file changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/b108e6a0/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 70d54da..b7a376f 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -366,6 +366,16 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
     undockedFrame.setSize(new Dimension(1024, 768));
     undockedFrame.pack();
 
+    preferenceModel.addPropertyChangeListener(
+      "scrollToBottom",
+      new PropertyChangeListener() {
+        public void propertyChange(PropertyChangeEvent evt) {
+          boolean value = ((Boolean) evt.getNewValue()).booleanValue();
+          if (value) {
+            scrollToBottom();
+          }
+        }
+      });
     /*
      * Menus on which the preferencemodels rely
      */


[03/50] [abbrv] logging-chainsaw git commit: Table rendering update (font fix, label icon for 'basic' mode)

Posted by rg...@apache.org.
Table rendering update (font fix, label icon for 'basic' mode)


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/0dcec147
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/0dcec147
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/0dcec147

Branch: refs/heads/master
Commit: 0dcec1476e0a8e876ef8fe271110075564fd0f20
Parents: 66805db
Author: Scott Deboy <sd...@apache.org>
Authored: Sat Oct 23 04:18:10 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sat Oct 23 04:18:10 2010 +0000

----------------------------------------------------------------------
 .../log4j/chainsaw/TableColorizingRenderer.java | 22 +++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/0dcec147/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index 33d74d1..37c2b7e 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -197,6 +197,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         return rendererComponent;
       }
       basicComponent = (JLabel)rendererComponent;
+      basicComponent.setFont(levelTextPane.getFont());
       setBasicComponentBorder(basicComponent, isSelected, table, col);
     }
     long delta = 0;
@@ -382,6 +383,23 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
         textPaneContainer.add(textPane, BorderLayout.SOUTH);
 
+        if (delta == 0 || !logPanelPreferenceModel.isShowMillisDeltaAsGap()) {
+          if (col == 0) {
+            textPane.setBorder(getLeftBorder(isSelected, delta));
+          } else if (col == table.getColumnCount() - 1) {
+            textPane.setBorder(getRightBorder(isSelected, delta));
+          } else {
+            textPane.setBorder(getMiddleBorder(isSelected, delta));
+          }
+        } else {
+            if (col == 0) {
+              textPane.setBorder(getLeftBorder(isSelected, 0));
+            } else if (col == table.getColumnCount() - 1) {
+              textPane.setBorder(getRightBorder(isSelected, 0));
+            } else {
+              textPane.setBorder(getMiddleBorder(isSelected, 0));
+            }
+        }
         int currentMarkerHeight = loggingEventWrapper.getMarkerHeight();
         int currentMsgHeight = loggingEventWrapper.getMsgHeight();
         int newRowHeight = ChainsawConstants.DEFAULT_ROW_HEIGHT;
@@ -425,13 +443,13 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
 
         component = textPaneContainer;
-        setComponentBorder(component, isSelected, table, col, delta);
       }
         break;
     case ChainsawColumns.INDEX_LEVEL_COL_NAME:
       if (levelUseIcons) {
         if (basic) {
           basicComponent.setText("");
+          basicComponent.setIcon((Icon)iconMap.get(value.toString()));
           if (!toolTipsVisible) {
             basicComponent.setToolTipText(value.toString());
           }
@@ -464,8 +482,6 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         }
       }
       if (basic) {
-        basicComponent.setForeground(label.getForeground());
-        basicComponent.setBackground(label.getBackground());
         component = basicComponent;
       } else {
         levelTextPane.setForeground(label.getForeground());


[47/50] [abbrv] logging-chainsaw git commit: Replace '(LF)' with '(NL)' for newline format and fix support for + in timestamp formats

Posted by rg...@apache.org.
Replace '(LF)' with '(NL)' for newline format and fix support for + in timestamp formats


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/d838d7fa
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/d838d7fa
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/d838d7fa

Branch: refs/heads/master
Commit: d838d7fa9bdc16a8905ee4f777b97d97d5c04c8f
Parents: c85387f
Author: Scott Deboy <sd...@apache.org>
Authored: Fri May 9 05:04:41 2014 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Fri May 9 05:04:41 2014 +0000

----------------------------------------------------------------------
 .../org/apache/log4j/varia/LogFilePatternReceiver.java   | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/d838d7fa/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
index 127f365..f8f12eb 100644
--- a/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
+++ b/src/main/java/org/apache/log4j/varia/LogFilePatternReceiver.java
@@ -152,7 +152,7 @@ public class LogFilePatternReceiver extends Receiver {
   private static final String FILE = "FILE";
   private static final String LINE = "LINE";
   private static final String METHOD = "METHOD";
-  private static final String NEWLINE = "(LF)";
+  private static final String NEWLINE = "(NL)";
   
   private static final String DEFAULT_HOST = "file";
   
@@ -202,7 +202,7 @@ public class LogFilePatternReceiver extends Receiver {
   private boolean appendNonMatches;
   private final Map customLevelDefinitionMap = new HashMap();
 
-  //default to one line - this number is incremented for each (LF) found in the logFormat
+  //default to one line - this number is incremented for each (NL) found in the logFormat
   private int lineCount = 1;
 
     public LogFilePatternReceiver() {
@@ -499,7 +499,7 @@ public class LogFilePatternReceiver extends Receiver {
         Matcher eventMatcher;
         Matcher exceptionMatcher;
         String line;
-        //if newlines are provided in the logFormat - (LF) - combine the lines prior to matching
+        //if newlines are provided in the logFormat - (NL) - combine the lines prior to matching
         while ((line = bufferedReader.readLine()) != null) {
             //there is already one line (read above, start i at 1
             for (int i=1;i<lineCount;i++)
@@ -611,7 +611,8 @@ public class LogFilePatternReceiver extends Receiver {
   private String convertTimestamp() {
     //some locales (for example, French) generate timestamp text with characters not included in \w -
     // now using \S (all non-whitespace characters) instead of /w 
-    String result = timestampFormat.replaceAll(VALID_DATEFORMAT_CHAR_PATTERN + "+", "\\\\S+");
+    String result = timestampFormat.replaceAll(Pattern.quote("+"), "[+]");
+    result = result.replaceAll(VALID_DATEFORMAT_CHAR_PATTERN, "\\\\S+");
     //make sure dots in timestamp are escaped
     result = result.replaceAll(Pattern.quote("."), "\\\\.");
     return result;
@@ -673,7 +674,7 @@ public class LogFilePatternReceiver extends Receiver {
 
     String newPattern = logFormat;
 
-    //process line feeds - (LF) - in the logFormat - before processing properties
+    //process newlines - (NL) - in the logFormat - before processing properties
     int index = 0;
     while (index > -1) {
       index = newPattern.indexOf(NEWLINE);


[33/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
new file mode 100644
index 0000000..f9d8125
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/UtilLoggingXMLDecoder.java
@@ -0,0 +1,468 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.zip.ZipInputStream;
+
+import javax.swing.ProgressMonitorInputStream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.UtilLoggingLevel;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.apache.log4j.spi.LocationInfo;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Decodes JDK 1.4's java.util.logging package events
+ * delivered via XML (using the logger.dtd).
+ *
+ * @author Scott Deboy (sdeboy@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public class UtilLoggingXMLDecoder implements Decoder {
+  //NOTE: xml section is only handed on first delivery of events
+  //on this first delivery of events, there is no end tag for the log element
+  /**
+   * Document prolog.
+   */
+  private static final String BEGIN_PART =
+    "<log>";
+    /**
+     * Document close.
+     */
+  private static final String END_PART = "</log>";
+    /**
+     * Document builder.
+     */
+  private DocumentBuilder docBuilder;
+    /**
+     * Additional properties.
+     */
+  private Map additionalProperties = new HashMap();
+    /**
+     * Partial event.
+     */
+  private String partialEvent;
+    /**
+     * Record end.
+     */
+  private static final String RECORD_END = "</record>";
+    /**
+     * Owner.
+     */
+  private Component owner = null;
+
+  private static final String ENCODING = "UTF-8";
+
+    /**
+     * Create new instance.
+     * @param o owner
+     */
+  public UtilLoggingXMLDecoder(final Component o) {
+      this();
+      this.owner = o;
+  }
+
+    /**
+     * Create new instance.
+     */
+  public UtilLoggingXMLDecoder() {
+    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+    dbf.setValidating(false);
+
+    try {
+      docBuilder = dbf.newDocumentBuilder();
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new UtilLoggingEntityResolver());
+    } catch (ParserConfigurationException pce) {
+      System.err.println("Unable to get document builder");
+    }
+  }
+
+  /**
+   * Sets an additionalProperty map, where each Key/Value pair is
+   * automatically added to each LoggingEvent as it is decoded.
+   *
+   * This is useful, say, to include the source file name of the Logging events
+   * @param properties additional properties
+   */
+  public void setAdditionalProperties(final Map properties) {
+    this.additionalProperties = properties;
+  }
+
+  /**
+   * Converts the LoggingEvent data in XML string format into an actual
+   * XML Document class instance.
+   * @param data XML fragment
+   * @return  dom document
+   */
+  private Document parse(final String data) {
+    if (docBuilder == null || data == null) {
+      return null;
+    }
+
+    Document document = null;
+
+    try {
+      // we change the system ID to a valid URI so that Crimson won't
+      // complain. Indeed, "log4j.dtd" alone is not a valid URI which
+      // causes Crimson to barf. The Log4jEntityResolver only cares
+      // about the "log4j.dtd" ending.
+
+      /**
+       * resetting the length of the StringBuffer is dangerous, particularly
+       * on some JDK 1.4 impls, there's a known Bug that causes a memory leak
+       */
+      StringBuffer buf = new StringBuffer(1024);
+
+      if (!data.startsWith("<?xml")) {
+        buf.append(BEGIN_PART);
+      }
+
+      buf.append(data);
+
+      if (!data.endsWith(END_PART)) {
+        buf.append(END_PART);
+      }
+
+      InputSource inputSource =
+        new InputSource(new StringReader(buf.toString()));
+      document = docBuilder.parse(inputSource);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    return document;
+  }
+
+  /**
+   * Decodes a File into a Vector of LoggingEvents.
+   * @param url the url of a file containing events to decode
+   * @return Vector of LoggingEvents
+   * @throws IOException if IO error during processing.
+   */
+  public Vector decode(final URL url) throws IOException {
+    LineNumberReader reader;
+    boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
+    InputStream inputStream;
+    if (isZipFile) {
+        inputStream = new ZipInputStream(url.openStream());
+        //move stream to next entry so we can read it
+        ((ZipInputStream)inputStream).getNextEntry();
+    } else {
+        inputStream = url.openStream();
+    }
+    if (owner != null) {
+        reader = new LineNumberReader(
+                new InputStreamReader(
+                        new ProgressMonitorInputStream(owner,
+                                "Loading " + url , inputStream), ENCODING));
+    } else {
+        reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
+    }
+    Vector v = new Vector();
+
+      String line;
+      Vector events;
+      try {
+          while ((line = reader.readLine()) != null) {
+              StringBuffer buffer = new StringBuffer(line);
+              for (int i = 0; i < 1000; i++) {
+                  buffer.append(reader.readLine()).append("\n");
+              }
+              events = decodeEvents(buffer.toString());
+              if (events != null) {
+                  v.addAll(events);
+              }
+          }
+    } finally {
+      partialEvent = null;
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return v;
+  }
+
+  /**
+   * Decodes a String representing a number of events into a
+   * Vector of LoggingEvents.
+   * @param document to decode events from
+   * @return Vector of LoggingEvents
+   */
+  public Vector decodeEvents(final String document) {
+
+      if (document != null) {
+
+          if (document.trim().equals("")) {
+              return null;
+          }
+
+          String newDoc;
+          String newPartialEvent = null;
+          //separate the string into the last portion ending with </record>
+          // (which will be processed) and the partial event which
+          // will be combined and processed in the next section
+
+          //if the document does not contain a record end,
+          // append it to the partial event string
+          if (document.lastIndexOf(RECORD_END) == -1) {
+              partialEvent = partialEvent + document;
+              return null;
+          }
+
+          if (document.lastIndexOf(RECORD_END) + RECORD_END.length()
+                  < document.length()) {
+              newDoc = document.substring(0,
+                      document.lastIndexOf(RECORD_END) + RECORD_END.length());
+              newPartialEvent = document.substring(
+                      document.lastIndexOf(RECORD_END) + RECORD_END.length());
+          } else {
+              newDoc = document;
+          }
+          if (partialEvent != null) {
+              newDoc = partialEvent + newDoc;
+          }
+          partialEvent = newPartialEvent;
+
+          Document doc = parse(newDoc);
+          if (doc == null) {
+              return null;
+          }
+          return decodeEvents(doc);
+      }
+      return null;
+  }
+
+    /**
+      * Converts the string data into an XML Document, and then soaks out the
+      * relevant bits to form a new LoggingEvent instance which can be used
+      * by any Log4j element locally.
+      * @param data XML fragment
+      * @return a single LoggingEvent or null
+      */
+  public LoggingEvent decode(final String data) {
+    Document document = parse(data);
+
+    if (document == null) {
+      return null;
+    }
+
+    Vector events = decodeEvents(document);
+
+    if (events.size() > 0) {
+      return (LoggingEvent) events.firstElement();
+    }
+
+    return null;
+  }
+
+  /**
+   * Given a Document, converts the XML into a Vector of LoggingEvents.
+   * @param document XML document
+   * @return Vector of LoggingEvents
+   */
+  private Vector decodeEvents(final Document document) {
+    Vector events = new Vector();
+
+    NodeList eventList = document.getElementsByTagName("record");
+
+    for (int eventIndex = 0; eventIndex < eventList.getLength();
+        eventIndex++) {
+      Node eventNode = eventList.item(eventIndex);
+
+      Logger logger = null;
+    long timeStamp = 0L;
+    Level level = null;
+    String threadName = null;
+    Object message = null;
+    String ndc = null;
+    String[] exception = null;
+    String className = null;
+    String methodName = null;
+    String fileName = null;
+    String lineNumber = null;
+    Hashtable properties = new Hashtable();
+
+      //format of date: 2003-05-04T11:04:52
+      //ignore date or set as a property? using millis in constructor instead
+      NodeList list = eventNode.getChildNodes();
+      int listLength = list.getLength();
+
+      if (listLength == 0) {
+        continue;
+      }
+
+      for (int y = 0; y < listLength; y++) {
+        String tagName = list.item(y).getNodeName();
+
+        if (tagName.equalsIgnoreCase("logger")) {
+          logger = Logger.getLogger(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("millis")) {
+          timeStamp = Long.parseLong(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("level")) {
+          level = UtilLoggingLevel.toLevel(getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("thread")) {
+          threadName = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("sequence")) {
+          properties.put("log4jid", getCData(list.item(y)));
+        }
+
+        if (tagName.equalsIgnoreCase("message")) {
+          message = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("class")) {
+          className = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("method")) {
+          methodName = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("exception")) {
+          ArrayList exceptionList = new ArrayList();
+          NodeList exList = list.item(y).getChildNodes();
+          int exlistLength = exList.getLength();
+
+          for (int i2 = 0; i2 < exlistLength; i2++) {
+            Node exNode = exList.item(i2);
+            String exName = exList.item(i2).getNodeName();
+
+            if (exName.equalsIgnoreCase("message")) {
+              exceptionList.add(getCData(exList.item(i2)));
+            }
+
+            if (exName.equalsIgnoreCase("frame")) {
+              NodeList exList2 = exNode.getChildNodes();
+              int exlist2Length = exList2.getLength();
+
+              for (int i3 = 0; i3 < exlist2Length; i3++) {
+                exceptionList.add(getCData(exList2.item(i3)) + "\n");
+              }
+            }
+          }
+          if (exceptionList.size() > 0) {
+              exception =
+                (String[]) exceptionList.toArray(new String[exceptionList.size()]);
+          }
+        }
+      }
+
+        /**
+         * We add all the additional properties to the properties
+         * hashtable. Override properties that already exist
+         */
+        if (additionalProperties.size() > 0) {
+            if (properties == null) {
+                properties = new Hashtable(additionalProperties);
+            }
+            Iterator i = additionalProperties.entrySet().iterator();
+            while (i.hasNext()) {
+                Map.Entry e = (Map.Entry) i.next();
+                properties.put(e.getKey(), e.getValue());
+            }
+        }
+
+      LocationInfo info;
+      if ((fileName != null)
+              || (className != null)
+              || (methodName != null)
+              || (lineNumber != null)) {
+          info = new LocationInfo(fileName, className, methodName, lineNumber);
+      } else {
+        info = LocationInfo.NA_LOCATION_INFO;
+      }
+
+        ThrowableInformation throwableInfo = null;
+        if (exception != null) {
+            throwableInfo = new ThrowableInformation(exception);
+        }
+
+        LoggingEvent loggingEvent = new LoggingEvent(null,
+                logger, timeStamp, level, message,
+                threadName,
+                throwableInfo,
+                ndc,
+                info,
+                properties);
+
+      events.add(loggingEvent);
+
+    }
+    return events;
+  }
+
+    /**
+     * Get contents of CDATASection.
+     * @param n CDATASection
+     * @return text content of all text or CDATA children of node.
+     */
+  private String getCData(final Node n) {
+    StringBuffer buf = new StringBuffer();
+    NodeList nl = n.getChildNodes();
+
+    for (int x = 0; x < nl.getLength(); x++) {
+      Node innerNode = nl.item(x);
+
+      if (
+        (innerNode.getNodeType() == Node.TEXT_NODE)
+          || (innerNode.getNodeType() == Node.CDATA_SECTION_NODE)) {
+        buf.append(innerNode.getNodeValue());
+      }
+    }
+
+    return buf.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/xml/XMLDecoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/xml/XMLDecoder.java b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
new file mode 100644
index 0000000..8ced851
--- /dev/null
+++ b/src/main/java/org/apache/log4j/xml/XMLDecoder.java
@@ -0,0 +1,495 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.xml;
+
+import java.awt.Component;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.zip.ZipInputStream;
+
+import javax.swing.ProgressMonitorInputStream;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.Decoder;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.ThrowableInformation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+
+/**
+ * Decodes Logging Events in XML formated into elements that are used by
+ * Chainsaw.
+ *
+ * This decoder can process a collection of log4j:event nodes ONLY
+ * (no XML declaration nor eventSet node)
+ *
+ * NOTE:  Only a single LoggingEvent is returned from the decode method
+ * even though the DTD supports multiple events nested in an eventSet.
+ *
+ * NOTE: This class has been created on the assumption that all XML log files
+ * are encoded in UTF-8. There is no current support for any other
+ * encoding format at this time.
+ * 
+ * @author Scott Deboy (sdeboy@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public class XMLDecoder implements Decoder {
+    
+  private static final String ENCODING = "UTF-8";
+    
+    /**
+     * Document prolog.
+     */
+  private static final String BEGINPART =
+    "<?xml version=\"1.0\" encoding=\"" + ENCODING + "\" ?>"
+    + "<!DOCTYPE log4j:eventSet SYSTEM \"http://localhost/log4j.dtd\">"
+    + "<log4j:eventSet version=\"1.2\" "
+    + "xmlns:log4j=\"http://jakarta.apache.org/log4j/\">";
+    /**
+     * Document close.
+     */
+  private static final String ENDPART = "</log4j:eventSet>";
+    /**
+     * Record end.
+     */
+  private static final String RECORD_END = "</log4j:event>";
+
+    /**
+     * Document builder.
+     */
+  private DocumentBuilder docBuilder;
+    /**
+     * Additional properties.
+     */
+  private Map additionalProperties = new HashMap();
+    /**
+     * Partial event.
+     */
+  private String partialEvent;
+    /**
+     * Owner.
+     */
+  private Component owner = null;
+
+    /**
+     * Create new instance.
+     * @param o owner
+     */
+  public XMLDecoder(final Component o) {
+      this();
+      this.owner = o;
+  }
+
+    /**
+     * Create new instance.
+     */
+   public XMLDecoder() {
+    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+    dbf.setValidating(false);
+
+    try {
+      docBuilder = dbf.newDocumentBuilder();
+      docBuilder.setErrorHandler(new SAXErrorHandler());
+      docBuilder.setEntityResolver(new Log4jEntityResolver());
+    } catch (ParserConfigurationException pce) {
+      System.err.println("Unable to get document builder");
+    }
+  }
+
+  /**
+   * Sets an additionalProperty map, where each Key/Value pair is
+   * automatically added to each LoggingEvent as it is decoded.
+   *
+   * This is useful, say, to include the source file name of the Logging events
+   * @param properties additional properties
+   */
+  public void setAdditionalProperties(final Map properties) {
+    this.additionalProperties = properties;
+  }
+
+  /**
+   * Converts the LoggingEvent data in XML string format into an actual
+   * XML Document class instance.
+   * @param data XML fragment
+   * @return dom document
+   */
+  private Document parse(final String data) {
+    if (docBuilder == null || data == null) {
+      return null;
+    }
+    Document document = null;
+
+    try {
+      // we change the system ID to a valid URI so that Crimson won't
+      // complain. Indeed, "log4j.dtd" alone is not a valid URI which
+      // causes Crimson to barf. The Log4jEntityResolver only cares
+      // about the "log4j.dtd" ending.
+
+      /**
+       * resetting the length of the StringBuffer is dangerous, particularly
+       * on some JDK 1.4 impls, there's a known Bug that causes a memory leak
+       */
+      StringBuffer buf = new StringBuffer(1024);
+
+      buf.append(BEGINPART);
+      buf.append(data);
+      buf.append(ENDPART);
+
+      InputSource inputSource =
+        new InputSource(new StringReader(buf.toString()));
+      document = docBuilder.parse(inputSource);
+    } catch (Exception e) {
+      e.printStackTrace();
+    }
+
+    return document;
+  }
+
+  /**
+   * Decodes a File into a Vector of LoggingEvents.
+   * @param url the url of a file containing events to decode
+   * @return Vector of LoggingEvents
+   * @throws IOException if IO error during processing.
+   */
+  public Vector decode(final URL url) throws IOException {
+    LineNumberReader reader;
+    boolean isZipFile = url.getPath().toLowerCase().endsWith(".zip");
+    InputStream inputStream;
+    if (isZipFile) {
+        inputStream = new ZipInputStream(url.openStream());
+        //move stream to next entry so we can read it
+        ((ZipInputStream)inputStream).getNextEntry();
+    } else {
+        inputStream = url.openStream();
+    }
+    if (owner != null) {
+        reader = new LineNumberReader(
+                new InputStreamReader(
+                        new ProgressMonitorInputStream(owner,
+                                "Loading " + url , inputStream), ENCODING));
+    } else {
+        reader = new LineNumberReader(new InputStreamReader(inputStream, ENCODING));
+    }
+
+    Vector v = new Vector();
+
+    String line;
+    Vector events;
+    try {
+        while ((line = reader.readLine()) != null) {
+            StringBuffer buffer = new StringBuffer(line);
+            for (int i = 0; i < 1000; i++) {
+                buffer.append(reader.readLine()).append("\n");
+            }
+            events = decodeEvents(buffer.toString());
+            if (events != null) {
+                v.addAll(events);
+            }
+        }
+    } finally {
+      partialEvent = null;
+      try {
+        if (reader != null) {
+          reader.close();
+        }
+      } catch (Exception e) {
+        e.printStackTrace();
+      }
+    }
+    return v;
+  }
+
+    /**
+     * Decodes a String representing a number of events into a
+     * Vector of LoggingEvents.
+     * @param document to decode events from
+     * @return Vector of LoggingEvents
+     */
+  public Vector decodeEvents(final String document) {
+    if (document != null) {
+      if (document.trim().equals("")) {
+        return null;
+      }
+        String newDoc = null;
+        String newPartialEvent = null;
+        //separate the string into the last portion ending with
+        // </log4j:event> (which will be processed) and the
+        // partial event which will be combined and
+        // processed in the next section
+
+        //if the document does not contain a record end,
+        // append it to the partial event string
+        if (document.lastIndexOf(RECORD_END) == -1) {
+            partialEvent = partialEvent + document;
+            return null;
+        }
+
+        if (document.lastIndexOf(RECORD_END)
+                + RECORD_END.length() < document.length()) {
+            newDoc = document.substring(0,
+                    document.lastIndexOf(RECORD_END) + RECORD_END.length());
+            newPartialEvent = document.substring(
+                    document.lastIndexOf(RECORD_END) + RECORD_END.length());
+        } else {
+            newDoc = document;
+        }
+        if (partialEvent != null) {
+            newDoc = partialEvent + newDoc;
+        }
+        partialEvent = newPartialEvent;
+        Document doc = parse(newDoc);
+        if (doc == null) {
+            return null;
+        }
+        return decodeEvents(doc);
+    }
+    return null;
+  }
+
+  /**
+   * Converts the string data into an XML Document, and then soaks out the
+   * relevant bits to form a new LoggingEvent instance which can be used
+   * by any Log4j element locally.
+   * @param data XML fragment
+   * @return a single LoggingEvent or null
+   */
+  public LoggingEvent decode(final String data) {
+    Document document = parse(data);
+
+    if (document == null) {
+      return null;
+    }
+
+    Vector events = decodeEvents(document);
+
+    if (events.size() > 0) {
+      return (LoggingEvent) events.firstElement();
+    }
+
+    return null;
+  }
+
+  /**
+   * Given a Document, converts the XML into a Vector of LoggingEvents.
+   * @param document XML document
+   * @return Vector of LoggingEvents
+   */
+  private Vector decodeEvents(final Document document) {
+    Vector events = new Vector();
+
+    Logger logger;
+    long timeStamp;
+    Level level;
+    String threadName;
+    Object message = null;
+    String ndc = null;
+    String[] exception = null;
+    String className = null;
+    String methodName = null;
+    String fileName = null;
+    String lineNumber = null;
+    Hashtable properties = null;
+
+    NodeList nl = document.getElementsByTagName("log4j:eventSet");
+    Node eventSet = nl.item(0);
+
+    NodeList eventList = eventSet.getChildNodes();
+
+    for (int eventIndex = 0; eventIndex < eventList.getLength();
+        eventIndex++) {
+        Node eventNode = eventList.item(eventIndex);
+      //ignore carriage returns in xml
+        if (eventNode.getNodeType() != Node.ELEMENT_NODE) {
+            continue;
+        }
+      logger = Logger.getLogger(eventNode.getAttributes().getNamedItem("logger").getNodeValue());
+      timeStamp = Long.parseLong(eventNode.getAttributes().getNamedItem("timestamp").getNodeValue());
+      level = Level.toLevel(eventNode.getAttributes().getNamedItem("level").getNodeValue());
+      threadName = eventNode.getAttributes().getNamedItem("thread").getNodeValue();
+
+      NodeList list = eventNode.getChildNodes();
+      int listLength = list.getLength();
+
+      if (listLength == 0) {
+        continue;
+      }
+
+      for (int y = 0; y < listLength; y++) {
+        String tagName = list.item(y).getNodeName();
+
+        if (tagName.equalsIgnoreCase("log4j:message")) {
+          message = getCData(list.item(y));
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:NDC")) {
+          ndc = getCData(list.item(y));
+        }
+        //still support receiving of MDC and convert to properties
+        if (tagName.equalsIgnoreCase("log4j:MDC")) {
+          properties = new Hashtable();
+          NodeList propertyList = list.item(y).getChildNodes();
+          int propertyLength = propertyList.getLength();
+
+          for (int i = 0; i < propertyLength; i++) {
+            String propertyTag = propertyList.item(i).getNodeName();
+
+            if (propertyTag.equalsIgnoreCase("log4j:data")) {
+              Node property = propertyList.item(i);
+              String name =
+                property.getAttributes().getNamedItem("name").getNodeValue();
+              String value =
+                property.getAttributes().getNamedItem("value").getNodeValue();
+              properties.put(name, value);
+            }
+          }
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:throwable")) {
+            String exceptionString = getCData(list.item(y));
+            if (exceptionString != null && !exceptionString.trim().equals("")) {
+                exception = new String[] {exceptionString.trim()
+            };
+          }
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:locationinfo")) {
+          className =
+            list.item(y).getAttributes().getNamedItem("class").getNodeValue();
+          methodName =
+            list.item(y).getAttributes().getNamedItem("method").getNodeValue();
+          fileName =
+            list.item(y).getAttributes().getNamedItem("file").getNodeValue();
+          lineNumber =
+            list.item(y).getAttributes().getNamedItem("line").getNodeValue();
+        }
+
+        if (tagName.equalsIgnoreCase("log4j:properties")) {
+          if (properties == null) {
+              properties = new Hashtable();
+          }
+          NodeList propertyList = list.item(y).getChildNodes();
+          int propertyLength = propertyList.getLength();
+
+          for (int i = 0; i < propertyLength; i++) {
+            String propertyTag = propertyList.item(i).getNodeName();
+
+            if (propertyTag.equalsIgnoreCase("log4j:data")) {
+              Node property = propertyList.item(i);
+              String name =
+                property.getAttributes().getNamedItem("name").getNodeValue();
+              String value =
+                property.getAttributes().getNamedItem("value").getNodeValue();
+              properties.put(name, value);
+            }
+          }
+        }
+
+          /**
+           * We add all the additional properties to the properties
+           * hashtable. Override properties that already exist
+           */
+          if (additionalProperties.size() > 0) {
+              if (properties == null) {
+                  properties = new Hashtable(additionalProperties);
+              }
+              Iterator i = additionalProperties.entrySet().iterator();
+              while (i.hasNext()) {
+                  Map.Entry e = (Map.Entry) i.next();
+                  properties.put(e.getKey(), e.getValue());
+              }
+          }
+      }
+
+      LocationInfo info;
+      if ((fileName != null)
+              || (className != null)
+              || (methodName != null)
+              || (lineNumber != null)) {
+          info = new LocationInfo(fileName, className, methodName, lineNumber);
+      } else {
+        info = LocationInfo.NA_LOCATION_INFO;
+      }
+      ThrowableInformation throwableInfo = null;
+      if (exception != null) {
+          throwableInfo = new ThrowableInformation(exception);
+      }
+
+        LoggingEvent loggingEvent = new LoggingEvent(null,
+                logger, timeStamp, level, message,
+                threadName,
+                throwableInfo,
+                ndc,
+                info,
+                properties);
+
+
+      events.add(loggingEvent);
+
+      message = null;
+      ndc = null;
+      exception = null;
+      className = null;
+      methodName = null;
+      fileName = null;
+      lineNumber = null;
+      properties = null;
+    }
+
+    return events;
+  }
+
+    /**
+     * Get contents of CDATASection.
+     * @param n CDATASection
+     * @return text content of all text or CDATA children of node.
+     */
+  private String getCData(final Node n) {
+    StringBuffer buf = new StringBuffer();
+    NodeList nl = n.getChildNodes();
+
+    for (int x = 0; x < nl.getLength(); x++) {
+      Node innerNode = nl.item(x);
+
+      if (
+        (innerNode.getNodeType() == Node.TEXT_NODE)
+          || (innerNode.getNodeType() == Node.CDATA_SECTION_NODE)) {
+        buf.append(innerNode.getNodeValue());
+      }
+    }
+
+    return buf.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
index 98e26df..b25f6cd 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
+++ b/src/main/resources/org/apache/log4j/chainsaw/help/release-notes.html
@@ -12,6 +12,7 @@
 <h1>2.1</h1>
 <h2>2 Oct 2011</h2>
 <ul>
+<li>Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.</li>
 <li>Added persistent "always display" expression support (button below the logger tree).  The 'always display' expression overrides hidden loggers and the hidden expression but not the refine focus filtering mechanism.  Often used with expressions like 'exception exists || level > warn' to ensure errors and exceptions are not filtered out due to the hidden expression or hidden logger mechanism. </li>
 </ul>
 <h2>11 Nov 2010</h2>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/VectorAppender.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/VectorAppender.java b/src/test/java/org/apache/log4j/VectorAppender.java
new file mode 100644
index 0000000..d7833a8
--- /dev/null
+++ b/src/test/java/org/apache/log4j/VectorAppender.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j;
+
+import java.util.Vector;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+   An appender that appends logging events to a vector.
+   @author Ceki  G&uuml;lc&uuml;
+*/
+public class VectorAppender extends AppenderSkeleton {
+  public Vector vector;
+
+  long delay = 0;
+  
+  public VectorAppender() {
+    super(true);
+    vector = new Vector();
+  }
+
+
+  /**
+     This method is called by the {@link AppenderSkeleton#doAppend}
+     method.
+
+  */
+  public void append(LoggingEvent event) {
+    if(delay > 0) {
+      try {
+        Thread.sleep(delay);
+      } catch (Exception e) {
+      }
+    }
+
+    vector.addElement(event);
+  }
+
+  /**
+   * Returns a vector of {@link LoggingEvent}.
+   */
+  public Vector getVector() {
+    return vector;
+  }
+
+  public synchronized void close() {
+    if (this.closed) {
+      return;
+    }
+
+    this.closed = true;
+  }
+
+  public boolean isClosed() {
+    return closed;
+  }
+
+  public boolean requiresLayout() {
+    return false;
+  }
+  
+  /**
+   * Returns a delay to log.
+   */
+  public long getDelay() {
+    return delay;
+  }
+
+  /**
+   * Sets a delay to log.
+   */  
+  public void setDelay(long delay) {
+    this.delay = delay;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/db/FullCycleDBTest.java b/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
new file mode 100644
index 0000000..6352974
--- /dev/null
+++ b/src/test/java/org/apache/log4j/db/FullCycleDBTest.java
@@ -0,0 +1,327 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.db;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.log4j.Hierarchy;
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.MDC;
+import org.apache.log4j.VectorAppender;
+import org.apache.log4j.LoggerRepositoryExImpl;
+import org.apache.log4j.helpers.Constants;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.apache.log4j.spi.LocationInfo;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.RootLogger;
+import org.apache.log4j.spi.LoggerRepository;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+import java.util.HashMap;
+import java.io.InputStream;
+import java.io.IOException;
+
+
+/**
+ * This test case writes a few events into a databases and reads them
+ * back comparing the event written and read back.
+ * 
+ * <p>It relies heavily on the proper configuration of its environment
+ * in joran config files as well system properties.
+ * </p>
+ * 
+ * <p>See also the Ant build file in the tests/ directory.</p> 
+ * 
+ * @author Ceki G&uuml;lc&uuml
+ */
+public class FullCycleDBTest
+       extends TestCase {
+  
+  Vector witnessEvents;
+  Hierarchy lrWrite;
+  LoggerRepository lrRead;
+  String appendConfigFile = null;
+  String readConfigFile = null;
+  
+  
+  /*
+   * @see TestCase#setUp()
+   */
+  protected void setUp()
+         throws Exception {
+    super.setUp();
+    appendConfigFile = "append-with-drivermanager1.xml";
+    readConfigFile = "read-with-drivermanager1.xml";
+
+    witnessEvents = new Vector();
+    lrWrite = new Hierarchy(new RootLogger(Level.DEBUG));
+    lrRead = new LoggerRepositoryExImpl(new Hierarchy(new RootLogger(Level.DEBUG)));
+
+
+    //
+    //   attempt to define tables in in-memory database
+    //      will throw exception if already defined.
+    //
+        Class.forName("org.hsqldb.jdbcDriver");
+        Connection connection = DriverManager.getConnection("jdbc:hsqldb:mem:testdb");
+        try {
+            Statement s = connection.createStatement();
+            s.executeUpdate("CREATE TABLE logging_event " +
+              "( sequence_number   BIGINT NOT NULL, " +
+               " timestamp         BIGINT NOT NULL, " +
+               " rendered_message  LONGVARCHAR NOT NULL, " +
+               " logger_name       VARCHAR NOT NULL, " +
+               " level_string      VARCHAR NOT NULL, " +
+               " ndc               LONGVARCHAR, " +
+               " thread_name       VARCHAR, " +
+               " reference_flag    SMALLINT, " +
+               " caller_filename   VARCHAR, " +
+               " caller_class      VARCHAR, " +
+               " caller_method     VARCHAR, " +
+               " caller_line       CHAR(4), " +
+               " event_id          INT NOT NULL IDENTITY)");
+            s.executeUpdate("CREATE TABLE logging_event_property " +
+              "( event_id	      INT NOT NULL, " +
+               " mapped_key        VARCHAR(254) NOT NULL, " +
+               " mapped_value      LONGVARCHAR, " +
+               " PRIMARY KEY(event_id, mapped_key), " +
+               " FOREIGN KEY (event_id) REFERENCES logging_event(event_id))");
+            s.executeUpdate("CREATE TABLE logging_event_exception" +
+                    "  ( event_id         INT NOT NULL, " +
+                    "    i                SMALLINT NOT NULL," +
+                    "    trace_line       VARCHAR NOT NULL," +
+                    "    PRIMARY KEY(event_id, i)," +
+                    "    FOREIGN KEY (event_id) REFERENCES logging_event(event_id))");
+        } catch(SQLException ex) {
+            String s = ex.toString();
+        } finally {
+            connection.close();
+        }
+
+  }
+
+
+  /*
+   * @see TestCase#tearDown()
+   */
+  protected void tearDown()
+         throws Exception {
+    super.tearDown();
+    lrRead.shutdown();
+    witnessEvents = null;
+  }
+
+  /**
+   * Constructor for DBReeceiverTest.
+   * @param arg0
+   */
+  public FullCycleDBTest(String arg0) {
+    super(arg0);
+  }
+
+  
+  /**
+   * This test starts by writing a single event to a DB using DBAppender
+   * and then reads it back using DBReceiver.
+   * 
+   * DB related information is specified within the configuration files.
+   * @throws Exception
+   */
+  public void testSingleOutput()
+         throws Exception {
+    DOMConfigurator jc1 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile);
+    jc1.doConfigure(is, lrWrite);
+    is.close();
+  
+    long startTime = System.currentTimeMillis();
+    System.out.println("***startTime is  "+startTime);
+
+    // Write out just one log message
+    Logger out = lrWrite.getLogger("testSingleOutput.out");
+    out.debug("some message"+startTime);
+
+    VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR");
+    witnessEvents = witnessAppender.getVector();
+    assertEquals(1, witnessEvents.size());    
+
+    // We have to close all appenders before starting to read
+    lrWrite.shutdown();
+
+    // now read it back
+    readBack(readConfigFile, startTime);
+
+  }
+
+  /**
+   * This test starts by writing a single event to a DB using DBAppender
+   * and then reads it back using DBReceiver.
+   * 
+   * The written event includes MDC and repository properties as well as
+   * exception info.
+   * 
+   * DB related information is specified within the configuration files.
+   * @throws Exception
+   */
+  public void testAllFields() throws IOException {
+    DOMConfigurator jc1 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile);
+    jc1.doConfigure(is, lrWrite);
+    is.close();
+  
+    long startTime = System.currentTimeMillis();
+    
+    // Write out just one log message
+    MDC.put("key1", "value1-"+startTime);
+    MDC.put("key2", "value2-"+startTime);
+    Map mdcMap = MDC.getContext();
+//    LogLog.info("**********"+mdcMap.size());
+    
+    // Write out just one log message
+    Logger out = lrWrite.getLogger("out"+startTime);
+
+    out.debug("some message"+startTime);
+    MDC.put("key3", "value2-"+startTime);
+    out.error("some error message"+startTime, new Exception("testing"));
+    
+    // we clear the MDC to avoid interference with the events read back from
+    // the db
+    MDC.remove("key1");
+    MDC.remove("key2");
+    MDC.remove("key3");
+
+    VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR");
+    witnessEvents = witnessAppender.getVector();
+    assertEquals(2, witnessEvents.size());    
+
+    // We have to close all appenders just before starting to read
+    lrWrite.shutdown();
+    
+    readBack(readConfigFile, startTime);
+  }
+
+
+  void readBack(String configfile, long startTime) throws IOException {
+    DOMConfigurator jc2 = new DOMConfigurator();
+    InputStream is = FullCycleDBTest.class.getResourceAsStream(configfile);
+    jc2.doConfigure(is, lrRead);
+    is.close();
+    
+    // wait a little to allow events to be read
+    try { Thread.sleep(3100); } catch(Exception e) {}
+    VectorAppender va = (VectorAppender) lrRead.getRootLogger().getAppender("VECTOR");
+    Vector returnedEvents = getRelevantEventsFromVA(va, startTime);
+    
+    compareEvents(witnessEvents, returnedEvents);
+    
+  }
+  
+  void compareEvents(Vector l, Vector r) {
+    assertNotNull("left vector of events should not be null");
+    assertEquals(l.size(), r.size());
+    
+    for(int i = 0; i < r.size(); i++) {
+      LoggingEvent le = (LoggingEvent) l.get(i);
+      LoggingEvent re = (LoggingEvent) r.get(i);
+      assertEquals(le.getMessage(),        re.getMessage());
+      assertEquals(le.getLoggerName(),     re.getLoggerName());
+      assertEquals(le.getLevel(),          re.getLevel());
+      assertEquals(le.getThreadName(), re.getThreadName());
+      if(re.getTimeStamp() < le.getTimeStamp()) {
+        fail("Returned event cannot preceed witness timestamp");
+      }
+
+      Map sourceMap = re.getProperties();
+      Map remap;
+      if (sourceMap == null) {
+          remap = new HashMap();
+      } else {
+          remap = new HashMap(sourceMap);
+          if (remap.containsKey(Constants.LOG4J_ID_KEY)) {
+              remap.remove(Constants.LOG4J_ID_KEY);
+          }
+      }
+      if(le.getProperties() == null || le.getProperties().size() == 0) {
+        if(remap.size() != 0) {
+          System.out.println("properties are "+remap);
+          fail("Returned event should have been empty");
+        }
+      } else {
+        assertEquals(le.getProperties(), remap);
+      }
+      comprareStringArrays( le.getThrowableStrRep(),  re.getThrowableStrRep());
+      compareLocationInfo(le, re);
+    } 
+  }
+  
+  void comprareStringArrays(String[] la, String[] ra) {
+    if((la == null) && (ra == null)) {
+      return;
+    }
+    assertEquals(la.length, ra.length);
+    for(int i = 0; i < la.length; i++) {
+      assertEquals(la[i], ra[i]);
+    }
+  }
+  
+  void compareLocationInfo(LoggingEvent l, LoggingEvent r) {
+    if(l.locationInformationExists()) {
+      assertEquals(l.getLocationInformation().fullInfo, r.getLocationInformation().fullInfo);
+    } else {
+      assertEquals(LocationInfo.NA_LOCATION_INFO, r.getLocationInformation());
+    }
+  }
+  
+  Vector getRelevantEventsFromVA(VectorAppender va, long startTime) {
+    assertNotNull(va);
+    Vector v = va.getVector();
+    Vector r = new Vector();
+    // remove all elements older than startTime
+    for(Iterator i = v.iterator(); i.hasNext(); ) {
+      LoggingEvent event = (LoggingEvent) i.next();  
+      if(startTime > event.getTimeStamp()) {
+        System.out.println("***Removing event with timestamp "+event.getTimeStamp());
+      } else {
+        System.out.println("***Keeping event with timestamo"+event.getTimeStamp());
+        r.add(event);
+      }
+    }
+    return r;
+  }
+
+  void dump(Vector v) {
+    for(int i = 0; i < v.size(); i++) {
+      LoggingEvent le = (LoggingEvent) v.get(i);
+      System.out.println("---"+le.getLevel()+" "+le.getLoggerName()+" "+le.getMessage());
+    }
+  }
+  
+  public static Test XXsuite() {
+    TestSuite suite = new TestSuite();
+    suite.addTest(new FullCycleDBTest("testSingleOutput"));
+    suite.addTest(new FullCycleDBTest("testAllFields"));
+    return suite;
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java b/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
new file mode 100644
index 0000000..58105ee
--- /dev/null
+++ b/src/test/java/org/apache/log4j/helpers/UtilLoggingLevelTest.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.helpers;
+
+import junit.framework.*;
+
+
+/**
+ * Unit tests for UtilLoggingLevel.
+ */
+
+public class UtilLoggingLevelTest extends TestCase {
+
+    /**
+     * Create new instance of test.
+     *
+     * @param testName test name
+     */
+    public UtilLoggingLevelTest(final String testName) {
+        super(testName);
+    }
+
+    /**
+     * Test toLevel("fiNeSt").
+     */
+    public void testToLevelFINEST() {
+        assertSame(UtilLoggingLevel.FINEST, UtilLoggingLevel.toLevel("fiNeSt"));
+    }
+
+}
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java b/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
new file mode 100644
index 0000000..f15700d
--- /dev/null
+++ b/src/test/java/org/apache/log4j/rewrite/RewriteAppenderTest.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import junit.framework.*;
+import org.apache.log4j.*;
+import org.apache.log4j.util.Compare;
+import org.apache.log4j.xml.*;
+
+import java.io.InputStream;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.TreeMap;
+import java.util.Hashtable;
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+
+public class RewriteAppenderTest extends TestCase {
+    public RewriteAppenderTest(final String name) {
+        super(name);
+    }
+
+    public void setUp() {
+        LogManager.getLoggerRepository().resetConfiguration();
+        Hashtable context = MDC.getContext();
+        if (context != null) {
+            context.clear();
+        }
+    }
+
+    public void tearDown() {
+        LogManager.getLoggerRepository().shutdown();
+    }
+
+    public void configure(final String resourceName) throws Exception {
+        InputStream is = RewriteAppenderTest.class.getResourceAsStream(resourceName);
+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(false);
+        DocumentBuilder builder = factory.newDocumentBuilder();
+        Document doc = builder.parse(is);
+        DOMConfigurator.configure(doc.getDocumentElement());
+    }
+
+
+    public void testMapPolicy() throws Exception {
+        configure("map.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        MDC.put("p1", "Hola");
+
+        Map msg = new TreeMap();
+        msg.put("p1", "Hello");
+        msg.put("p2", "World");
+        msg.put("x1", "Mundo");
+        logger.info(msg);
+        msg.put("message", "Message 1");
+        logger.info(msg);
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "map.log"));
+    }
+
+    private static class BaseBean {
+        private final Object p2;
+        private final Object x1;
+
+        public BaseBean(final Object p2,
+                        final Object x1) {
+             this.p2 = p2;
+             this.x1 = x1;
+        }
+
+        public Object getP2() {
+            return p2;
+        }
+
+        public Object getX1() {
+            return x1;
+        }
+
+        public String toString() {
+            return "I am bean.";
+        }
+    }
+
+    private static class MessageBean extends BaseBean {
+        private final Object msg;
+
+        public MessageBean(final Object msg,
+                           final Object p2,
+                           final Object x1) {
+            super(p2, x1);
+            this.msg = msg;
+        }
+
+        public Object getMessage() {
+            return msg;
+        }
+    }
+
+    public void testReflectionPolicy() throws Exception {
+        configure("reflection.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        logger.info(new BaseBean("Hello", "World" ));
+        MDC.put("p1", "Hola");
+        MDC.put("p2", "p2");
+        logger.info(new MessageBean("Welcome to The Hub", "Hello", "World" ));
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "reflection.log"));
+    }
+
+    public void testPropertyPolicy() throws Exception {
+        configure("property.xml");
+        Logger logger = Logger.getLogger(RewriteAppenderTest.class);
+        logger.info("Message 0");
+        MDC.put("p1", "Hola");
+        logger.info("Message 1");
+        assertTrue(Compare.compare(RewriteAppenderTest.class, "temp", "property.log"));
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/util/Compare.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/util/Compare.java b/src/test/java/org/apache/log4j/util/Compare.java
new file mode 100644
index 0000000..42aa233
--- /dev/null
+++ b/src/test/java/org/apache/log4j/util/Compare.java
@@ -0,0 +1,202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.zip.GZIPInputStream;
+
+
+public class Compare {
+  static final int B1_NULL = -1;
+  static final int B2_NULL = -2;
+
+  private static final InputStream open(
+          final Class testClass,
+          final String fileName) throws IOException {
+      String resourceName = fileName;
+      if (fileName.startsWith("witness/")) {
+          resourceName = fileName.substring(fileName.lastIndexOf('/') + 1);
+      }
+      InputStream is = testClass.getResourceAsStream(resourceName);
+      if (is == null) {
+          File file = new File(fileName);
+          if (file.exists()) {
+              is = new FileInputStream(file);
+          } else {
+              throw new FileNotFoundException("Resource "
+                      + resourceName + " not found");
+          }
+      }
+      return is;
+  }
+
+  public static boolean compare(Class testClass,
+                                final String file1,
+                                final String file2)
+    throws IOException {
+    BufferedReader in1 = new BufferedReader(new FileReader(file1));
+    BufferedReader in2 = new BufferedReader(new InputStreamReader(
+            open(testClass, file2)));
+    try {
+      return compare(testClass, file1, file2, in1, in2);
+    } finally {
+      in1.close();
+      in2.close();
+    }
+  }
+    
+ public static boolean compare(
+         Class testClass, String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+    String s1;
+    int lineCounter = 0;
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+
+      String s2 = in2.readLine();
+
+      if (!s1.equals(s2)) {
+        System.out.println(
+          "Files [" + file1 + "] and [" + file2 + "] differ on line "
+          + lineCounter);
+        System.out.println("One reads:  [" + s1 + "].");
+        System.out.println("Other reads:[" + s2 + "].");
+        outputFile(testClass, file1);
+        outputFile(testClass, file2);
+
+        return false;
+      }
+    }
+
+    // the second file is longer
+    if (in2.read() != -1) {
+      System.out.println(
+        "File [" + file2 + "] longer than file [" + file1 + "].");
+      outputFile(testClass, file1);
+      outputFile(testClass, file2);
+
+      return false;
+    }
+
+    return true;
+  }
+
+  /** 
+   * 
+   * Prints file on the console.
+   *
+   */
+  private static void outputFile(Class testClass, String file)
+    throws IOException {
+    InputStream is = open(testClass, file);
+    BufferedReader in1 = new BufferedReader(new InputStreamReader(is));
+
+    String s1;
+    int lineCounter = 0;
+    System.out.println("--------------------------------");
+    System.out.println("Contents of " + file + ":");
+
+    while ((s1 = in1.readLine()) != null) {
+      lineCounter++;
+      System.out.print(lineCounter);
+
+      if (lineCounter < 10) {
+        System.out.print("   : ");
+      } else if (lineCounter < 100) {
+        System.out.print("  : ");
+      } else if (lineCounter < 1000) {
+        System.out.print(" : ");
+      } else {
+        System.out.print(": ");
+      }
+
+      System.out.println(s1);
+    }
+    in1.close();
+  }
+
+
+    public static boolean gzCompare(final Class testClass,
+                                    final String actual,
+                                    final String expected)
+      throws FileNotFoundException, IOException {
+      String resourceName = expected;
+      int lastSlash = expected.lastIndexOf("/");
+      if (lastSlash >= 0) {
+          resourceName = expected.substring(lastSlash + 1);
+      }
+      InputStream resourceStream = testClass.getResourceAsStream(resourceName);
+      if (resourceStream == null) {
+          throw new FileNotFoundException("Could not locate resource " + resourceName);
+      }
+
+      BufferedReader in1 = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(actual))));
+      BufferedReader in2 = new BufferedReader(new InputStreamReader(new GZIPInputStream(resourceStream)));
+      try {
+        return gzCompare(testClass, actual, expected, in1, in2);
+      } finally {
+        in1.close();
+        in2.close();
+      }
+    }
+
+    public static boolean gzCompare(Class testClass, String file1, String file2, BufferedReader in1, BufferedReader in2) throws IOException {
+
+      String s1;
+      int lineCounter = 0;
+
+      while ((s1 = in1.readLine()) != null) {
+        lineCounter++;
+
+        String s2 = in2.readLine();
+
+        if (!s1.equals(s2)) {
+          System.out.println(
+            "Files [" + file1 + "] and [" + file2 + "] differ on line "
+            + lineCounter);
+          System.out.println("One reads:  [" + s1 + "].");
+          System.out.println("Other reads:[" + s2 + "].");
+          outputFile(testClass, file1);
+          outputFile(testClass, file2);
+
+          return false;
+        }
+      }
+
+      // the second file is longer
+      if (in2.read() != -1) {
+        System.out.println(
+          "File [" + file2 + "] longer than file [" + file1 + "].");
+        outputFile(testClass, file1);
+        outputFile(testClass, file2);
+
+        return false;
+      }
+
+      return true;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
new file mode 100644
index 0000000..bd9e7bc
--- /dev/null
+++ b/src/test/java/org/apache/log4j/xml/XMLDecoderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.xml;
+
+import junit.framework.TestCase;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.CharBuffer;
+import java.util.Vector;
+import java.net.URL;
+
+/**
+ * Tests for XMLDecoder.
+ *
+ */
+public class XMLDecoderTest extends TestCase {
+
+
+  /**
+   * Constructor for XMLDecoderTest.
+   * @param arg0 test name.
+   */
+  public XMLDecoderTest(String arg0) {
+    super(arg0);
+  }
+
+  public String getStringFromResource(final String resourceName,
+                                      final int maxSize) throws Exception {
+      InputStream is = XMLDecoderTest.class.getResourceAsStream(resourceName);
+      if (is == null) {
+          throw new FileNotFoundException(resourceName);
+      }
+      InputStreamReader reader = new InputStreamReader(is, "UTF-8");
+      CharBuffer cb = CharBuffer.allocate(maxSize);
+      for(int chars = reader.read(cb);
+          chars != -1;
+          chars = reader.read(cb));
+      cb.flip();
+      return cb.toString();
+  }
+
+    public void testDecodeEventsString1() throws Exception {
+        String xmlStr = getStringFromResource("xmlLayout.1.xml", 10000);
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decodeEvents(xmlStr);
+        assertEquals(17, events.size());
+    }
+
+  public void testDecodeEventsString2() throws Exception {
+      String xmlStr = getStringFromResource("xsltLayout.1.xml", 10000);
+      XMLDecoder decoder = new XMLDecoder();
+      Vector events = decoder.decodeEvents(xmlStr);
+      assertEquals(15, events.size());
+  }
+
+    public void testDecodeEventsURL1() throws Exception {
+        URL resource = XMLDecoderTest.class.getResource("xmlLayout.1.xml");
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decode(resource);
+        assertEquals(17, events.size());
+    }
+
+    public void testDecodeEventsURL2() throws Exception {
+        URL resource = XMLDecoderTest.class.getResource("xsltLayout.1.xml");
+        XMLDecoder decoder = new XMLDecoder();
+        Vector events = decoder.decode(resource);
+        assertEquals(15, events.size());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml b/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
new file mode 100644
index 0000000..04d02bd
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/db/append-with-drivermanager1.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<!DOCTYPE log4j:configuration SYSTEM 'http://logging.apache.org/log4j/1.2/log4j.dtd'>
+	  
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' debug="true">
+	  
+  <appender name="DB" class="org.apache.log4j.db.DBAppender">
+     <param name="locationInfo" value="true"/>
+     <connectionSource class="org.apache.log4j.db.DriverManagerConnectionSource">
+       <param name="driverClass" value="org.hsqldb.jdbcDriver"/>
+       <param name="url" value="jdbc:hsqldb:mem:testdb"/>
+       <param name="user" value="sa"/>
+       <param name="password" value=""/>
+     </connectionSource>
+  </appender>
+
+  <appender name="VECTOR" class="org.apache.log4j.VectorAppender">
+  </appender>
+  
+  <!-- Prevent internal log4j DEBUG messages from polluting the output. -->
+  <logger name="org.apache.log4j.joran"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.config"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.db.DBAppender"><level value="INFO" /></logger>
+  
+  <root>
+    <level value ="debug"/>
+    <appender-ref ref="DB" />
+    <appender-ref ref="VECTOR" />
+  </root>  
+</log4j:configuration>
+
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml b/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
new file mode 100644
index 0000000..3e77c49
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/db/read-with-drivermanager1.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<!DOCTYPE log4j:configuration SYSTEM 'http://logging.apache.org/log4j/1.2/log4j.dtd'>
+
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/' debug="true">
+	  
+  <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+     <layout class="org.apache.log4j.PatternLayout">
+       <param name="ConversionPattern" value="READING %relative %level %logger - %message%n"/>
+     </layout>
+  </appender>
+  
+  <appender name="VECTOR" class="org.apache.log4j.VectorAppender">
+  </appender>
+  
+  <plugin name="DB" class="org.apache.log4j.db.DBReceiver">
+     <connectionSource class="org.apache.log4j.db.DriverManagerConnectionSource">
+       <param name="driverClass" value="org.hsqldb.jdbcDriver"/>
+       <param name="url" value="jdbc:hsqldb:mem:testdb"/>
+       <param name="user" value="sa"/>
+       <param name="password" value=""/>
+     </connectionSource>
+  </plugin>
+  
+
+  <!-- Prevent internal log4j DEBUG messages from polluting the output. -->
+  <logger name="org.apache.log4j.joran"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.config"><level value="INFO" /></logger>
+  <logger name="org.apache.log4j.db"><level value="INFO" /></logger>
+    
+  <root>
+    <level value="debug"/>
+    <appender-ref ref="VECTOR" />
+    <appender-ref ref="CONSOLE" />
+  </root>  
+</log4j:configuration>
+
+
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/map.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/map.log b/src/test/resources/org/apache/log4j/rewrite/map.log
new file mode 100644
index 0000000..3ce933f
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/map.log
@@ -0,0 +1,3 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2: Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World {p1=Hello, p2=World, x1=Mundo}
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World Message 1

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/map.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/map.xml b/src/test/resources/org/apache/log4j/rewrite/map.xml
new file mode 100644
index 0000000..7cb60b7
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/map.xml
@@ -0,0 +1,38 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.MapRewritePolicy"/>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/property.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/property.log b/src/test/resources/org/apache/log4j/rewrite/property.log
new file mode 100644
index 0000000..9aa2c49
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/property.log
@@ -0,0 +1,2 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hello p2:World Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hola p2:World Message 1

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/property.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/property.xml b/src/test/resources/org/apache/log4j/rewrite/property.xml
new file mode 100644
index 0000000..13a04f8
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/property.xml
@@ -0,0 +1,40 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.PropertyRewritePolicy">
+          <param name="properties" value="p1=Hello,p2=World,x1=3.1415"/>
+      </rewritePolicy>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/reflection.log
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/reflection.log b/src/test/resources/org/apache/log4j/rewrite/reflection.log
new file mode 100644
index 0000000..da0b52f
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/reflection.log
@@ -0,0 +1,3 @@
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2: Message 0
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1: p2:Hello I am bean.
+INFO org.apache.log4j.rewrite.RewriteAppenderTest - p1:Hola p2:Hello Welcome to The Hub

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/rewrite/reflection.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/rewrite/reflection.xml b/src/test/resources/org/apache/log4j/rewrite/reflection.xml
new file mode 100644
index 0000000..643850b
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/rewrite/reflection.xml
@@ -0,0 +1,38 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements.  See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+-->
+<log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>
+    <appender name="F1" class="org.apache.log4j.FileAppender">
+        <param name="file"   value="temp"/>
+        <param name="append" value="false"/>
+        <layout class="org.apache.log4j.PatternLayout">
+           <param name="ConversionPattern" value="%p %c - p1:%X{p1} p2:%X{p2} %m%n"/>
+        </layout>
+    </appender>
+
+
+  <appender name="A1" class="org.apache.log4j.rewrite.RewriteAppender">
+      <appender-ref ref="F1"/>
+      <rewritePolicy class="org.apache.log4j.rewrite.ReflectionRewritePolicy"/>
+  </appender>
+
+  <root>
+    <level value ="debug" />
+    <appender-ref ref="A1" />
+  </root>
+
+</log4j:configuration>

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
----------------------------------------------------------------------
diff --git a/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml b/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
new file mode 100644
index 0000000..06dc106
--- /dev/null
+++ b/src/test/resources/org/apache/log4j/xml/xmlLayout.1.xml
@@ -0,0 +1,162 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+ 
+       http://www.apache.org/licenses/LICENSE-2.0
+ 
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase$X" timestamp="1187196936354" level="INFO" thread="main">
+<log4j:message><![CDATA[in X() constructor]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936358" level="TRACE" thread="main">
+<log4j:message><![CDATA[Message 0]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936358" level="TRACE" thread="main">
+<log4j:message><![CDATA[Message 0]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936358" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 1]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 1]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="INFO" thread="main">
+<log4j:message><![CDATA[Message 2]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="INFO" thread="main">
+<log4j:message><![CDATA[Message 2]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="WARN" thread="main">
+<log4j:message><![CDATA[Message 3]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="WARN" thread="main">
+<log4j:message><![CDATA[Message 3]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 4]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 4]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936363" level="FATAL" thread="main">
+<log4j:message><![CDATA[Message 5]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936363" level="FATAL" thread="main">
+<log4j:message><![CDATA[Message 5]]></log4j:message>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936364" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 6]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936368" level="DEBUG" thread="main">
+<log4j:message><![CDATA[Message 6]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.doRun(IdeaTestRunner.java:69)
+	at junit.textui.TestRunner.doRun(TestRunner.java:109)
+	at com.intellij.rt.execution.junit.IdeaTestRunner.startRunnerWithArgs(IdeaTestRunner.java:24)
+	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:118)
+	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="org.apache.log4j.xml.XMLLayoutTestCase" timestamp="1187196936369" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 7]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+]]></log4j:throwable>
+</log4j:event>
+
+<log4j:event logger="root" timestamp="1187196936371" level="ERROR" thread="main">
+<log4j:message><![CDATA[Message 7]]></log4j:message>
+<log4j:throwable><![CDATA[java.lang.Exception: Just testing
+	at org.apache.log4j.xml.XMLLayoutTestCase.common(XMLLayoutTestCase.java:219)
+	at org.apache.log4j.xml.XMLLayoutTestCase.basic(XMLLayoutTestCase.java:64)
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:585)
+	at junit.framework.TestCase.runTest(TestCase.java:154)
+	at junit.framework.TestCase.runBare(TestCase.java:127)
+	at junit.framework.TestResult$1.protect(TestResult.java:106)
+	at junit.framework.TestResult.runProtected(TestResult.java:124)
+	at junit.framework.TestResult.run(TestResult.java:109)
+	at junit.framework.TestCase.run(TestCase.java:118)
+	at junit.framework.TestSuite.runTest(TestSuite.java:208)
+	at junit.framework.TestSuite.run(TestSuite.java:203)
+	at junit.textui.TestRunner.doRun(TestRunner.java:116)
+]]></log4j:throwable>
+</log4j:event>
+


[27/50] [abbrv] logging-chainsaw git commit: Minor UI fixes Using platform-specific default look and feel on mac & linux instead of metal Defaulting Chainsaw screen size to maximized by default

Posted by rg...@apache.org.
Minor UI fixes
Using platform-specific default look and feel on mac & linux instead of metal
Defaulting Chainsaw screen size to maximized by default


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/cbfde96a
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/cbfde96a
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/cbfde96a

Branch: refs/heads/master
Commit: cbfde96a9bcdf68498ceebc0f904616f78a6cc29
Parents: 8f17d6a
Author: Scott Deboy <sd...@apache.org>
Authored: Sun Nov 14 06:31:46 2010 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Sun Nov 14 06:31:46 2010 +0000

----------------------------------------------------------------------
 .../java/org/apache/log4j/chainsaw/LogUI.java   | 26 +++++++++++++++++---
 .../log4j/chainsaw/prefs/default.properties     |  5 ++--
 2 files changed, 26 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cbfde96a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index ce6154a..6785335 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -290,6 +290,19 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
         public void run()
         {
           String lookAndFeelClassName = model.getLookAndFeelClassName();
+          if (lookAndFeelClassName == null || lookAndFeelClassName.trim().equals("")) {
+              String osName = System.getProperty("os.name");
+              if (osName.toLowerCase().startsWith("mac")) {
+                  //no need to assign look and feel
+              } else if (osName.toLowerCase().startsWith("windows")) {
+                  lookAndFeelClassName = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
+                  model.setLookAndFeelClassName(lookAndFeelClassName);
+              } else if (osName.toLowerCase().startsWith("linux")) {
+                  lookAndFeelClassName = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
+                  model.setLookAndFeelClassName(lookAndFeelClassName);
+              }
+          }
+
           if (lookAndFeelClassName != null && !(lookAndFeelClassName.trim().equals(""))) {
             loadLookAndFeelUsingPluginClassLoader(lookAndFeelClassName);
           }
@@ -709,9 +722,16 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
   public void loadSettings(LoadSettingsEvent event) {
     setLocation(
       event.asInt(LogUI.MAIN_WINDOW_X), event.asInt(LogUI.MAIN_WINDOW_Y));
-    setSize(
-      event.asInt(LogUI.MAIN_WINDOW_WIDTH),
-      event.asInt(LogUI.MAIN_WINDOW_HEIGHT));
+      int width = event.asInt(LogUI.MAIN_WINDOW_WIDTH);
+      int height = event.asInt(LogUI.MAIN_WINDOW_HEIGHT);
+      if (width == -1 && height == -1) {
+          width = Toolkit.getDefaultToolkit().getScreenSize().width;
+          height = Toolkit.getDefaultToolkit().getScreenSize().height;
+          setSize(width, height);
+          setExtendedState(getExtendedState() | MAXIMIZED_BOTH);
+      } else {
+          setSize(width, height);
+      }
 
     getToolBarAndMenus().stateChange();
     RuleColorizer colorizer = new RuleColorizer();

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/cbfde96a/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties
----------------------------------------------------------------------
diff --git a/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties b/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties
index 291d78e..8035e50 100644
--- a/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties
+++ b/src/main/resources/org/apache/log4j/chainsaw/prefs/default.properties
@@ -21,8 +21,9 @@
 # window when it is first realized on startup
 main.window.x=0
 main.window.y=0
-main.window.width=1024
-main.window.height=768
+# default width and height to -1 will display the app at full screen resolution
+main.window.width=-1
+main.window.height=-1
 
 table.columns.order=ID,TIMESTAMP,MARKER,LEVEL,LOGGER,MESSAGE,THROWABLE,THREAD,NDC,CLASS,METHOD,FILE,LINE,MILLISDELTA
 table.columns.widths=50,80,95,50,100,500,100,100,100,100,100,100,100,100


[30/50] [abbrv] logging-chainsaw git commit: Update string comparisons to be case insensitive or explicitly use the English locale where needed in Chainsaw and extras companion

Posted by rg...@apache.org.
Update string comparisons to be case insensitive or explicitly use the English locale where needed in Chainsaw and extras companion


Project: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/commit/11e4448b
Tree: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/tree/11e4448b
Diff: http://git-wip-us.apache.org/repos/asf/logging-chainsaw/diff/11e4448b

Branch: refs/heads/master
Commit: 11e4448b2de0f9c1012ccdab82dcf9dc958aaf4d
Parents: 7329254
Author: Scott Deboy <sd...@apache.org>
Authored: Wed Aug 17 08:18:24 2011 +0000
Committer: Scott Deboy <sd...@apache.org>
Committed: Wed Aug 17 08:18:24 2011 +0000

----------------------------------------------------------------------
 .../chainsaw/ApplicationPreferenceModelPanel.java      |  5 +++--
 .../log4j/chainsaw/ChainsawCyclicBufferTableModel.java |  7 ++++---
 .../java/org/apache/log4j/chainsaw/FileSaveAction.java |  3 ++-
 .../log4j/chainsaw/LogFilePatternLayoutBuilder.java    | 13 +++++++------
 src/main/java/org/apache/log4j/chainsaw/LogPanel.java  |  5 +++--
 src/main/java/org/apache/log4j/chainsaw/LogUI.java     |  9 +++++----
 .../log4j/chainsaw/ReceiverConfigurationPanel.java     |  3 ++-
 .../apache/log4j/chainsaw/TableColorizingRenderer.java |  2 +-
 .../org/apache/log4j/chainsaw/helper/SwingHelper.java  |  3 ++-
 .../chainsaw/receivers/PluginPropertyEditorPanel.java  |  2 +-
 10 files changed, 30 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
index b96d052..7dd5d56 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ApplicationPreferenceModelPanel.java
@@ -30,6 +30,7 @@ import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.Hashtable;
 
+import java.util.Locale;
 import javax.swing.BorderFactory;
 import javax.swing.Box;
 import javax.swing.BoxLayout;
@@ -187,7 +188,7 @@ public static void main(String[] args) {
       boolean useNewLookAndFeels = false;
       int j = 0;
       for (int i=0;i<lookAndFeels.length;i++) {
-        if (lookAndFeels[i].getClassName().toLowerCase().contains("nimbus")) {
+        if (lookAndFeels[i].getClassName().toLowerCase(Locale.ENGLISH).contains("nimbus")) {
             useNewLookAndFeels = true;
         } else {
             newLookAndFeels[j++] = lookAndFeels[i];
@@ -549,7 +550,7 @@ public static void main(String[] args) {
                       defaultPath = currentConfigurationPath.getPath();
                       //FileDialog will not navigate to this location unless we remove the prefixing protocol and slash
                       //at least on winxp
-                      if (defaultPath.toLowerCase().startsWith("file:\\")) {
+                      if (defaultPath.toLowerCase(Locale.ENGLISH).startsWith("file:\\")) {
                           defaultPath = defaultPath.substring("file:\\".length());
                       }
                   }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
index 719094f..4871e39 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ChainsawCyclicBufferTableModel.java
@@ -27,6 +27,7 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -601,11 +602,11 @@ class ChainsawCyclicBufferTableModel extends AbstractTableModel
         //case may not match..try case sensitive and fall back to case-insensitive
         String result = event.getProperty(columnNames.get(columnIndex).toString());
         if (result == null) {
-            String lowerColName = columnNames.get(columnIndex).toString().toLowerCase();
+            String lowerColName = columnNames.get(columnIndex).toString().toLowerCase(Locale.ENGLISH);
             Set entrySet = event.getProperties().entrySet();
             for (Iterator iter = entrySet.iterator();iter.hasNext();) {
                 Map.Entry thisEntry = (Map.Entry) iter.next();
-                if (thisEntry.getKey().toString().toLowerCase().equals(lowerColName)) {
+                if (thisEntry.getKey().toString().equalsIgnoreCase(lowerColName)) {
                     result = thisEntry.getValue().toString();
                 }
             }
@@ -785,7 +786,7 @@ class ChainsawCyclicBufferTableModel extends AbstractTableModel
    * @see javax.swing.table.TableModel#isCellEditable(int, int)
    */
   public boolean isCellEditable(int rowIndex, int columnIndex) {
-    if (getColumnName(columnIndex).toLowerCase().equals(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE)) {
+    if (getColumnName(columnIndex).equalsIgnoreCase(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE)) {
       return true;
     }
 

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java b/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
index 9fe7a55..fc7feb3 100644
--- a/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
+++ b/src/main/java/org/apache/log4j/chainsaw/FileSaveAction.java
@@ -30,6 +30,7 @@ import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
@@ -103,7 +104,7 @@ class FileSaveAction extends AbstractAction {
 
     XMLLayout layout = new XMLLayout();
     layout.setProperties(true);
-    boolean saveAsZip = selectedFile.getName().toLowerCase().endsWith(".zip");
+    boolean saveAsZip = selectedFile.getName().toLowerCase(Locale.ENGLISH).endsWith(".zip");
     Writer writer = null;
     try {
       if (saveAsZip) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
index cd5a016..0112818 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogFilePatternLayoutBuilder.java
@@ -25,6 +25,7 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 
@@ -191,7 +192,7 @@ public class LogFilePatternLayoutBuilder
         Map.Entry appenderEntry = (Map.Entry)iter.next();
         String appenderName = appenderEntry.getKey().toString();
         String appenderClassName = appenderEntry.getValue().toString();
-        if (appenderClassName.toLowerCase().endsWith("fileappender")) {
+        if (appenderClassName.toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
           String layout = props.getProperty(appenderPrefix + "." + appenderName + ".layout");
           if (layout != null && layout.trim().equals("org.apache.log4j.PatternLayout")) {
             String conversion = props.getProperty(appenderPrefix + "." + appenderName + ".layout.ConversionPattern");
@@ -247,7 +248,7 @@ public class LogFilePatternLayoutBuilder
         if (appenderAttributes.getNamedItem("name") != null && appenderClass != null && appenderClass.getNodeValue() != null) {
           //all log4j fileappenders end in fileappender..if a custom fileappender also ends in fileappender and uses the same dom nodes to be loaded,
           //try to parse the nodes as well
-          if (appenderClass.getNodeValue().toLowerCase().endsWith("fileappender")) {
+          if (appenderClass.getNodeValue().toLowerCase(Locale.ENGLISH).endsWith("fileappender")) {
             String appenderName = appenderAttributes.getNamedItem("name").getNodeValue();
             //subclass of FileAppender - add it
             Map entry = new HashMap();
@@ -256,23 +257,23 @@ public class LogFilePatternLayoutBuilder
               Node appenderChild = appenderChildren.item(j);
               if (appenderChild.getNodeName().equals("param") && appenderChild.hasAttributes()) {
                 Node fileNameNode = appenderChild.getAttributes().getNamedItem("name");
-                if (fileNameNode != null && fileNameNode.getNodeValue().toLowerCase().equals("file")) {
+                if (fileNameNode != null && fileNameNode.getNodeValue().equalsIgnoreCase("file")) {
                   Node fileValueNode = appenderChild.getAttributes().getNamedItem("value");
                   if (fileValueNode != null) {
                     entry.put("file", fileValueNode.getNodeValue());
                   }
                 }
               }
-              if (appenderChild.getNodeName().toLowerCase().equals("layout") && appenderChild.hasAttributes()) {
+              if (appenderChild.getNodeName().equalsIgnoreCase("layout") && appenderChild.hasAttributes()) {
                 NamedNodeMap layoutAttributes = appenderChild.getAttributes();
                 Node layoutNode = layoutAttributes.getNamedItem("class");
-                if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equals("org.apache.log4j.PatternLayout")) {
+                if (layoutNode != null && layoutNode.getNodeValue() != null && layoutNode.getNodeValue().equalsIgnoreCase("org.apache.log4j.PatternLayout")) {
                   NodeList layoutChildren = appenderChild.getChildNodes();
                   for (int k = 0; k < layoutChildren.getLength(); k++) {
                     Node layoutChild = layoutChildren.item(k);
                     if (layoutChild.getNodeName().equals("param") && layoutChild.hasAttributes()) {
                       Node layoutName = layoutChild.getAttributes().getNamedItem("name");
-                      if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().toLowerCase().equals("conversionpattern")) {
+                      if (layoutName != null && layoutName.getNodeValue() != null && layoutName.getNodeValue().equalsIgnoreCase("conversionpattern")) {
                         Node conversionValue = layoutChild.getAttributes().getNamedItem("value");
                         if (conversionValue != null) {
                           entry.put("conversion", conversionValue.getNodeValue());

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
index 4173b21..aef99d7 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogPanel.java
@@ -67,6 +67,7 @@ import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.StringTokenizer;
@@ -532,7 +533,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
         		}
             for (Iterator iter = preferenceModel.getVisibleColumnOrder().iterator();iter.hasNext();) {
               TableColumn c = (TableColumn)iter.next();
-              if (c.getHeaderValue().toString().toLowerCase().equals(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE))
+              if (c.getHeaderValue().toString().equalsIgnoreCase(ChainsawConstants.LOG4J_MARKER_COL_NAME_LOWERCASE))
               {
                 c.setCellEditor(markerCellEditor);
               }
@@ -4321,7 +4322,7 @@ public class LogPanel extends DockablePanel implements EventBatchListener, Profi
                 List entriesCopy = new ArrayList(allEntries);
                 for (Iterator iter = entriesCopy.iterator();iter.hasNext();) {
                     String thisEntry = iter.next().toString();
-                    if (thisEntry.toLowerCase().contains(textToMatch.toLowerCase())) {
+                    if (thisEntry.toLowerCase(Locale.ENGLISH).contains(textToMatch.toLowerCase())) {
                         model.addElement(thisEntry);
                     }
                 }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/LogUI.java b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
index c62efe0..e99760e 100644
--- a/src/main/java/org/apache/log4j/chainsaw/LogUI.java
+++ b/src/main/java/org/apache/log4j/chainsaw/LogUI.java
@@ -52,6 +52,7 @@ import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 
@@ -290,12 +291,12 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
           String lookAndFeelClassName = model.getLookAndFeelClassName();
           if (lookAndFeelClassName == null || lookAndFeelClassName.trim().equals("")) {
               String osName = System.getProperty("os.name");
-              if (osName.toLowerCase().startsWith("mac")) {
+              if (osName.toLowerCase(Locale.ENGLISH).startsWith("mac")) {
                   //no need to assign look and feel
-              } else if (osName.toLowerCase().startsWith("windows")) {
+              } else if (osName.toLowerCase(Locale.ENGLISH).startsWith("windows")) {
                   lookAndFeelClassName = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
                   model.setLookAndFeelClassName(lookAndFeelClassName);
-              } else if (osName.toLowerCase().startsWith("linux")) {
+              } else if (osName.toLowerCase(Locale.ENGLISH).startsWith("linux")) {
                   lookAndFeelClassName = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
                   model.setLookAndFeelClassName(lookAndFeelClassName);
               }
@@ -1453,7 +1454,7 @@ public class LogUI extends JFrame implements ChainsawViewer, SettingsListener {
             for (Iterator iter = plugins.iterator();iter.hasNext();) {
                 Plugin plugin = (Plugin)iter.next();
                 //don't stop ZeroConfPlugin if it is registered
-                if (!plugin.getName().toLowerCase().contains("zeroconf")) {
+                if (!plugin.getName().toLowerCase(Locale.ENGLISH).contains("zeroconf")) {
                   pluginRegistry.stopPlugin(plugin.getName());
                 }
             }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
index c755963..e99fca4 100644
--- a/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/ReceiverConfigurationPanel.java
@@ -34,6 +34,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.util.List;
 
+import java.util.Locale;
 import javax.swing.AbstractAction;
 import javax.swing.BorderFactory;
 import javax.swing.ButtonGroup;
@@ -809,7 +810,7 @@ class ReceiverConfigurationPanel extends JPanel {
 
         boolean isPatternLayoutLogFormat() {
             Object item = logFileFormatTypeComboBox.getSelectedItem();
-            return item != null && item.toString().toLowerCase().contains("patternlayout");
+            return item != null && item.toString().toLowerCase(Locale.ENGLISH).contains("patternlayout");
         }
 
         String getLogFormatTimestampFormat() {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
index bd3a921..cb6f15b 100644
--- a/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
+++ b/src/main/java/org/apache/log4j/chainsaw/TableColorizingRenderer.java
@@ -400,7 +400,7 @@ public class TableColorizingRenderer extends DefaultTableCellRenderer {
         //find the property in the property set...case-sensitive
         for (Iterator iter = propertySet.iterator();iter.hasNext();) {
             String entry = iter.next().toString();
-            if (entry.toLowerCase().equals(headerName)) {
+            if (entry.equalsIgnoreCase(headerName)) {
                 thisProp = entry;
                 break;
             }

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
index 239a8bc..3eab190 100644
--- a/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
+++ b/src/main/java/org/apache/log4j/chainsaw/helper/SwingHelper.java
@@ -30,6 +30,7 @@ import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
 
+import java.util.Locale;
 import javax.swing.AbstractAction;
 import javax.swing.Action;
 import javax.swing.InputMap;
@@ -92,7 +93,7 @@ public final class SwingHelper {
   }
 
   public static boolean isMacOSX() {
-    return System.getProperty("os.name").toLowerCase().startsWith("mac os x");
+    return System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("mac os x");
   }
 
   public static List orderOKCancelButtons(JButton okButton, JButton cancelButton) {

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/11e4448b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
index c543216..23d76db 100644
--- a/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
+++ b/src/main/java/org/apache/log4j/chainsaw/receivers/PluginPropertyEditorPanel.java
@@ -349,7 +349,7 @@ public class PluginPropertyEditorPanel extends JPanel {
 
             if (columnIndex == 1) {
                 //ensure name is set
-                if (descriptors[rowIndex].getName().toLowerCase().equals("name") && (aValue == null || aValue.toString().trim().equals(""))) {
+                if (descriptors[rowIndex].getName().equalsIgnoreCase("name") && (aValue == null || aValue.toString().trim().equals(""))) {
                     logger.error("Name required");
                     return;
                 }


[35/50] [abbrv] logging-chainsaw git commit: Moved component and receivers companion sources to the Chainsaw source tree - those companions won't be released.

Posted by rg...@apache.org.
http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
new file mode 100644
index 0000000..cd37dc4
--- /dev/null
+++ b/src/main/java/org/apache/log4j/net/XMLSocketReceiver.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.net;
+
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.util.List;
+import java.util.Vector;
+
+import org.apache.log4j.plugins.Pauseable;
+import org.apache.log4j.plugins.Plugin;
+import org.apache.log4j.plugins.Receiver;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggingEvent;
+
+
+/**
+  XMLSocketReceiver receives a remote logging event via XML on a configured
+  socket and "posts" it to a LoggerRepository as if the event were
+  generated locally. This class is designed to receive events from
+  the XMLSocketAppender class (or classes that send compatible events).
+  <p>
+  This receiver supports log files created using log4j's XMLLayout, as well as java.util.logging
+  XMLFormatter (via the org.apache.log4j.spi.Decoder interface).
+  <p>
+  By default, log4j's XMLLayout is supported (no need to specify a decoder in that case).
+  <p>
+  To configure this receiver to support java.util.logging's XMLFormatter, specify a 'decoder' param
+  of org.apache.log4j.xml.UtilLoggingXMLDecoder.
+  <p>
+  Once the event has been "posted", it will be handled by the
+  appenders currently configured in the LoggerRespository.
+
+  @author Mark Womack
+  @author Scott Deboy <sd...@apache.org>
+
+*/
+public class XMLSocketReceiver extends Receiver implements Runnable, PortBased, Pauseable {
+  private boolean paused;
+  //default to log4j xml decoder
+  protected String decoder = "org.apache.log4j.xml.XMLDecoder";
+  private ServerSocket serverSocket;
+  private List socketList = new Vector();
+  private Thread rThread;
+  public static final int DEFAULT_PORT = 4448;
+  protected int port = DEFAULT_PORT;
+  private boolean advertiseViaMulticastDNS;
+  private ZeroConfSupport zeroConf;
+
+  /**
+   * The MulticastDNS zone advertised by an XMLSocketReceiver
+   */
+  public static final String ZONE = "_log4j_xml_tcpaccept_receiver.local.";
+
+  /*
+   * Log4j doesn't provide an XMLSocketAppender, but the MulticastDNS zone that should be advertised by one is:
+   * _log4j_xml_tcpconnect_appender.local.
+   */
+
+  public XMLSocketReceiver() {
+  }
+
+  public XMLSocketReceiver(int _port) {
+    port = _port;
+  }
+
+  public XMLSocketReceiver(int _port, LoggerRepository _repository) {
+    port = _port;
+    repository = _repository;
+  }
+
+  /**
+    Get the port to receive logging events on. */
+  public int getPort() {
+    return port;
+  }
+
+  /**
+    Set the port to receive logging events on. */
+  public void setPort(int _port) {
+    port = _port;
+  }
+
+  public String getDecoder() {
+    return decoder;
+  }
+
+  /**
+   *Specify the class name implementing org.apache.log4j.spi.Decoder that can process the file.
+   */
+  public void setDecoder(String _decoder) {
+    decoder = _decoder;
+  }
+
+  public boolean isPaused() {
+    return paused;
+  }
+
+  public void setPaused(boolean b) {
+    paused = b;
+  }
+
+  /**
+   * Returns true if the receiver is the same class and they are
+   * configured for the same properties, and super class also considers
+   * them to be equivalent. This is used by PluginRegistry when determining
+   * if the a similarly configured receiver is being started.
+   * 
+   * @param testPlugin The plugin to test equivalency against.
+   * @return boolean True if the testPlugin is equivalent to this plugin.
+   */
+  public boolean isEquivalent(Plugin testPlugin) {
+    if ((testPlugin != null) && testPlugin instanceof XMLSocketReceiver) {
+      XMLSocketReceiver sReceiver = (XMLSocketReceiver) testPlugin;
+
+      return (port == sReceiver.getPort() && super.isEquivalent(testPlugin));
+    }
+
+    return false;
+  }
+
+  public int hashCode() {
+  	
+  	int result = 37 * (repository != null? repository.hashCode():0);
+  	result = result * 37 + port;
+  	return (result * 37 + (getName() != null? getName().hashCode():0));
+  }
+
+  /**
+    Sets the flag to indicate if receiver is active or not.
+   @param b new value
+   */
+  protected synchronized void setActive(final boolean b) {
+    active = b;
+  }
+
+  /**
+    Starts the SocketReceiver with the current options. */
+  public void activateOptions() {
+    if (!isActive()) {
+      rThread = new Thread(this);
+      rThread.setDaemon(true);
+      rThread.start();
+
+      if (advertiseViaMulticastDNS) {
+        zeroConf = new ZeroConfSupport(ZONE, port, getName());
+        zeroConf.advertise();
+      }
+
+      active = true;
+    }
+  }
+
+  public void setAdvertiseViaMulticastDNS(boolean advertiseViaMulticastDNS) {
+    this.advertiseViaMulticastDNS = advertiseViaMulticastDNS;
+  }
+
+  public boolean isAdvertiseViaMulticastDNS() {
+    return advertiseViaMulticastDNS;
+  }
+
+  /**
+    Called when the receiver should be stopped. Closes the
+    server socket and all of the open sockets. */
+  public synchronized void shutdown() {
+    // mark this as no longer running
+    active = false;
+
+    if (rThread != null) {
+      rThread.interrupt();
+      rThread = null;
+    }
+    doShutdown();
+  }
+
+    /**
+     * Does the actual shutting down by closing the server socket
+     * and any connected sockets that have been created.
+     */
+    private synchronized void doShutdown() {
+      active = false;
+
+      getLogger().debug("{} doShutdown called", getName());
+
+      // close the server socket
+      closeServerSocket();
+
+      // close all of the accepted sockets
+      closeAllAcceptedSockets();
+
+      if (advertiseViaMulticastDNS) {
+          zeroConf.unadvertise();
+      }
+    }
+
+    /**
+      * Closes the server socket, if created.
+      */
+     private void closeServerSocket() {
+       getLogger().debug("{} closing server socket", getName());
+
+       try {
+         if (serverSocket != null) {
+           serverSocket.close();
+         }
+       } catch (Exception e) {
+         // ignore for now
+       }
+
+       serverSocket = null;
+     }
+
+    /**
+      * Closes all the connected sockets in the List.
+      */
+     private synchronized void closeAllAcceptedSockets() {
+       for (int x = 0; x < socketList.size(); x++) {
+         try {
+           ((Socket) socketList.get(x)).close();
+         } catch (Exception e) {
+           // ignore for now
+         }
+       }
+
+       // clear member variables
+       socketList.clear();
+     }
+
+  /**
+    Loop, accepting new socket connections. */
+  public void run() {
+      /**
+        * Ensure we start fresh.
+        */
+    getLogger().debug("performing socket cleanup prior to entering loop for {}",  name);
+    closeServerSocket();
+    closeAllAcceptedSockets();
+    getLogger().debug("socket cleanup complete for {}", name);       
+    active = true;
+
+    // start the server socket
+    try {
+      serverSocket = new ServerSocket(port);
+    } catch (Exception e) {
+      getLogger().error(
+        "error starting SocketReceiver (" + this.getName()
+        + "), receiver did not start", e);
+      active = false;
+      doShutdown();
+
+      return;
+    }
+
+    Socket socket = null;
+
+    try {
+      getLogger().debug("in run-about to enter while isactiveloop");
+
+      active = true;
+
+      while (!rThread.isInterrupted()) {
+        // if we have a socket, start watching it
+        if (socket != null) {
+          getLogger().debug("socket not null - creating and starting socketnode");
+          socketList.add(socket);
+
+          XMLSocketNode node = new XMLSocketNode(decoder, socket, this);
+          node.setLoggerRepository(this.repository);
+          new Thread(node).start();
+          socket = null;
+        }
+
+        getLogger().debug("waiting to accept socket");
+
+        // wait for a socket to open, then loop to start it
+        socket = serverSocket.accept();
+        getLogger().debug("accepted socket");
+      }
+
+      // socket not watched because we a no longer running
+      // so close it now.
+      if (socket != null) {
+        socket.close();
+      }
+    } catch (Exception e) {
+      getLogger().warn(
+        "socket server disconnected, stopping");
+    }
+  }
+
+  /* (non-Javadoc)
+   * @see org.apache.log4j.plugins.Receiver#doPost(org.apache.log4j.spi.LoggingEvent)
+   */
+  public void doPost(LoggingEvent event) {
+    if(!isPaused()){
+      super.doPost(event);
+    }
+  }
+
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Pauseable.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Pauseable.java b/src/main/java/org/apache/log4j/plugins/Pauseable.java
new file mode 100644
index 0000000..6268ba3
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Pauseable.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+
+/**
+ * Instances of this interface can be paused, and resumed.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ *
+ */
+public interface Pauseable {
+    /**
+     * Set paused state.
+     * @param paused new value
+     */
+  void setPaused(boolean paused);
+
+    /**
+     * Get paused state.
+     * @return paused state.
+     */
+  boolean isPaused();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Plugin.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Plugin.java b/src/main/java/org/apache/log4j/plugins/Plugin.java
new file mode 100644
index 0000000..e1b6a6f
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Plugin.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.OptionHandler;
+
+import java.beans.PropertyChangeListener;
+
+
+/**
+ * Defines the required interface for all Plugin objects.
+ * <p/>
+ * <p>A plugin implements some specific functionality to extend
+ * the log4j framework.  Each plugin is associated with a specific
+ * LoggerRepository, which it then uses/acts upon.  The functionality
+ * of the plugin is up to the developer.
+ * <p/>
+ * <p>Examples of plugins are Receiver and Watchdog. Receiver plugins
+ * allow for remote logging events to be received and processed by
+ * a repository as if the event was sent locally. Watchdog plugins
+ * allow for a repository to be reconfigured when some "watched"
+ * configuration data changes.
+ *
+ * @author Mark Womack (mwomack@apache.org)
+ * @author Nicko Cadell
+ * @author Paul Smith (psmith@apache.org)
+ */
+public interface Plugin extends OptionHandler {
+    /**
+     * Gets the name of the plugin.
+     *
+     * @return String the name of the plugin.
+     */
+    String getName();
+
+    /**
+     * Sets the name of the plugin.
+     *
+     * @param name the name of the plugin.
+     */
+    void setName(String name);
+
+    /**
+     * Gets the logger repository for this plugin.
+     *
+     * @return the logger repository to which this plugin is attached.
+     */
+    LoggerRepository getLoggerRepository();
+
+    /**
+     * Sets the logger repository used by this plugin. This
+     * repository will be used by the plugin functionality.
+     *
+     * @param repository the logger repository to attach this plugin to.
+     */
+    void setLoggerRepository(LoggerRepository repository);
+
+    /**
+     * Adds a PropertyChangeListener to this instance which is
+     * notified only by changes of the property with name propertyName.
+     *
+     * @param propertyName
+     *    the name of the property in standard JavaBean syntax
+     *    (e.g. for setName(), property="name")
+     * @param l listener
+     */
+    void addPropertyChangeListener(
+            String propertyName, PropertyChangeListener l);
+
+    /**
+     * Adds a PropertyChangeListener that will be notified of all property
+     * changes.
+     *
+     * @param l The listener to add.
+     */
+    void addPropertyChangeListener(PropertyChangeListener l);
+
+    /**
+     * Removes a specific PropertyChangeListener from this instances
+     * registry that has been mapped to be notified of all property
+     * changes.
+     *
+     * @param l The listener to remove.
+     */
+    void removePropertyChangeListener(PropertyChangeListener l);
+
+    /**
+     * Removes a specific PropertyChangeListener from this instance's
+     * registry which has been previously registered to be notified
+     * of only a specific property change.
+     *
+     * @param propertyName property name, may not be null.
+     * @param l listener to be removed.
+     */
+    void removePropertyChangeListener(
+            String propertyName, PropertyChangeListener l);
+
+    /**
+     * True if the plugin is active and running.
+     *
+     * @return boolean true if the plugin is currently active.
+     */
+    boolean isActive();
+
+    /**
+     * Returns true if the testPlugin is considered to be "equivalent" to the
+     * this plugin.  The equivalency test is at the discretion of the plugin
+     * implementation.  The PluginRegistry will use this method when starting
+     * new plugins to see if a given plugin is considered equivalent to an
+     * already running plugin with the same name.  If they are considered to
+     * be equivalent, the currently running plugin will be left in place, and
+     * the new plugin will not be started.
+     * <p/>
+     * It is possible to override the equals() method, however this has
+     * more meaning than is required for this simple test and would also
+     * require the overriding of the hashCode() method as well.  All of this
+     * is more work than is needed, so this simple method is used instead.
+     *
+     * @param testPlugin The plugin to test equivalency against.
+     * @return Returns true if testPlugin is considered to be equivelent.
+     */
+    boolean isEquivalent(Plugin testPlugin);
+
+    /**
+     * Call when the plugin should be stopped.
+     */
+    void shutdown();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginEvent.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginEvent.java b/src/main/java/org/apache/log4j/plugins/PluginEvent.java
new file mode 100644
index 0000000..1843034
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginEvent.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+import java.util.EventObject;
+
+
+/**
+ * All Plugin events are encapsulated in this class, which
+ * simply contains the source Plugin, but may in future include more
+ * information.
+ *
+ * @author Paul Smith
+ */
+public class PluginEvent extends EventObject {
+    /**
+     * @param source The source plugin of the event
+     */
+    PluginEvent(final Plugin source) {
+        super(source);
+    }
+
+    /**
+     * Returns the source Plugin of this event, which is simple
+     * the getSource() method casted to Plugin for convenience.
+     *
+     * @return Plugin source of this event
+     */
+    public Plugin getPlugin() {
+        return (Plugin) getSource();
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginListener.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginListener.java b/src/main/java/org/apache/log4j/plugins/PluginListener.java
new file mode 100644
index 0000000..11f628e
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginListener.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ */
+package org.apache.log4j.plugins;
+
+import java.util.EventListener;
+
+
+/**
+ * PluginListeners are notified when plugins are started or stopped
+ * by the PluginRegistry.
+ *
+ * @author Paul Smith (psmith@apache.org)
+ */
+public interface PluginListener extends EventListener {
+    /**
+     * Notification that plugin has started.
+     * @param e event
+     */
+  void pluginStarted(PluginEvent e);
+
+    /**
+     * Notification that plugin has stopped.
+     * @param e event
+     */
+  void pluginStopped(PluginEvent e);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginRegistry.java b/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
new file mode 100644
index 0000000..d34f885
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginRegistry.java
@@ -0,0 +1,303 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.plugins;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.spi.LoggerRepositoryEx;
+import org.apache.log4j.spi.LoggerRepositoryEventListener;
+
+
+/**
+ * This is a registry for Plugin instances. It provides methods to
+ * start and stop plugin objects individually and to stop all
+ * plugins for a repository.
+ *
+ * @author Mark Womack
+ * @author Paul Smith
+ */
+public final class PluginRegistry {
+    /**
+     * The pluginMap is keyed by plugin name and contains plugins as values.
+     * key=plugin.getName, value=plugin
+     */
+    private final Map pluginMap;
+    /**
+     * Logger repository.
+     */
+    private final LoggerRepositoryEx loggerRepository;
+
+    /**
+     * the listener used to listen for repository events.
+     */
+    private final RepositoryListener listener = new RepositoryListener();
+    /**
+     * List of listeners.
+     */
+    private final List listenerList =
+            Collections.synchronizedList(new ArrayList());
+
+    /**
+     * Creates a new instance.
+     * @param repository logger repository.
+     */
+    public PluginRegistry(final LoggerRepositoryEx repository) {
+        super();
+        pluginMap = new HashMap();
+        this.loggerRepository = repository;
+        this.loggerRepository.addLoggerRepositoryEventListener(listener);
+    }
+
+    /**
+     * Get logger repository.
+     * @return logger repository.
+     */
+    public LoggerRepositoryEx getLoggerRepository() {
+        return loggerRepository;
+    }
+
+
+    /**
+     * Returns true if the specified name is already taken by
+     * an existing Plugin registered within the scope of the specified
+     * LoggerRepository.
+     *
+     * @param name The name to check the repository for
+     * @return true if the name is already in use, otherwise false
+     */
+    public boolean pluginNameExists(final String name) {
+        synchronized (pluginMap) {
+            return pluginMap.containsKey(name);
+        }
+    }
+
+
+    /**
+     * Adds a plugin to the plugin registry.
+     * If a plugin with the same name exists
+     * already, it is shutdown and removed.
+     *
+     * @param plugin the plugin to add.
+     */
+    public void addPlugin(final Plugin plugin) {
+        // put plugin into the repository's reciever map
+        synchronized (pluginMap) {
+            String name = plugin.getName();
+
+            // make sure the plugin has reference to repository
+            plugin.setLoggerRepository(getLoggerRepository());
+
+            Plugin existingPlugin = (Plugin) pluginMap.get(name);
+            if (existingPlugin != null) {
+                existingPlugin.shutdown();
+            }
+
+            // put the new plugin into the map
+            pluginMap.put(name, plugin);
+            firePluginStarted(plugin);
+        }
+    }
+
+
+    /**
+     * Calls the pluginStarted method on every registered PluginListener.
+     *
+     * @param plugin The plugin that has been started.
+     */
+    private void firePluginStarted(final Plugin plugin) {
+        PluginEvent e = null;
+        synchronized (listenerList) {
+            for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+                PluginListener l = (PluginListener) iter.next();
+                if (e == null) {
+                    e = new PluginEvent(plugin);
+                }
+                l.pluginStarted(e);
+            }
+        }
+    }
+
+
+    /**
+     * Calls the pluginStopped method for every registered PluginListner.
+     *
+     * @param plugin The plugin that has been stopped.
+     */
+    private void firePluginStopped(final Plugin plugin) {
+        PluginEvent e = null;
+        synchronized (listenerList) {
+            for (Iterator iter = listenerList.iterator(); iter.hasNext();) {
+                PluginListener l = (PluginListener) iter.next();
+                if (e == null) {
+                    e = new PluginEvent(plugin);
+                }
+                l.pluginStopped(e);
+            }
+        }
+    }
+
+
+    /**
+     * Returns all the plugins for a given repository.
+     *
+     * @return List list of plugins from the repository.
+     */
+    public List getPlugins() {
+        synchronized (pluginMap) {
+            List pluginList = new ArrayList(pluginMap.size());
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                pluginList.add(iter.next());
+            }
+            return pluginList;
+        }
+    }
+
+
+    /**
+     * Returns all the plugins for a given repository that are instances
+     * of a certain class.
+     *
+     * @param pluginClass the class the plugin must implement to be selected.
+     * @return List list of plugins from the repository.
+     */
+    public List getPlugins(final Class pluginClass) {
+        synchronized (pluginMap) {
+            List pluginList = new ArrayList(pluginMap.size());
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                Object plugin = iter.next();
+
+                if (pluginClass.isInstance(plugin)) {
+                    pluginList.add(plugin);
+                }
+            }
+            return pluginList;
+        }
+    }
+
+
+    /**
+     * Stops a plugin by plugin name and repository.
+     *
+     * @param pluginName the name of the plugin to stop.
+     * @return Plugin the plugin, if stopped, or null if the
+     *         the plugin was not found in the registry.
+     */
+    public Plugin stopPlugin(final String pluginName) {
+        synchronized (pluginMap) {
+            Plugin plugin = (Plugin) pluginMap.get(pluginName);
+
+            if (plugin == null) {
+                return null;
+            }
+
+            // shutdown the plugin
+            plugin.shutdown();
+
+            // remove it from the plugin map
+            pluginMap.remove(pluginName);
+            firePluginStopped(plugin);
+
+            // return it for future use
+            return plugin;
+        }
+    }
+
+    /**
+     * Stops all plugins in the given logger repository.
+     */
+    public void stopAllPlugins() {
+        synchronized (pluginMap) {
+            // remove the listener for this repository
+            loggerRepository.removeLoggerRepositoryEventListener(listener);
+
+            Iterator iter = pluginMap.values().iterator();
+
+            while (iter.hasNext()) {
+                Plugin plugin = (Plugin) iter.next();
+                plugin.shutdown();
+                firePluginStopped(plugin);
+            }
+        }
+    }
+
+
+    /**
+     * Adds a PluginListener to this registry to be notified
+     * of PluginEvents.
+     *
+     * @param l PluginListener to add to this registry
+     */
+    public void addPluginListener(final PluginListener l) {
+        listenerList.add(l);
+    }
+
+
+    /**
+     * Removes a particular PluginListener from this registry
+     * such that it will no longer be notified of PluginEvents.
+     *
+     * @param l PluginListener to remove
+     */
+    public void removePluginListener(final PluginListener l) {
+        listenerList.remove(l);
+    }
+
+    /**
+     * Internal class used to handle listener events from repositories.
+     */
+    private class RepositoryListener implements LoggerRepositoryEventListener {
+        /**
+         * Stops all plugins associated with the repository being reset.
+         *
+         * @param repository the repository that was reset.
+         */
+        public void configurationResetEvent(final LoggerRepository repository) {
+            PluginRegistry.this.stopAllPlugins();
+        }
+
+
+        /**
+         * Called when the repository configuration is changed.
+         *
+         * @param repository the repository that was changed.
+         */
+        public void configurationChangedEvent(
+                final LoggerRepository repository) {
+            // do nothing with this event
+        }
+
+
+        /**
+         * Stops all plugins associated with the repository being shutdown.
+         *
+         * @param repository the repository being shutdown.
+         */
+        public void shutdownEvent(final LoggerRepository repository) {
+            PluginRegistry.this.stopAllPlugins();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java b/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
new file mode 100644
index 0000000..2660473
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/PluginSkeleton.java
@@ -0,0 +1,222 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+import org.apache.log4j.spi.ComponentBase;
+import org.apache.log4j.spi.LoggerRepository;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyChangeSupport;
+
+
+/**
+ * A convienent abstract class for plugin subclasses that implements
+ * the basic methods of the Plugin interface. Subclasses are required
+ * to implement the isActive(), activateOptions(), and shutdown()
+ * methods.
+ * <p/>
+ * <p>Developers are not required to subclass PluginSkeleton to
+ * develop their own plugins (they are only required to implement the
+ * Plugin interface), but it provides a convenient base class to start
+ * from.
+ * <p/>
+ * Contributors: Nicko Cadell
+ *
+ * @author Mark Womack (mwomack@apache.org)
+ * @author Paul Smith (psmith@apache.org)
+ */
+public abstract class PluginSkeleton extends ComponentBase implements Plugin {
+    /**
+     * Name of this plugin.
+     */
+    protected String name = "plugin";
+
+    /**
+     * Active state of plugin.
+     */
+    protected boolean active;
+
+    /**
+     * This is a delegate that does all the PropertyChangeListener
+     * support.
+     */
+    private PropertyChangeSupport propertySupport =
+            new PropertyChangeSupport(this);
+
+    /**
+     * Construct new instance.
+     */
+    protected PluginSkeleton() {
+        super();
+    }
+
+    /**
+     * Gets the name of the plugin.
+     *
+     * @return String the name of the plugin.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the name of the plugin and notifies
+     * PropertyChangeListeners of the change.
+     *
+     * @param newName the name of the plugin to set.
+     */
+    public void setName(final String newName) {
+        String oldName = this.name;
+        this.name = newName;
+        propertySupport.firePropertyChange("name", oldName, this.name);
+    }
+
+    /**
+     * Gets the logger repository for this plugin.
+     *
+     * @return LoggerRepository the logger repository this plugin will affect.
+     */
+    public LoggerRepository getLoggerRepository() {
+        return repository;
+    }
+
+    /**
+     * Sets the logger repository used by this plugin and notifies a
+     * relevant PropertyChangeListeners registered. This
+     * repository will be used by the plugin functionality.
+     *
+     * @param repository the logger repository that this plugin should affect.
+     */
+    public void setLoggerRepository(final LoggerRepository repository) {
+        Object oldValue = this.repository;
+        this.repository = repository;
+        firePropertyChange("loggerRepository", oldValue, this.repository);
+    }
+
+    /**
+     * Returns whether this plugin is Active or not.
+     *
+     * @return true/false
+     */
+    public synchronized boolean isActive() {
+        return active;
+    }
+
+    /**
+     * Returns true if the plugin has the same name and logger repository as the
+     * testPlugin passed in.
+     *
+     * @param testPlugin The plugin to test equivalency against.
+     * @return Returns true if testPlugin is considered to be equivalent.
+     */
+    public boolean isEquivalent(final Plugin testPlugin) {
+        return (repository == testPlugin.getLoggerRepository())
+                && ((this.name == null && testPlugin.getName() == null)
+                || (this.name != null
+                           && name.equals(testPlugin.getName())))
+                && this.getClass().equals(testPlugin.getClass());
+    }
+
+    /**
+     * Add property change listener.
+     * @param listener listener.
+     */
+    public final void addPropertyChangeListener(
+            final PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(listener);
+    }
+
+    /**
+     * Add property change listener for one property only.
+     * @param propertyName property name.
+     * @param listener listener.
+     */
+    public final void addPropertyChangeListener(
+            final String propertyName,
+            final PropertyChangeListener listener) {
+        propertySupport.addPropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * Remove property change listener.
+     * @param listener listener.
+     */
+    public final void removePropertyChangeListener(
+            final PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(listener);
+    }
+
+    /**
+     * Remove property change listener on a specific property.
+     * @param propertyName property name.
+     * @param listener listener.
+     */
+    public final void removePropertyChangeListener(
+            final String propertyName,
+            final PropertyChangeListener listener) {
+        propertySupport.removePropertyChangeListener(propertyName, listener);
+    }
+
+    /**
+     * Fire a property change event to appropriate listeners.
+     * @param evt change event.
+     */
+    protected final void firePropertyChange(
+            final PropertyChangeEvent evt) {
+        propertySupport.firePropertyChange(evt);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final boolean oldValue,
+            final boolean newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final int oldValue, final int newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+
+    /**
+     * Fire property change event to appropriate listeners.
+     * @param propertyName property name.
+     * @param oldValue old value.
+     * @param newValue new value.
+     */
+    protected final void firePropertyChange(
+            final String propertyName,
+            final Object oldValue,
+            final Object newValue) {
+        propertySupport.firePropertyChange(propertyName, oldValue, newValue);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/plugins/Receiver.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/plugins/Receiver.java b/src/main/java/org/apache/log4j/plugins/Receiver.java
new file mode 100644
index 0000000..d78ae59
--- /dev/null
+++ b/src/main/java/org/apache/log4j/plugins/Receiver.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.plugins;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.Thresholdable;
+
+
+/**
+ * Defines the base class for Receiver plugins.
+ * <p/>
+ * <p>Just as Appenders send logging events outside of the log4j
+ * environment (to files, to smtp, to sockets, etc), Receivers bring
+ * logging events inside the log4j environment.
+ * <p/>
+ * <p>Receivers are meant to support the receiving of
+ * remote logging events from another process. For example,
+ * SocketAppender "appends" a logging event to a socket, configured
+ * for a specific host and port number.  On the receiving side of
+ * the socket can be a SocketReceiver object.  The SocketReceiver
+ * object receives the logging event, and then "posts" it to the
+ * log4j environment (LoggerRepository) on the receiving machine, to
+ * be handled by the configured appenders, etc.  The various
+ * settings in this environment (Logger levels, Appender filters &
+ * thresholds) are applied to the received logging event.
+ * <p/>
+ * <p>Receivers can also be used to "import" log messages from other
+ * logging packages into the log4j environment.
+ * <p/>
+ * <p>Receivers can be configured to post events to a given
+ * LoggerRepository.
+ * <p/>
+ * <p>Subclasses of Receiver must implement the isActive(),
+ * activateOptions(), and shutdown() methods. The doPost() method
+ * is provided to standardize the "import" of remote events into
+ * the repository.
+ *
+ * @author Mark Womack
+ * @author Ceki G&uuml;lc&uuml;
+ * @author Paul Smith (psmith@apache.org)
+ */
+public abstract class Receiver extends PluginSkeleton implements Thresholdable {
+    /**
+     * Threshold level.
+     */
+    protected Level thresholdLevel;
+
+    /**
+     * Create new instance.
+     */
+    protected Receiver() {
+        super();
+    }
+
+    /**
+     * Sets the receiver theshold to the given level.
+     *
+     * @param level The threshold level events must equal or be greater
+     *              than before further processing can be done.
+     */
+    public void setThreshold(final Level level) {
+        Level oldValue = this.thresholdLevel;
+        thresholdLevel = level;
+        firePropertyChange("threshold", oldValue, this.thresholdLevel);
+    }
+
+    /**
+     * Gets the current threshold setting of the receiver.
+     *
+     * @return Level The current threshold level of the receiver.
+     */
+    public Level getThreshold() {
+        return thresholdLevel;
+    }
+
+    /**
+     * Returns true if the given level is equals or greater than the current
+     * threshold value of the receiver.
+     *
+     * @param level The level to test against the receiver threshold.
+     * @return boolean True if level is equal or greater than the
+     *         receiver threshold.
+     */
+    public boolean isAsSevereAsThreshold(final Level level) {
+        return ((thresholdLevel == null)
+                || level.isGreaterOrEqual(thresholdLevel));
+    }
+
+    /**
+     * Posts the logging event to a logger in the configured logger
+     * repository.
+     *
+     * @param event the log event to post to the local log4j environment.
+     */
+    public void doPost(final LoggingEvent event) {
+        // if event does not meet threshold, exit now
+        if (!isAsSevereAsThreshold(event.getLevel())) {
+            return;
+        }
+
+        // get the "local" logger for this event from the
+        // configured repository.
+        Logger localLogger =
+                getLoggerRepository().getLogger(event.getLoggerName());
+
+        // if the logger level is greater or equal to the level
+        // of the event, use the logger to append the event.
+        if (event.getLevel()
+                .isGreaterOrEqual(localLogger.getEffectiveLevel())) {
+            // call the loggers appenders to process the event
+            localLogger.callAppenders(event);
+        }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
new file mode 100644
index 0000000..4fca465
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/MapRewritePolicy.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events where the message of the
+ * original event implementes java.util.Map.
+ * All other events are passed through unmodified.
+ * If the map contains a "message" entry, the value will be
+ * used as the message for the rewritten event.  The rewritten
+ * event will have a property set that is the combination of the
+ * original property set and the other members of the message map.
+ * If both the original property set and the message map
+ * contain the same entry, the value from the message map
+ * will overwrite the original property set.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the MapFilter from log4j 1.3. 
+ */
+public class MapRewritePolicy implements RewritePolicy {
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        Object msg = source.getMessage();
+        if (msg instanceof Map) {
+            Map props = new HashMap(source.getProperties());
+            Map eventProps = (Map) msg;
+            //
+            //   if the map sent in the logging request
+            //      has "message" entry, use that as the message body
+            //      otherwise, use the entire map.
+            //
+            Object newMsg = eventProps.get("message");
+            if (newMsg == null) {
+                newMsg = msg;
+            }
+
+            for(Iterator iter = eventProps.entrySet().iterator();
+                    iter.hasNext();
+                  ) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                if (!("message".equals(entry.getKey()))) {
+                    props.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            return new LoggingEvent(
+                    source.getFQNOfLoggerClass(),
+                    source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()), 
+                    source.getTimeStamp(),
+                    source.getLevel(),
+                    newMsg,
+                    source.getThreadName(),
+                    source.getThrowableInformation(),
+                    source.getNDC(),
+                    source.getLocationInformation(),
+                    props);
+        } else {
+            return source;
+        }
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
new file mode 100644
index 0000000..535736c
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/PropertyRewritePolicy.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events by adding
+ * a user-specified list of properties to the event.
+ * Existing properties are not modified.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the PropertyFilter from log4j 1.3.
+ */
+
+public class PropertyRewritePolicy implements RewritePolicy {
+    private Map properties = Collections.EMPTY_MAP;
+    public PropertyRewritePolicy() {
+    }
+
+    /**
+     * Set a string representing the property name/value pairs.
+     * 
+     * Form: propname1=propvalue1,propname2=propvalue2
+     * 
+     * @param props
+     */
+    public void setProperties(String props) {
+        Map hashTable = new HashMap();
+        StringTokenizer pairs = new StringTokenizer(props, ",");
+        while (pairs.hasMoreTokens()) {
+            StringTokenizer entry = new StringTokenizer(pairs.nextToken(), "=");
+            hashTable.put(entry.nextElement().toString().trim(), entry.nextElement().toString().trim());
+        }
+        synchronized(this) {
+            properties = hashTable;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        if (!properties.isEmpty()) {
+            Map rewriteProps = new HashMap(source.getProperties());
+            for(Iterator iter = properties.entrySet().iterator();
+                    iter.hasNext();
+                    ) {
+                Map.Entry entry = (Map.Entry) iter.next();
+                if (!rewriteProps.containsKey(entry.getKey())) {
+                    rewriteProps.put(entry.getKey(), entry.getValue());
+                }
+            }
+
+            return new LoggingEvent(
+                    source.getFQNOfLoggerClass(),
+                    source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()), 
+                    source.getTimeStamp(),
+                    source.getLevel(),
+                    source.getMessage(),
+                    source.getThreadName(),
+                    source.getThrowableInformation(),
+                    source.getNDC(),
+                    source.getLocationInformation(),
+                    rewriteProps);
+        }
+        return source;
+    }
+
+
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
new file mode 100644
index 0000000..f1a4cc5
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/ReflectionRewritePolicy.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * This policy rewrites events by evaluating any
+ * JavaBean properties on the message object and adding them
+ * to the event properties.  If the message object has a
+ * message property, the value of that property will be
+ * used as the message for the rewritten event and will
+ * not be added to the event properties.  Values from the
+ * JavaBean properties will replace any existing property
+ * with the same name.
+ *
+ * The combination of the RewriteAppender and this policy
+ * performs the same actions as the ReflectionFilter from log4j 1.3. 
+ */
+public class ReflectionRewritePolicy implements RewritePolicy {
+    /**
+     * {@inheritDoc}
+     */
+    public LoggingEvent rewrite(final LoggingEvent source) {
+        Object msg = source.getMessage();
+        if (!(msg instanceof String)) {
+            Object newMsg = msg;
+            Map rewriteProps = new HashMap(source.getProperties());
+
+            try {
+                PropertyDescriptor[] props = Introspector.getBeanInfo(
+                        msg.getClass(), Object.class).getPropertyDescriptors();
+                if (props.length > 0) {
+                    for (int i=0;i<props.length;i++) {
+                        try {
+                            Object propertyValue =
+                                props[i].getReadMethod().invoke(msg,
+                                        (Object[]) null);
+                            if ("message".equalsIgnoreCase(props[i].getName())) {
+                                newMsg = propertyValue;
+                            } else {
+                                rewriteProps.put(props[i].getName(), propertyValue);
+                            }
+                        } catch (Exception e) {
+                            LogLog.warn("Unable to evaluate property " +
+                                    props[i].getName(), e);
+                        }
+                    }
+                    return new LoggingEvent(
+                            source.getFQNOfLoggerClass(),
+                            source.getLogger() != null ? source.getLogger(): Logger.getLogger(source.getLoggerName()),
+                            source.getTimeStamp(),
+                            source.getLevel(),
+                            newMsg,
+                            source.getThreadName(),
+                            source.getThrowableInformation(),
+                            source.getNDC(),
+                            source.getLocationInformation(),
+                            rewriteProps);
+                }
+            } catch (Exception e) {
+                LogLog.warn("Unable to get property descriptors", e);
+            }
+
+        }
+        return source;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java b/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
new file mode 100644
index 0000000..368ecf9
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/RewriteAppender.java
@@ -0,0 +1,199 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.helpers.AppenderAttachableImpl;
+import org.apache.log4j.spi.AppenderAttachable;
+import org.apache.log4j.spi.LoggingEvent;
+import org.apache.log4j.spi.OptionHandler;
+import org.apache.log4j.xml.UnrecognizedElementHandler;
+import org.w3c.dom.Element;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * This appender forwards a logging request to another
+ * appender after possibly rewriting the logging event.
+ *
+ * This appender (with the appropriate policy)
+ * replaces the MapFilter, PropertyFilter and ReflectionFilter
+ * from log4j 1.3.
+ */
+public class RewriteAppender extends AppenderSkeleton
+     implements AppenderAttachable, UnrecognizedElementHandler {
+    /**
+     * Rewrite policy.
+     */
+    private RewritePolicy policy;
+    /**
+     * Nested appenders.
+     */
+    private final AppenderAttachableImpl appenders;
+
+    public RewriteAppender() {
+        appenders = new AppenderAttachableImpl();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void append(final LoggingEvent event) {
+        LoggingEvent rewritten = event;
+        if (policy != null) {
+            rewritten = policy.rewrite(event);
+        }
+        if (rewritten != null) {
+            synchronized (appenders) {
+              appenders.appendLoopOnAppenders(rewritten);
+            }
+        }
+    }
+
+    /**
+     * Add appender.
+     *
+     * @param newAppender appender to add, may not be null.
+     */
+    public void addAppender(final Appender newAppender) {
+      synchronized (appenders) {
+        appenders.addAppender(newAppender);
+      }
+    }
+
+    /**
+     * Get iterator over attached appenders.
+     * @return iterator or null if no attached appenders.
+     */
+    public Enumeration getAllAppenders() {
+      synchronized (appenders) {
+        return appenders.getAllAppenders();
+      }
+    }
+
+    /**
+     * Get appender by name.
+     *
+     * @param name name, may not be null.
+     * @return matching appender or null.
+     */
+    public Appender getAppender(final String name) {
+      synchronized (appenders) {
+        return appenders.getAppender(name);
+      }
+    }
+
+
+    /**
+     * Close this <code>AsyncAppender</code> by interrupting the dispatcher
+     * thread which will process all pending events before exiting.
+     */
+    public void close() {
+      closed = true;
+      //
+      //    close all attached appenders.
+      //
+      synchronized (appenders) {
+        Enumeration iter = appenders.getAllAppenders();
+
+        if (iter != null) {
+          while (iter.hasMoreElements()) {
+            Object next = iter.nextElement();
+
+            if (next instanceof Appender) {
+              ((Appender) next).close();
+            }
+          }
+        }
+      }
+    }
+
+    /**
+     * Determines if specified appender is attached.
+     * @param appender appender.
+     * @return true if attached.
+     */
+    public boolean isAttached(final Appender appender) {
+      synchronized (appenders) {
+        return appenders.isAttached(appender);
+      }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean requiresLayout() {
+      return false;
+    }
+
+    /**
+     * Removes and closes all attached appenders.
+     */
+    public void removeAllAppenders() {
+      synchronized (appenders) {
+        appenders.removeAllAppenders();
+      }
+    }
+
+    /**
+     * Removes an appender.
+     * @param appender appender to remove.
+     */
+    public void removeAppender(final Appender appender) {
+      synchronized (appenders) {
+        appenders.removeAppender(appender);
+      }
+    }
+
+    /**
+     * Remove appender by name.
+     * @param name name.
+     */
+    public void removeAppender(final String name) {
+      synchronized (appenders) {
+        appenders.removeAppender(name);
+      }
+    }
+
+
+    public void setRewritePolicy(final RewritePolicy rewritePolicy) {
+        policy = rewritePolicy;
+    }
+    /**
+     * {@inheritDoc}
+     */
+    public boolean parseUnrecognizedElement(final Element element,
+                                            final Properties props) throws Exception {
+        final String nodeName = element.getNodeName();
+        if ("rewritePolicy".equals(nodeName)) {
+            Object rewritePolicy =
+                    org.apache.log4j.xml.DOMConfigurator.parseElement(
+                            element, props, RewritePolicy.class);
+            if (rewritePolicy != null) {
+                if (rewritePolicy instanceof OptionHandler) {
+                    ((OptionHandler) rewritePolicy).activateOptions();
+                }
+                this.setRewritePolicy((RewritePolicy) rewritePolicy);
+            }
+            return true;
+        }
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java b/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
new file mode 100644
index 0000000..bb40507
--- /dev/null
+++ b/src/main/java/org/apache/log4j/rewrite/RewritePolicy.java
@@ -0,0 +1,37 @@
+package org.apache.log4j.rewrite;
+
+import org.apache.log4j.spi.LoggingEvent;
+
+/*
+* Licensed to the Apache Software Foundation (ASF) under one or more
+* contributor license agreements.  See the NOTICE file distributed with
+* this work for additional information regarding copyright ownership.
+* The ASF licenses this file to You under the Apache License, Version 2.0
+* (the "License"); you may not use this file except in compliance with
+* the License.  You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+/**
+ * This interface is implemented to provide a rewrite
+ * strategy for RewriteAppender.  RewriteAppender will
+ * call the rewrite method with a source logging event.
+ * The strategy may return that event, create a new event
+ * or return null to suppress the logging request.
+ */
+public interface RewritePolicy {
+    /**
+     * Rewrite a logging event.
+     * @param source a logging event that may be returned or
+     * used to create a new logging event.
+     * @return a logging event or null to suppress processing.
+     */
+    LoggingEvent rewrite(final LoggingEvent source);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/scheduler/Job.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/scheduler/Job.java b/src/main/java/org/apache/log4j/scheduler/Job.java
new file mode 100644
index 0000000..a0e9be4
--- /dev/null
+++ b/src/main/java/org/apache/log4j/scheduler/Job.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.scheduler;
+
+
+/**
+ * Job is a very simple interface. It only has a single method {@link #execute}
+ * which is called by the {@link Scheduler} when a task is ready for execution.
+ * <p/>
+ * It is assumed that the execution context
+ * are contained within the implementing
+ * {@link Job} itself.
+ *
+ * @author Ceki G&uuml;lc&uuml;
+ */
+public interface Job {
+    /**
+     * Execute job.
+     */
+    void execute();
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/scheduler/Scheduler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/scheduler/Scheduler.java b/src/main/java/org/apache/log4j/scheduler/Scheduler.java
new file mode 100644
index 0000000..72809f7
--- /dev/null
+++ b/src/main/java/org/apache/log4j/scheduler/Scheduler.java
@@ -0,0 +1,307 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.scheduler;
+
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * A simple but still useful implementation of a Scheduler (in memory only).
+ * <p/>
+ * This implementation will work very well when the number of scheduled job is
+ * small, say less than 100 jobs. If a larger number of events need to be
+ * scheduled, than a better adapted data structure for the jobList can give
+ * improved performance.
+ *
+ * @author Ceki
+ */
+public class Scheduler extends Thread {
+
+    /**
+     * Job list.
+     */
+    List jobList;
+    /**
+     * If set true, scheduler has or should shut down.
+     */
+    boolean shutdown = false;
+
+    /**
+     * Create new instance.
+     */
+    public Scheduler() {
+        super();
+        jobList = new Vector();
+    }
+
+    /**
+     * Find the index of a given job.
+     * @param job job
+     * @return -1 if the job could not be found.
+     */
+    int findIndex(final Job job) {
+        int size = jobList.size();
+        boolean found = false;
+
+        int i = 0;
+        for (; i < size; i++) {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.get(i);
+            if (se.job == job) {
+                found = true;
+                break;
+            }
+        }
+        if (found) {
+            return i;
+        } else {
+            return -1;
+        }
+    }
+
+    /**
+     * Delete the given job.
+     * @param job job.
+     * @return true if the job could be deleted, and
+     * false if the job could not be found or if the Scheduler is about to
+     * shutdown in which case deletions are not permitted.
+     */
+    public synchronized boolean delete(final Job job) {
+        // if already shutdown in the process of shutdown, there is no
+        // need to remove Jobs as they will never be executed.
+        if (shutdown) {
+            return false;
+        }
+        int i = findIndex(job);
+        if (i != -1) {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.remove(i);
+            if (se.job != job) { // this should never happen
+                new IllegalStateException("Internal programming error");
+            }
+            // if the job is the first on the list,
+            // then notify the scheduler thread to schedule a new job
+            if (i == 0) {
+                this.notifyAll();
+            }
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Schedule a {@link Job} for execution at system time given by
+     * the <code>desiredTime</code> parameter.
+     * @param job job to schedule.
+     * @param desiredTime desired time of execution.
+     */
+    public synchronized void schedule(final Job job,
+                                      final long desiredTime) {
+        schedule(new ScheduledJobEntry(job, desiredTime));
+    }
+
+    /**
+     * Schedule a {@link Job} for execution at system time given by
+     * the <code>desiredTime</code> parameter.
+     * <p/>
+     * The job will be rescheduled. It will execute with a frequency determined
+     * by the period parameter.
+     * @param job job to schedule.
+     * @param desiredTime desired time of execution.
+     * @param period repeat period.
+     */
+    public synchronized void schedule(final Job job,
+                                      final long desiredTime,
+                                      final long period) {
+        schedule(new ScheduledJobEntry(job, desiredTime, period));
+    }
+
+    /**
+     * Change the period of a job. The original job must exist for its period
+     * to be changed.
+     * <p/>
+     * The method returns true if the period could be changed, and false
+     * otherwise.
+     * @param job job.
+     * @param newPeriod new repeat period.
+     * @return true if period could be changed.
+     */
+    public synchronized boolean changePeriod(final Job job,
+                                             final long newPeriod) {
+        if (newPeriod <= 0) {
+            throw new IllegalArgumentException(
+                    "Period must be an integer langer than zero");
+        }
+
+        int i = findIndex(job);
+        if (i == -1) {
+            return false;
+        } else {
+            ScheduledJobEntry se = (ScheduledJobEntry) jobList.get(i);
+            se.period = newPeriod;
+            return true;
+        }
+    }
+
+    /**
+     * Schedule a job.
+     * @param newSJE new job entry.
+     */
+    private synchronized void schedule(final ScheduledJobEntry newSJE) {
+        // disallow new jobs after shutdown
+        if (shutdown) {
+            return;
+        }
+        int max = jobList.size();
+        long desiredExecutionTime = newSJE.desiredExecutionTime;
+
+        // find the index i such that timeInMillis < jobList[i]
+        int i = 0;
+        for (; i < max; i++) {
+
+            ScheduledJobEntry sje = (ScheduledJobEntry) jobList.get(i);
+
+            if (desiredExecutionTime < sje.desiredExecutionTime) {
+                break;
+            }
+        }
+        jobList.add(i, newSJE);
+        // if the jobList was empty, then notify the scheduler thread
+        if (i == 0) {
+            this.notifyAll();
+        }
+    }
+
+    /**
+     * Shut down scheduler.
+     */
+    public synchronized void shutdown() {
+        shutdown = true;
+    }
+
+    /**
+     * Run scheduler.
+     */
+    public synchronized void run() {
+        while (!shutdown) {
+            if (jobList.isEmpty()) {
+                linger();
+            } else {
+                ScheduledJobEntry sje = (ScheduledJobEntry) jobList.get(0);
+                long now = System.currentTimeMillis();
+                if (now >= sje.desiredExecutionTime) {
+                    executeInABox(sje.job);
+                    jobList.remove(0);
+                    if (sje.period > 0) {
+                        sje.desiredExecutionTime = now + sje.period;
+                        schedule(sje);
+                    }
+                } else {
+                    linger(sje.desiredExecutionTime - now);
+                }
+            }
+        }
+        // clear out the job list to facilitate garbage collection
+        jobList.clear();
+        jobList = null;
+        System.out.println("Leaving scheduler run method");
+    }
+
+    /**
+     * We do not want a single failure to affect the whole scheduler.
+     * @param job job to execute.
+     */
+    void executeInABox(final Job job) {
+        try {
+            job.execute();
+        } catch (Exception e) {
+            System.err.println("The execution of the job threw an exception");
+            e.printStackTrace(System.err);
+        }
+    }
+
+    /**
+     * Wait for notification.
+     */
+    void linger() {
+        try {
+            while (jobList.isEmpty() && !shutdown) {
+                this.wait();
+            }
+        } catch (InterruptedException ie) {
+            shutdown = true;
+        }
+    }
+
+    /**
+     * Wait for notification or time to elapse.
+     * @param timeToLinger time to linger.
+     */
+    void linger(final long timeToLinger) {
+        try {
+            this.wait(timeToLinger);
+        } catch (InterruptedException ie) {
+            shutdown = true;
+        }
+    }
+
+    /**
+     * Represents an entry in job scheduler.
+     */
+    static final class ScheduledJobEntry {
+        /**
+         * Desired execution time.
+         */
+        long desiredExecutionTime;
+        /**
+         * Job to run.
+         */
+        Job job;
+        /**
+         * Repeat period.
+         */
+        long period = 0;
+
+        /**
+         * Create new instance.
+         * @param job job
+         * @param desiredTime desired time.
+         */
+        ScheduledJobEntry(final Job job, final long desiredTime) {
+            this(job, desiredTime, 0);
+        }
+
+        /**
+         * Create new instance.
+         * @param job job
+         * @param desiredTime desired time
+         * @param period repeat period
+         */
+        ScheduledJobEntry(final Job job,
+                          final long desiredTime,
+                          final long period) {
+            super();
+            this.desiredExecutionTime = desiredTime;
+            this.job = job;
+            this.period = period;
+        }
+    }
+
+}
+
+

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Component.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Component.java b/src/main/java/org/apache/log4j/spi/Component.java
new file mode 100644
index 0000000..42ef29a
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Component.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+
+/**
+ * A common interface shared by log4j components.
+ *
+ * @author Ceki Gulcu
+ */
+public interface Component {
+
+
+    /**
+     * Set owning logger repository for this component. This operation can
+     * only be performed once.
+     * Once set, a subsequent attempt will throw an IllegalStateException.
+     *
+     * @param repository The repository where this appender is attached.
+     */
+    void setLoggerRepository(LoggerRepository repository);
+
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/ComponentBase.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/ComponentBase.java b/src/main/java/org/apache/log4j/spi/ComponentBase.java
new file mode 100644
index 0000000..78932f7
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/ComponentBase.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.log4j.spi;
+
+import org.apache.log4j.ULogger;
+import org.apache.log4j.Logger;
+
+
+/**
+ * Most log4j components derive from this class.
+ *
+ * @author Ceki Gulcu
+ */
+public class ComponentBase implements Component {
+
+    /**
+     * Error count limit.
+     */
+    private static final int ERROR_COUNT_LIMIT = 3;
+
+    /**
+     * Logger repository.
+     */
+    protected LoggerRepository repository;
+    /**
+     * Logger.
+     */
+    private ULogger logger;
+    /**
+     * Error count.
+     */
+    private int errorCount = 0;
+
+    /**
+     * Construct a new instance.
+     */
+    protected ComponentBase() {
+        super();
+    }
+
+
+    /**
+     * Called by derived classes when they deem that the component has recovered
+     * from an erroneous state.
+     */
+    protected void resetErrorCount() {
+        errorCount = 0;
+    }
+
+    /**
+     * Set the owning repository. The owning repository cannot be set more than
+     * once.
+     *
+     * @param repository repository
+     */
+    public void setLoggerRepository(final LoggerRepository repository) {
+        if (this.repository == null) {
+            this.repository = repository;
+        } else if (this.repository != repository) {
+            throw new IllegalStateException("Repository has been already set");
+        }
+    }
+
+    /**
+     * Return the LoggerRepository to which this component is attached.
+     *
+     * @return Owning LoggerRepository
+     */
+    protected LoggerRepository getLoggerRepository() {
+        return repository;
+    }
+
+    /**
+     * Return an instance specific logger to be used by the component itself.
+     * This logger is not intended to be accessed by the end-user, hence the
+     * protected keyword.
+     * <p/>
+     * <p>In case the repository for this component is not set,
+     * this implementations returns a {@link SimpleULogger} instance.
+     *
+     * @return A ULogger instance.
+     */
+    protected ULogger getLogger() {
+        if (logger == null) {
+            if (repository != null) {
+                Logger l = repository.getLogger(this.getClass().getName());
+                if (l instanceof ULogger) {
+                    logger = (ULogger) l;
+                } else {
+                    logger = new Log4JULogger(l);
+                }
+            } else {
+                logger = SimpleULogger.getLogger(this.getClass().getName());
+            }
+        }
+        return logger;
+    }
+
+    /**
+     * Frequently called methods in log4j components can invoke this method in
+     * order to avoid flooding the output when logging lasting error conditions.
+     *
+     * @return a regular logger, or a NOPLogger if called too frequently.
+     */
+    protected ULogger getNonFloodingLogger() {
+        if (errorCount++ >= ERROR_COUNT_LIMIT) {
+            return NOPULogger.NOP_LOGGER;
+        } else {
+            return getLogger();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/Decoder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/Decoder.java b/src/main/java/org/apache/log4j/spi/Decoder.java
new file mode 100644
index 0000000..d4686ad
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/Decoder.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+
+import java.io.IOException;
+
+import java.net.URL;
+
+import java.util.Map;
+import java.util.Vector;
+
+
+/**
+ *  Allow LoggingEvents to be reconstructed from a different format
+ * (usually XML).
+ *
+ *  @author Scott Deboy (sdeboy@apache.org)
+ */
+public interface Decoder {
+    /**
+     * Decode events from document.
+     * @param document document to decode.
+     * @return list of LoggingEvent instances.
+     */
+  Vector decodeEvents(String document);
+
+    /**
+     * Decode event from string.
+     * @param event string representation of event
+     * @return event
+     */
+  LoggingEvent decode(String event);
+
+    /**
+     * Decode event from document retreived from URL.
+     * @param url url of document
+     * @return list of LoggingEvent instances.
+     * @throws IOException if IO error resolving document.
+     */
+  Vector decode(URL url) throws IOException;
+
+    /**
+     * Sets additional properties.
+     * @param additionalProperties map of additional properties.
+     */
+  void setAdditionalProperties(Map additionalProperties);
+}

http://git-wip-us.apache.org/repos/asf/logging-chainsaw/blob/08c7be5c/src/main/java/org/apache/log4j/spi/ErrorItem.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/log4j/spi/ErrorItem.java b/src/main/java/org/apache/log4j/spi/ErrorItem.java
new file mode 100644
index 0000000..f6f3686
--- /dev/null
+++ b/src/main/java/org/apache/log4j/spi/ErrorItem.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.log4j.spi;
+
+import java.io.PrintStream;
+
+/**
+ * Used to store special log4j errors which cannot be logged using internal
+ * logging. Such errors include those occurring during the initial phases
+ * of log4j configuration or errors emanating from core components such as
+ * Logger or Hierarchy.
+ *
+ * @author Ceki Gulcu
+ */
+public class ErrorItem {
+    /**
+     * Message.
+     */
+  String message;
+    /**
+     * Column.
+     */
+  int colNumber = -1;
+    /**
+     * Line number.
+     */
+  int lineNumber = -1;
+    /**
+     * Exception.
+     */
+  Throwable exception;
+
+    /**
+     * Create new instance.
+     * @param message message
+     * @param e exception
+     */
+  public ErrorItem(final String message, final Exception e) {
+    super();
+    this.message = message;
+    exception = e;
+  }
+
+    /**
+     * Creaet new instance.
+     * @param message message.
+     */
+  public ErrorItem(final String message) {
+    this(message, null);
+  }
+
+    /**
+     * Get column number.
+     * @return column number.
+     */
+  public int getColNumber() {
+    return colNumber;
+  }
+
+    /**
+     * Set column number.
+     * @param colNumber new column number.
+     */
+  public void setColNumber(int colNumber) {
+    this.colNumber = colNumber;
+  }
+
+    /**
+     * Get exception.
+     * @return exception.
+     */
+  public Throwable getException() {
+    return exception;
+  }
+
+    /**
+     * Set exception.
+     * @param exception exception
+     */
+  public void setException(final Throwable exception) {
+    this.exception = exception;
+  }
+
+    /**
+     * Get line number.
+     * @return line number.
+     */
+  public int getLineNumber() {
+    return lineNumber;
+  }
+
+    /**
+     * Set line number.
+     * @param lineNumber line number.
+     */
+  public void setLineNumber(final int lineNumber) {
+    this.lineNumber = lineNumber;
+  }
+
+    /**
+     * Get message.
+     * @return message.
+     */
+  public String getMessage() {
+    return message;
+  }
+
+    /**
+     * Set message.
+     * @param message message.
+     */
+  public void setMessage(final String message) {
+    this.message = message;
+  }
+
+    /**
+     * String representation of ErrorItem.
+     * @return string.
+     */
+  public String toString() {
+    String str =
+      "Reported error: \"" + message + "\"";
+
+    if (lineNumber != -1) {
+      str += " at line " + lineNumber + " column " + colNumber;
+    }
+    if (exception != null) {
+      str += (" with exception " + exception);
+    }
+    return str;
+  }
+
+  /**
+   * Dump the details of this ErrorItem to System.out.
+   */
+  public void dump() {
+    dump(System.out);
+  }
+  
+  /**
+   * Dump the details of this ErrorItem on the specified {@link PrintStream}.
+   * @param ps print stream.
+   */
+  public void dump(final PrintStream ps) {
+    String str =
+      "Reported error: \"" + message + "\"";
+
+    if (lineNumber != -1) {
+      str += " at line " + lineNumber + " column " + colNumber;
+    }
+    ps.println(str);
+
+    if (exception != null) {
+      exception.printStackTrace(ps);
+    }
+  }
+}