logging-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From grobme...@apache.org
Subject svn commit: r1345492 [9/18] - in /logging/log4j/branches/log4j12modules: ./ contribs/ contribs/CekiGulcu/ contribs/EirikLygre/ contribs/JamesHouse/ contribs/Jamie Tsao/ contribs/JimMoore/ contribs/KevinSteppe/ contribs/KitchingSimon/ contribs/LeosLiter...
Date Sat, 02 Jun 2012 11:41:11 GMT
Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/LoggingReceiver.java.orig Sat Jun  2 11:40:31 2012
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+
+/**
+ * A daemon thread the processes connections from a
+ * <code>org.apache.log4j.net.SocketAppender.html</code>.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+class LoggingReceiver extends Thread {
+    /** used to log messages **/
+    private static final Logger LOG = Logger.getLogger(LoggingReceiver.class);
+
+    /**
+     * Helper that actually processes a client connection. It receives events
+     * and adds them to the supplied model.
+     *
+     * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+     */
+    private class Slurper implements Runnable {
+        /** socket connection to read events from **/
+        private final Socket mClient;
+
+        /**
+         * Creates a new <code>Slurper</code> instance.
+         *
+         * @param aClient socket to receive events from
+         */
+        Slurper(Socket aClient) {
+            mClient = aClient;
+        }
+
+        /** loops getting the events **/
+        public void run() {
+            LOG.debug("Starting to get data");
+            try {
+                final ObjectInputStream ois =
+                    new ObjectInputStream(mClient.getInputStream());
+                while (true) {
+                    final LoggingEvent event = (LoggingEvent) ois.readObject();
+                    mModel.addEvent(new EventDetails(event));
+                }
+            } catch (EOFException e) {
+                LOG.info("Reached EOF, closing connection");
+            } catch (SocketException e) {
+                LOG.info("Caught SocketException, closing connection");
+            } catch (IOException e) {
+                LOG.warn("Got IOException, closing connection", e);
+            } catch (ClassNotFoundException e) {
+                LOG.warn("Got ClassNotFoundException, closing connection", e);
+            }
+
+            try {
+                mClient.close();
+            } catch (IOException e) {
+                LOG.warn("Error closing connection", e);
+            }
+        }
+    }
+
+    /** where to put the events **/
+    private MyTableModel mModel;
+
+    /** server for listening for connections **/
+    private ServerSocket mSvrSock;
+    
+    /**
+     * Creates a new <code>LoggingReceiver</code> instance.
+     *
+     * @param aModel model to place put received into
+     * @param aPort port to listen on
+     * @throws IOException if an error occurs
+     */
+    LoggingReceiver(MyTableModel aModel, int aPort) throws IOException {
+        setDaemon(true);
+        mModel = aModel;
+        mSvrSock = new ServerSocket(aPort);
+    }
+
+    /** Listens for client connections **/
+    public void run() {
+        LOG.info("Thread started");
+        try {
+            while (true) {
+                LOG.debug("Waiting for a connection");
+                final Socket client = mSvrSock.accept();
+                LOG.debug("Got a connection from " +
+                          client.getInetAddress().getHostName());
+                final Thread t = new Thread(new Slurper(client));
+                t.setDaemon(true);
+                t.start();
+            }
+        } catch (IOException e) {
+            LOG.error("Error in accepting connections, stopping.", e);
+        }
+    }
+}

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java Sat Jun  2 11:40:31 2012
@@ -0,0 +1,192 @@
+/*
+ * 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;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.Properties;
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+/**
+ * The main application.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+public class Main
+    extends JFrame
+{
+    /** the default port number to listen on **/
+    private static final int DEFAULT_PORT = 4445;
+
+    /** name of property for port name **/
+    public static final String PORT_PROP_NAME = "chainsaw.port";
+
+    /** use to log messages **/
+    private static final Logger LOG = Logger.getLogger(Main.class);
+
+
+    /**
+     * Creates a new <code>Main</code> instance.
+     */
+    private Main() {
+        super("CHAINSAW - Log4J Log Viewer");
+        // create the all important model
+        final MyTableModel model = new MyTableModel();
+
+        //Create the menu bar.
+        final JMenuBar menuBar = new JMenuBar();
+        setJMenuBar(menuBar);
+        final JMenu menu = new JMenu("File");
+        menuBar.add(menu);
+
+        try {
+            final LoadXMLAction lxa = new LoadXMLAction(this, model);
+            final JMenuItem loadMenuItem = new JMenuItem("Load file...");
+            menu.add(loadMenuItem);
+            loadMenuItem.addActionListener(lxa);
+        } catch (NoClassDefFoundError e) {
+            LOG.info("Missing classes for XML parser", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "XML parser not in classpath - unable to load XML events.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+        } catch (Exception e) {
+            LOG.info("Unable to create the action to load XML files", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "Unable to create a XML parser - unable to load XML events.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+        }
+
+        final JMenuItem exitMenuItem = new JMenuItem("Exit");
+        menu.add(exitMenuItem);
+        exitMenuItem.addActionListener(ExitAction.INSTANCE);
+
+        // Add control panel
+        final ControlPanel cp = new ControlPanel(model);
+        getContentPane().add(cp, BorderLayout.NORTH);
+
+        // Create the table
+        final JTable table = new JTable(model);
+        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        final JScrollPane scrollPane = new JScrollPane(table);
+        scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
+        scrollPane.setPreferredSize(new Dimension(900, 300));
+
+        // Create the details
+        final JPanel details = new DetailPanel(table, model);
+        details.setPreferredSize(new Dimension(900, 300));
+
+        // Add the table and stack trace into a splitter
+        final JSplitPane jsp =
+            new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
+        getContentPane().add(jsp, BorderLayout.CENTER);
+
+        addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent aEvent) {
+                    ExitAction.INSTANCE.actionPerformed(null);
+                }
+            });
+
+        pack();
+        setVisible(true);
+
+        setupReceiver(model);
+    }
+
+    /**
+     * Setup recieving messages.
+     *
+     * @param aModel a <code>MyTableModel</code> value
+     */
+    private void setupReceiver(MyTableModel aModel) {
+        int port = DEFAULT_PORT;
+        final String strRep = System.getProperty(PORT_PROP_NAME);
+        if (strRep != null) {
+            try {
+                port = Integer.parseInt(strRep);
+            } catch (NumberFormatException nfe) {
+                LOG.fatal("Unable to parse " + PORT_PROP_NAME +
+                          " property with value " + strRep + ".");
+                JOptionPane.showMessageDialog(
+                    this,
+                    "Unable to parse port number from '" + strRep +
+                    "', quitting.",
+                    "CHAINSAW",
+                    JOptionPane.ERROR_MESSAGE);
+                System.exit(1);
+            }
+        }
+
+        try {
+            final LoggingReceiver lr = new LoggingReceiver(aModel, port);
+            lr.start();
+        } catch (IOException e) {
+            LOG.fatal("Unable to connect to socket server, quiting", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "Unable to create socket on port " + port + ", quitting.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+            System.exit(1);
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+    // static methods
+    ////////////////////////////////////////////////////////////////////////////
+
+
+    /** initialise log4j **/
+    private static void initLog4J() {
+        final Properties props = new Properties();
+        props.setProperty("log4j.rootLogger", "DEBUG, A1");
+        props.setProperty("log4j.appender.A1",
+                          "org.apache.log4j.ConsoleAppender");
+        props.setProperty("log4j.appender.A1.layout",
+                          "org.apache.log4j.TTCCLayout");
+        PropertyConfigurator.configure(props);
+    }
+
+    /**
+     * The main method.
+     *
+     * @param aArgs ignored
+     */
+    public static void main(String[] aArgs) {
+        initLog4J();
+        new Main();
+    }
+}

Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/Main.java.orig Sat Jun  2 11:40:31 2012
@@ -0,0 +1,192 @@
+/*
+ * 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;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.IOException;
+import java.util.Properties;
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+
+/**
+ * The main application.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+public class Main
+    extends JFrame
+{
+    /** the default port number to listen on **/
+    private static final int DEFAULT_PORT = 4445;
+
+    /** name of property for port name **/
+    public static final String PORT_PROP_NAME = "chainsaw.port";
+
+    /** use to log messages **/
+    private static final Logger LOG = Logger.getLogger(Main.class);
+
+
+    /**
+     * Creates a new <code>Main</code> instance.
+     */
+    private Main() {
+        super("CHAINSAW - Log4J Log Viewer");
+        // create the all important model
+        final MyTableModel model = new MyTableModel();
+
+        //Create the menu bar.
+        final JMenuBar menuBar = new JMenuBar();
+        setJMenuBar(menuBar);
+        final JMenu menu = new JMenu("File");
+        menuBar.add(menu);
+
+        try {
+            final LoadXMLAction lxa = new LoadXMLAction(this, model);
+            final JMenuItem loadMenuItem = new JMenuItem("Load file...");
+            menu.add(loadMenuItem);
+            loadMenuItem.addActionListener(lxa);
+        } catch (NoClassDefFoundError e) {
+            LOG.info("Missing classes for XML parser", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "XML parser not in classpath - unable to load XML events.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+        } catch (Exception e) {
+            LOG.info("Unable to create the action to load XML files", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "Unable to create a XML parser - unable to load XML events.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+        }
+
+        final JMenuItem exitMenuItem = new JMenuItem("Exit");
+        menu.add(exitMenuItem);
+        exitMenuItem.addActionListener(ExitAction.INSTANCE);
+
+        // Add control panel
+        final ControlPanel cp = new ControlPanel(model);
+        getContentPane().add(cp, BorderLayout.NORTH);
+
+        // Create the table
+        final JTable table = new JTable(model);
+        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+        final JScrollPane scrollPane = new JScrollPane(table);
+        scrollPane.setBorder(BorderFactory.createTitledBorder("Events: "));
+        scrollPane.setPreferredSize(new Dimension(900, 300));
+
+        // Create the details
+        final JPanel details = new DetailPanel(table, model);
+        details.setPreferredSize(new Dimension(900, 300));
+
+        // Add the table and stack trace into a splitter
+        final JSplitPane jsp =
+            new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPane, details);
+        getContentPane().add(jsp, BorderLayout.CENTER);
+
+        addWindowListener(new WindowAdapter() {
+                public void windowClosing(WindowEvent aEvent) {
+                    ExitAction.INSTANCE.actionPerformed(null);
+                }
+            });
+
+        pack();
+        setVisible(true);
+
+        setupReceiver(model);
+    }
+
+    /**
+     * Setup recieving messages.
+     *
+     * @param aModel a <code>MyTableModel</code> value
+     */
+    private void setupReceiver(MyTableModel aModel) {
+        int port = DEFAULT_PORT;
+        final String strRep = System.getProperty(PORT_PROP_NAME);
+        if (strRep != null) {
+            try {
+                port = Integer.parseInt(strRep);
+            } catch (NumberFormatException nfe) {
+                LOG.fatal("Unable to parse " + PORT_PROP_NAME +
+                          " property with value " + strRep + ".");
+                JOptionPane.showMessageDialog(
+                    this,
+                    "Unable to parse port number from '" + strRep +
+                    "', quitting.",
+                    "CHAINSAW",
+                    JOptionPane.ERROR_MESSAGE);
+                System.exit(1);
+            }
+        }
+
+        try {
+            final LoggingReceiver lr = new LoggingReceiver(aModel, port);
+            lr.start();
+        } catch (IOException e) {
+            LOG.fatal("Unable to connect to socket server, quiting", e);
+            JOptionPane.showMessageDialog(
+                this,
+                "Unable to create socket on port " + port + ", quitting.",
+                "CHAINSAW",
+                JOptionPane.ERROR_MESSAGE);
+            System.exit(1);
+        }
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+    // static methods
+    ////////////////////////////////////////////////////////////////////////////
+
+
+    /** initialise log4j **/
+    private static void initLog4J() {
+        final Properties props = new Properties();
+        props.setProperty("log4j.rootLogger", "DEBUG, A1");
+        props.setProperty("log4j.appender.A1",
+                          "org.apache.log4j.ConsoleAppender");
+        props.setProperty("log4j.appender.A1.layout",
+                          "org.apache.log4j.TTCCLayout");
+        PropertyConfigurator.configure(props);
+    }
+
+    /**
+     * The main method.
+     *
+     * @param aArgs ignored
+     */
+    public static void main(String[] aArgs) {
+        initLog4J();
+        new Main();
+    }
+}

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java Sat Jun  2 11:40:31 2012
@@ -0,0 +1,390 @@
+/*
+ * 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;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.swing.table.AbstractTableModel;
+import org.apache.log4j.Priority;
+import org.apache.log4j.Logger;
+
+/**
+ * Represents a list of <code>EventDetails</code> objects that are sorted on
+ * logging time. Methods are provided to filter the events that are visible.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+class MyTableModel
+    extends AbstractTableModel
+{
+
+    /** used to log messages **/
+    private static final Logger LOG = Logger.getLogger(MyTableModel.class);
+
+    /** use the compare logging events **/
+    private static final Comparator MY_COMP = new Comparator()
+    {
+        /** @see Comparator **/
+        public int compare(Object aObj1, Object aObj2) {
+            if ((aObj1 == null) && (aObj2 == null)) {
+                return 0; // treat as equal
+            } else if (aObj1 == null) {
+                return -1; // null less than everything
+            } else if (aObj2 == null) {
+                return 1; // think about it. :->
+            }
+
+            // will assume only have LoggingEvent
+            final EventDetails le1 = (EventDetails) aObj1;
+            final EventDetails le2 = (EventDetails) aObj2;
+
+            if (le1.getTimeStamp() < le2.getTimeStamp()) {
+                return 1;
+            }
+            // assume not two events are logged at exactly the same time
+            return -1;
+        }
+        };
+
+    /**
+     * Helper that actually processes incoming events.
+     * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+     */
+    private class Processor
+        implements Runnable
+    {
+        /** loops getting the events **/
+        public void run() {
+            while (true) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+
+                synchronized (mLock) {
+                    if (mPaused) {
+                        continue;
+                    }
+
+                    boolean toHead = true; // were events added to head
+                    boolean needUpdate = false;
+                    final Iterator it = mPendingEvents.iterator();
+                    while (it.hasNext()) {
+                        final EventDetails event = (EventDetails) it.next();
+                        mAllEvents.add(event);
+                        toHead = toHead && (event == mAllEvents.first());
+                        needUpdate = needUpdate || matchFilter(event);
+                    }
+                    mPendingEvents.clear();
+
+                    if (needUpdate) {
+                        updateFilteredEvents(toHead);
+                    }
+                }
+            }
+
+        }
+    }
+
+
+    /** names of the columns in the table **/
+    private static final String[] COL_NAMES = {
+        "Time", "Priority", "Trace", "Category", "NDC", "Message"};
+
+    /** definition of an empty list **/
+    private static final EventDetails[] EMPTY_LIST =  new EventDetails[] {};
+
+    /** used to format dates **/
+    private static final DateFormat DATE_FORMATTER =
+        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
+
+    /** the lock to control access **/
+    private final Object mLock = new Object();
+    /** set of all logged events - not filtered **/
+    private final SortedSet mAllEvents = new TreeSet(MY_COMP);
+    /** events that are visible after filtering **/
+    private EventDetails[] mFilteredEvents = EMPTY_LIST;
+    /** list of events that are buffered for processing **/
+    private final List mPendingEvents = new ArrayList();
+    /** indicates whether event collection is paused to the UI **/
+    private boolean mPaused = false;
+
+    /** filter for the thread **/
+    private String mThreadFilter = "";
+    /** filter for the message **/
+    private String mMessageFilter = "";
+    /** filter for the NDC **/
+    private String mNDCFilter = "";
+    /** filter for the category **/
+    private String mCategoryFilter = "";
+    /** filter for the priority **/
+    private Priority mPriorityFilter = Priority.DEBUG;
+
+
+    /**
+     * Creates a new <code>MyTableModel</code> instance.
+     *
+     */
+    MyTableModel() {
+        final Thread t = new Thread(new Processor());
+        t.setDaemon(true);
+        t.start();
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Table Methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /** @see javax.swing.table.TableModel **/
+    public int getRowCount() {
+        synchronized (mLock) {
+            return mFilteredEvents.length;
+        }
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public int getColumnCount() {
+        // does not need to be synchronized
+        return COL_NAMES.length;
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public String getColumnName(int aCol) {
+        // does not need to be synchronized
+        return COL_NAMES[aCol];
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public Class getColumnClass(int aCol) {
+        // does not need to be synchronized
+        return (aCol == 2) ? Boolean.class : Object.class;
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public Object getValueAt(int aRow, int aCol) {
+        synchronized (mLock) {
+            final EventDetails event = mFilteredEvents[aRow];
+
+            if (aCol == 0) {
+                return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
+            } else if (aCol == 1) {
+                return event.getPriority();
+            } else if (aCol == 2) {
+                return (event.getThrowableStrRep() == null)
+                    ? Boolean.FALSE : Boolean.TRUE;
+            } else if (aCol == 3) {
+                return event.getCategoryName();
+            } else if (aCol == 4) {
+                return event.getNDC();
+            }
+            return event.getMessage();
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Public Methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Sets the priority to filter events on. Only events of equal or higher
+     * property are now displayed.
+     *
+     * @param aPriority the priority to filter on
+     */
+    public void setPriorityFilter(Priority aPriority) {
+        synchronized (mLock) {
+            mPriorityFilter = aPriority;
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the thread field.
+     *
+     * @param aStr the string to match
+     */
+    public void setThreadFilter(String aStr) {
+        synchronized (mLock) {
+            mThreadFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the message field.
+     *
+     * @param aStr the string to match
+     */
+    public void setMessageFilter(String aStr) {
+        synchronized (mLock) {
+            mMessageFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the NDC field.
+     *
+     * @param aStr the string to match
+     */
+    public void setNDCFilter(String aStr) {
+        synchronized (mLock) {
+            mNDCFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the category field.
+     *
+     * @param aStr the string to match
+     */
+    public void setCategoryFilter(String aStr) {
+        synchronized (mLock) {
+            mCategoryFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Add an event to the list.
+     *
+     * @param aEvent a <code>EventDetails</code> value
+     */
+    public void addEvent(EventDetails aEvent) {
+        synchronized (mLock) {
+            mPendingEvents.add(aEvent);
+        }
+    }
+
+    /**
+     * Clear the list of all events.
+     */
+    public void clear() {
+        synchronized (mLock) {
+            mAllEvents.clear();
+            mFilteredEvents = new EventDetails[0];
+            mPendingEvents.clear();
+            fireTableDataChanged();
+        }
+    }
+
+    /** Toggle whether collecting events **/
+    public void toggle() {
+        synchronized (mLock) {
+            mPaused = !mPaused;
+        }
+    }
+
+    /** @return whether currently paused collecting events **/
+    public boolean isPaused() {
+        synchronized (mLock) {
+            return mPaused;
+        }
+    }
+
+    /**
+     * Get the throwable information at a specified row in the filtered events.
+     *
+     * @param aRow the row index of the event
+     * @return the throwable information
+     */
+    public EventDetails getEventDetails(int aRow) {
+        synchronized (mLock) {
+            return mFilteredEvents[aRow];
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Private methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Update the filtered events data structure.
+     * @param aInsertedToFront indicates whether events were added to front of
+     *        the events. If true, then the current first event must still exist
+     *        in the list after the filter is applied.
+     */
+    private void updateFilteredEvents(boolean aInsertedToFront) {
+        final long start = System.currentTimeMillis();
+        final List filtered = new ArrayList();
+        final int size = mAllEvents.size();
+        final Iterator it = mAllEvents.iterator();
+
+        while (it.hasNext()) {
+            final EventDetails event = (EventDetails) it.next();
+            if (matchFilter(event)) {
+                filtered.add(event);
+            }
+        }
+
+        final EventDetails lastFirst = (mFilteredEvents.length == 0)
+            ? null
+            : mFilteredEvents[0];
+        mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
+
+        if (aInsertedToFront && (lastFirst != null)) {
+            final int index = filtered.indexOf(lastFirst);
+            if (index < 1) {
+                LOG.warn("In strange state");
+                fireTableDataChanged();
+            } else {
+                fireTableRowsInserted(0, index - 1);
+            }
+        } else {
+            fireTableDataChanged();
+        }
+
+        final long end = System.currentTimeMillis();
+        LOG.debug("Total time [ms]: " + (end - start)
+                  + " in update, size: " + size);
+    }
+
+    /**
+     * Returns whether an event matches the filters.
+     *
+     * @param aEvent the event to check for a match
+     * @return whether the event matches
+     */
+    private boolean matchFilter(EventDetails aEvent) {
+        if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
+            (aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
+            (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
+            ((mNDCFilter.length() == 0) ||
+             ((aEvent.getNDC() != null) &&
+              (aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
+        {
+            final String rm = aEvent.getMessage();
+            if (rm == null) {
+                // only match if we have not filtering in place
+                return (mMessageFilter.length() == 0);
+            } else {
+                return (rm.indexOf(mMessageFilter) >= 0);
+            }
+        }
+
+        return false; // by default not match
+    }
+}

Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/MyTableModel.java.orig Sat Jun  2 11:40:31 2012
@@ -0,0 +1,390 @@
+/*
+ * 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;
+
+import java.text.DateFormat;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import javax.swing.table.AbstractTableModel;
+import org.apache.log4j.Priority;
+import org.apache.log4j.Logger;
+
+/**
+ * Represents a list of <code>EventDetails</code> objects that are sorted on
+ * logging time. Methods are provided to filter the events that are visible.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ */
+class MyTableModel
+    extends AbstractTableModel
+{
+
+    /** used to log messages **/
+    private static final Logger LOG = Logger.getLogger(MyTableModel.class);
+
+    /** use the compare logging events **/
+    private static final Comparator MY_COMP = new Comparator()
+    {
+        /** @see Comparator **/
+        public int compare(Object aObj1, Object aObj2) {
+            if ((aObj1 == null) && (aObj2 == null)) {
+                return 0; // treat as equal
+            } else if (aObj1 == null) {
+                return -1; // null less than everything
+            } else if (aObj2 == null) {
+                return 1; // think about it. :->
+            }
+
+            // will assume only have LoggingEvent
+            final EventDetails le1 = (EventDetails) aObj1;
+            final EventDetails le2 = (EventDetails) aObj2;
+
+            if (le1.getTimeStamp() < le2.getTimeStamp()) {
+                return 1;
+            }
+            // assume not two events are logged at exactly the same time
+            return -1;
+        }
+        };
+
+    /**
+     * Helper that actually processes incoming events.
+     * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+     */
+    private class Processor
+        implements Runnable
+    {
+        /** loops getting the events **/
+        public void run() {
+            while (true) {
+                try {
+                    Thread.sleep(1000);
+                } catch (InterruptedException e) {
+                    // ignore
+                }
+
+                synchronized (mLock) {
+                    if (mPaused) {
+                        continue;
+                    }
+
+                    boolean toHead = true; // were events added to head
+                    boolean needUpdate = false;
+                    final Iterator it = mPendingEvents.iterator();
+                    while (it.hasNext()) {
+                        final EventDetails event = (EventDetails) it.next();
+                        mAllEvents.add(event);
+                        toHead = toHead && (event == mAllEvents.first());
+                        needUpdate = needUpdate || matchFilter(event);
+                    }
+                    mPendingEvents.clear();
+
+                    if (needUpdate) {
+                        updateFilteredEvents(toHead);
+                    }
+                }
+            }
+
+        }
+    }
+
+
+    /** names of the columns in the table **/
+    private static final String[] COL_NAMES = {
+        "Time", "Priority", "Trace", "Category", "NDC", "Message"};
+
+    /** definition of an empty list **/
+    private static final EventDetails[] EMPTY_LIST =  new EventDetails[] {};
+
+    /** used to format dates **/
+    private static final DateFormat DATE_FORMATTER =
+        DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM);
+
+    /** the lock to control access **/
+    private final Object mLock = new Object();
+    /** set of all logged events - not filtered **/
+    private final SortedSet mAllEvents = new TreeSet(MY_COMP);
+    /** events that are visible after filtering **/
+    private EventDetails[] mFilteredEvents = EMPTY_LIST;
+    /** list of events that are buffered for processing **/
+    private final List mPendingEvents = new ArrayList();
+    /** indicates whether event collection is paused to the UI **/
+    private boolean mPaused = false;
+
+    /** filter for the thread **/
+    private String mThreadFilter = "";
+    /** filter for the message **/
+    private String mMessageFilter = "";
+    /** filter for the NDC **/
+    private String mNDCFilter = "";
+    /** filter for the category **/
+    private String mCategoryFilter = "";
+    /** filter for the priority **/
+    private Priority mPriorityFilter = Priority.DEBUG;
+
+
+    /**
+     * Creates a new <code>MyTableModel</code> instance.
+     *
+     */
+    MyTableModel() {
+        final Thread t = new Thread(new Processor());
+        t.setDaemon(true);
+        t.start();
+    }
+
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Table Methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /** @see javax.swing.table.TableModel **/
+    public int getRowCount() {
+        synchronized (mLock) {
+            return mFilteredEvents.length;
+        }
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public int getColumnCount() {
+        // does not need to be synchronized
+        return COL_NAMES.length;
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public String getColumnName(int aCol) {
+        // does not need to be synchronized
+        return COL_NAMES[aCol];
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public Class getColumnClass(int aCol) {
+        // does not need to be synchronized
+        return (aCol == 2) ? Boolean.class : Object.class;
+    }
+
+    /** @see javax.swing.table.TableModel **/
+    public Object getValueAt(int aRow, int aCol) {
+        synchronized (mLock) {
+            final EventDetails event = mFilteredEvents[aRow];
+
+            if (aCol == 0) {
+                return DATE_FORMATTER.format(new Date(event.getTimeStamp()));
+            } else if (aCol == 1) {
+                return event.getPriority();
+            } else if (aCol == 2) {
+                return (event.getThrowableStrRep() == null)
+                    ? Boolean.FALSE : Boolean.TRUE;
+            } else if (aCol == 3) {
+                return event.getCategoryName();
+            } else if (aCol == 4) {
+                return event.getNDC();
+            }
+            return event.getMessage();
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Public Methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Sets the priority to filter events on. Only events of equal or higher
+     * property are now displayed.
+     *
+     * @param aPriority the priority to filter on
+     */
+    public void setPriorityFilter(Priority aPriority) {
+        synchronized (mLock) {
+            mPriorityFilter = aPriority;
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the thread field.
+     *
+     * @param aStr the string to match
+     */
+    public void setThreadFilter(String aStr) {
+        synchronized (mLock) {
+            mThreadFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the message field.
+     *
+     * @param aStr the string to match
+     */
+    public void setMessageFilter(String aStr) {
+        synchronized (mLock) {
+            mMessageFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the NDC field.
+     *
+     * @param aStr the string to match
+     */
+    public void setNDCFilter(String aStr) {
+        synchronized (mLock) {
+            mNDCFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Set the filter for the category field.
+     *
+     * @param aStr the string to match
+     */
+    public void setCategoryFilter(String aStr) {
+        synchronized (mLock) {
+            mCategoryFilter = aStr.trim();
+            updateFilteredEvents(false);
+        }
+    }
+
+    /**
+     * Add an event to the list.
+     *
+     * @param aEvent a <code>EventDetails</code> value
+     */
+    public void addEvent(EventDetails aEvent) {
+        synchronized (mLock) {
+            mPendingEvents.add(aEvent);
+        }
+    }
+
+    /**
+     * Clear the list of all events.
+     */
+    public void clear() {
+        synchronized (mLock) {
+            mAllEvents.clear();
+            mFilteredEvents = new EventDetails[0];
+            mPendingEvents.clear();
+            fireTableDataChanged();
+        }
+    }
+
+    /** Toggle whether collecting events **/
+    public void toggle() {
+        synchronized (mLock) {
+            mPaused = !mPaused;
+        }
+    }
+
+    /** @return whether currently paused collecting events **/
+    public boolean isPaused() {
+        synchronized (mLock) {
+            return mPaused;
+        }
+    }
+
+    /**
+     * Get the throwable information at a specified row in the filtered events.
+     *
+     * @param aRow the row index of the event
+     * @return the throwable information
+     */
+    public EventDetails getEventDetails(int aRow) {
+        synchronized (mLock) {
+            return mFilteredEvents[aRow];
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Private methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * Update the filtered events data structure.
+     * @param aInsertedToFront indicates whether events were added to front of
+     *        the events. If true, then the current first event must still exist
+     *        in the list after the filter is applied.
+     */
+    private void updateFilteredEvents(boolean aInsertedToFront) {
+        final long start = System.currentTimeMillis();
+        final List filtered = new ArrayList();
+        final int size = mAllEvents.size();
+        final Iterator it = mAllEvents.iterator();
+
+        while (it.hasNext()) {
+            final EventDetails event = (EventDetails) it.next();
+            if (matchFilter(event)) {
+                filtered.add(event);
+            }
+        }
+
+        final EventDetails lastFirst = (mFilteredEvents.length == 0)
+            ? null
+            : mFilteredEvents[0];
+        mFilteredEvents = (EventDetails[]) filtered.toArray(EMPTY_LIST);
+
+        if (aInsertedToFront && (lastFirst != null)) {
+            final int index = filtered.indexOf(lastFirst);
+            if (index < 1) {
+                LOG.warn("In strange state");
+                fireTableDataChanged();
+            } else {
+                fireTableRowsInserted(0, index - 1);
+            }
+        } else {
+            fireTableDataChanged();
+        }
+
+        final long end = System.currentTimeMillis();
+        LOG.debug("Total time [ms]: " + (end - start)
+                  + " in update, size: " + size);
+    }
+
+    /**
+     * Returns whether an event matches the filters.
+     *
+     * @param aEvent the event to check for a match
+     * @return whether the event matches
+     */
+    private boolean matchFilter(EventDetails aEvent) {
+        if (aEvent.getPriority().isGreaterOrEqual(mPriorityFilter) &&
+            (aEvent.getThreadName().indexOf(mThreadFilter) >= 0) &&
+            (aEvent.getCategoryName().indexOf(mCategoryFilter) >= 0) &&
+            ((mNDCFilter.length() == 0) ||
+             ((aEvent.getNDC() != null) &&
+              (aEvent.getNDC().indexOf(mNDCFilter) >= 0))))
+        {
+            final String rm = aEvent.getMessage();
+            if (rm == null) {
+                // only match if we have not filtering in place
+                return (mMessageFilter.length() == 0);
+            } else {
+                return (rm.indexOf(mMessageFilter) >= 0);
+            }
+        }
+
+        return false; // by default not match
+    }
+}

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java Sat Jun  2 11:40:31 2012
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import java.util.StringTokenizer;
+import org.apache.log4j.Level;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A content handler for document containing Log4J events logged using the
+ * XMLLayout class. It will create events and add them to a supplied model.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ * @version 1.0
+ */
+class XMLFileHandler
+    extends DefaultHandler
+{
+    /** represents the event tag **/
+    private static final String TAG_EVENT = "log4j:event";
+    /** represents the message tag **/
+    private static final String TAG_MESSAGE = "log4j:message";
+    /** represents the ndc tag **/
+    private static final String TAG_NDC = "log4j:NDC";
+    /** represents the throwable tag **/
+    private static final String TAG_THROWABLE = "log4j:throwable";
+    /** represents the location info tag **/
+    private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
+
+    /** where to put the events **/
+    private final MyTableModel mModel;
+    /** the number of events in the document **/
+    private int mNumEvents;
+
+    /** the time of the event **/
+    private long mTimeStamp;
+    /** the priority (level) of the event **/
+    private Level mLevel;
+    /** the category of the event **/
+    private String mCategoryName;
+    /** the NDC for the event **/
+    private String mNDC;
+    /** the thread for the event **/
+    private String mThreadName;
+    /** the msg for the event **/
+    private String mMessage;
+    /** the throwable details the event **/
+    private String[] mThrowableStrRep;
+    /** the location details for the event **/
+    private String mLocationDetails;
+    /** buffer for collecting text **/
+    private final StringBuffer mBuf = new StringBuffer();
+
+    /**
+     * Creates a new <code>XMLFileHandler</code> instance.
+     *
+     * @param aModel where to add the events
+     */
+    XMLFileHandler(MyTableModel aModel) {
+        mModel = aModel;
+    }
+
+    /** @see DefaultHandler **/
+    public void startDocument()
+        throws SAXException
+    {
+        mNumEvents = 0;
+    }
+
+    /** @see DefaultHandler **/
+    public void characters(char[] aChars, int aStart, int aLength) {
+        mBuf.append(String.valueOf(aChars, aStart, aLength));
+    }
+
+    /** @see DefaultHandler **/
+    public void endElement(String aNamespaceURI,
+                           String aLocalName,
+                           String aQName)
+    {
+        if (TAG_EVENT.equals(aQName)) {
+            addEvent();
+            resetData();
+        } else if (TAG_NDC.equals(aQName)) {
+            mNDC = mBuf.toString();
+        } else if (TAG_MESSAGE.equals(aQName)) {
+            mMessage = mBuf.toString();
+        } else if (TAG_THROWABLE.equals(aQName)) {
+            final StringTokenizer st =
+                new StringTokenizer(mBuf.toString(), "\n\t");
+            mThrowableStrRep = new String[st.countTokens()];
+            if (mThrowableStrRep.length > 0) {
+                mThrowableStrRep[0] = st.nextToken();
+                for (int i = 1; i < mThrowableStrRep.length; i++) {
+                    mThrowableStrRep[i] = "\t" + st.nextToken();
+                }
+            }
+        }
+    }
+
+    /** @see DefaultHandler **/
+    public void startElement(String aNamespaceURI,
+                             String aLocalName,
+                             String aQName,
+                             Attributes aAtts)
+    {
+        mBuf.setLength(0);
+
+        if (TAG_EVENT.equals(aQName)) {
+            mThreadName = aAtts.getValue("thread");
+            mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
+            mCategoryName = aAtts.getValue("logger");
+            mLevel = Level.toLevel(aAtts.getValue("level"));
+        } else if (TAG_LOCATION_INFO.equals(aQName)) {
+            mLocationDetails = aAtts.getValue("class") + "."
+                + aAtts.getValue("method")
+                + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+                + ")";
+        }
+    }
+
+    /** @return the number of events in the document **/
+    int getNumEvents() {
+        return mNumEvents;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Private methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /** Add an event to the model **/
+    private void addEvent() {
+        mModel.addEvent(new EventDetails(mTimeStamp,
+                                         mLevel,
+                                         mCategoryName,
+                                         mNDC,
+                                         mThreadName,
+                                         mMessage,
+                                         mThrowableStrRep,
+                                         mLocationDetails));
+        mNumEvents++;
+    }
+
+    /** Reset the data for an event **/
+    private void resetData() {
+        mTimeStamp = 0;
+        mLevel = null;
+        mCategoryName = null;
+        mNDC = null;
+        mThreadName = null;
+        mMessage = null;
+        mThrowableStrRep = null;
+        mLocationDetails = null;
+    }
+}

Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/java/org/apache/log4j/chainsaw/XMLFileHandler.java.orig Sat Jun  2 11:40:31 2012
@@ -0,0 +1,170 @@
+/*
+ * 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;
+
+import java.util.StringTokenizer;
+import org.apache.log4j.Level;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A content handler for document containing Log4J events logged using the
+ * XMLLayout class. It will create events and add them to a supplied model.
+ *
+ * @author <a href="mailto:oliver@puppycrawl.com">Oliver Burn</a>
+ * @version 1.0
+ */
+class XMLFileHandler
+    extends DefaultHandler
+{
+    /** represents the event tag **/
+    private static final String TAG_EVENT = "log4j:event";
+    /** represents the message tag **/
+    private static final String TAG_MESSAGE = "log4j:message";
+    /** represents the ndc tag **/
+    private static final String TAG_NDC = "log4j:NDC";
+    /** represents the throwable tag **/
+    private static final String TAG_THROWABLE = "log4j:throwable";
+    /** represents the location info tag **/
+    private static final String TAG_LOCATION_INFO = "log4j:locationInfo";
+
+    /** where to put the events **/
+    private final MyTableModel mModel;
+    /** the number of events in the document **/
+    private int mNumEvents;
+
+    /** the time of the event **/
+    private long mTimeStamp;
+    /** the priority (level) of the event **/
+    private Level mLevel;
+    /** the category of the event **/
+    private String mCategoryName;
+    /** the NDC for the event **/
+    private String mNDC;
+    /** the thread for the event **/
+    private String mThreadName;
+    /** the msg for the event **/
+    private String mMessage;
+    /** the throwable details the event **/
+    private String[] mThrowableStrRep;
+    /** the location details for the event **/
+    private String mLocationDetails;
+    /** buffer for collecting text **/
+    private final StringBuffer mBuf = new StringBuffer();
+
+    /**
+     * Creates a new <code>XMLFileHandler</code> instance.
+     *
+     * @param aModel where to add the events
+     */
+    XMLFileHandler(MyTableModel aModel) {
+        mModel = aModel;
+    }
+
+    /** @see DefaultHandler **/
+    public void startDocument()
+        throws SAXException
+    {
+        mNumEvents = 0;
+    }
+
+    /** @see DefaultHandler **/
+    public void characters(char[] aChars, int aStart, int aLength) {
+        mBuf.append(String.valueOf(aChars, aStart, aLength));
+    }
+
+    /** @see DefaultHandler **/
+    public void endElement(String aNamespaceURI,
+                           String aLocalName,
+                           String aQName)
+    {
+        if (TAG_EVENT.equals(aQName)) {
+            addEvent();
+            resetData();
+        } else if (TAG_NDC.equals(aQName)) {
+            mNDC = mBuf.toString();
+        } else if (TAG_MESSAGE.equals(aQName)) {
+            mMessage = mBuf.toString();
+        } else if (TAG_THROWABLE.equals(aQName)) {
+            final StringTokenizer st =
+                new StringTokenizer(mBuf.toString(), "\n\t");
+            mThrowableStrRep = new String[st.countTokens()];
+            if (mThrowableStrRep.length > 0) {
+                mThrowableStrRep[0] = st.nextToken();
+                for (int i = 1; i < mThrowableStrRep.length; i++) {
+                    mThrowableStrRep[i] = "\t" + st.nextToken();
+                }
+            }
+        }
+    }
+
+    /** @see DefaultHandler **/
+    public void startElement(String aNamespaceURI,
+                             String aLocalName,
+                             String aQName,
+                             Attributes aAtts)
+    {
+        mBuf.setLength(0);
+
+        if (TAG_EVENT.equals(aQName)) {
+            mThreadName = aAtts.getValue("thread");
+            mTimeStamp = Long.parseLong(aAtts.getValue("timestamp"));
+            mCategoryName = aAtts.getValue("logger");
+            mLevel = Level.toLevel(aAtts.getValue("level"));
+        } else if (TAG_LOCATION_INFO.equals(aQName)) {
+            mLocationDetails = aAtts.getValue("class") + "."
+                + aAtts.getValue("method")
+                + "(" + aAtts.getValue("file") + ":" + aAtts.getValue("line")
+                + ")";
+        }
+    }
+
+    /** @return the number of events in the document **/
+    int getNumEvents() {
+        return mNumEvents;
+    }
+
+    ////////////////////////////////////////////////////////////////////////////
+    // Private methods
+    ////////////////////////////////////////////////////////////////////////////
+
+    /** Add an event to the model **/
+    private void addEvent() {
+        mModel.addEvent(new EventDetails(mTimeStamp,
+                                         mLevel,
+                                         mCategoryName,
+                                         mNDC,
+                                         mThreadName,
+                                         mMessage,
+                                         mThrowableStrRep,
+                                         mLocationDetails));
+        mNumEvents++;
+    }
+
+    /** Reset the data for an event **/
+    private void resetData() {
+        mTimeStamp = 0;
+        mLevel = null;
+        mCategoryName = null;
+        mNDC = null;
+        mThreadName = null;
+        mMessage = null;
+        mThrowableStrRep = null;
+        mLocationDetails = null;
+    }
+}

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png?rev=1345492&view=auto
==============================================================================
Binary file - no diff available.

Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png
------------------------------------------------------------------------------
    svn:mime-type = image/png

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig?rev=1345492&view=auto
==============================================================================
Files logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig (added) and logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/docFiles/screen_01.png.orig Sat Jun  2 11:40:31 2012 differ

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html Sat Jun  2 11:40:31 2012
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+ 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>
+  <HEAD>
+    <TITLE>Chainsaw Tool</TITLE>
+  </head>
+    
+  <BODY>
+
+    <P>Chainsaw is a GUI log viewer and filter for the log4j
+package. By default it listens for <a
+href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
+the <A href="../net/SocketAppender.html">SocketAppender</A> and
+displays them in a table. The events can be filtered based on:</P>
+
+    <UL>
+      <LI>Level </li>
+
+      <LI>Thread name</li>
+
+      <LI>Logger</li>
+      <LI>Message</li>
+
+      <LI>NDC</LI>
+    </UL>
+
+    <P>All the details for each event can be displayed by selecting
+      the event in the table.</P> 
+
+    <P>Chainsaw also supports loading a events logged to a file using
+      the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
+      is great for analysing log files, and means you do not need to
+      keep Chainsaw running continously. It is easy to add support
+      for loading events from other sources like JDBC.</P> 
+
+    <P>A picture is worth a thousand words: </P>
+
+    <P align=center><A
+      href="doc-files/screen_01.png"><IMG
+      height="50%" alt="Screen shot of chainsaw"
+      src="doc-files/screen_01.png"
+      width="50%"></A>.</P> 
+
+    <P>Finally, why is it called chainsaw?
+      Because it cuts your log (file) down to size. :-)
+    </P>
+
+
+    <H2>Requirements</H2> 
+
+    <P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
+
+
+    <H2>Running chainsaw</H2>
+
+    <H3>Setup</H3>
+    <P>You need to include the <code>log4j.jar</code> in the classpath.
+
+    <H3>Usage</H3>
+
+    <P>The command line usage is:</P>
+
+    <PRE>  java -D&lt;property&gt;=&lt;value&gt; org.apache.log4j.chainsaw.Main </PRE>
+
+    <P>The default behaviour of chainsaw can be changed by setting system properties 
+      using the <CODE>-D&lt;property&gt;=&lt;value&gt;</CODE> arguments to java. The 
+      following table describes what properties can be set:</P>
+
+    <TABLE cellSpacing=0 cellPadding=2 border=1>
+
+      <TR>
+	<TD vAlign=top><B>Property</B></TD>
+	<TD vAlign=top><B>Description</B></TD></TR>
+      <TR>
+	<TD vAlign=top>chainsaw.port</TD>
+	<TD vAlign=top>Indicates which port to listen for connections on. Defaults 
+	  to <SPAN class=default>"4445"</SPAN>.
+	</TD>
+      </TR>
+    </TBODY>
+    </TABLE>
+
+    <H2>Configuring Log4J</H2>
+
+    <P>You will need to configure log4j to send logging events to
+      Chainsaw.  Here is a sample <CODE>log4j.properties</CODE> file
+      for sending logging events to Chainsaw.</P>
+
+<PRE>
+log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
+
+log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
+log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
+log4j.appender.CHAINSAW_CLIENT.Port=4445
+log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
+</PRE>
+
+
+
+  </body>
+</html>
\ No newline at end of file

Propchange: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig (added)
+++ logging/log4j/branches/log4j12modules/modules/chainsaw/src/main/resources/org/apache/log4j/chainsaw/package.html.orig Sat Jun  2 11:40:31 2012
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<!--
+ 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>
+  <HEAD>
+    <TITLE>Chainsaw Tool</TITLE>
+  </head>
+    
+  <BODY>
+
+    <P>Chainsaw is a GUI log viewer and filter for the log4j
+package. By default it listens for <a
+href="../spi/LoggingEvent.html">LoggingEvent</A> objects sent using
+the <A href="../net/SocketAppender.html">SocketAppender</A> and
+displays them in a table. The events can be filtered based on:</P>
+
+    <UL>
+      <LI>Level </li>
+
+      <LI>Thread name</li>
+
+      <LI>Logger</li>
+      <LI>Message</li>
+
+      <LI>NDC</LI>
+    </UL>
+
+    <P>All the details for each event can be displayed by selecting
+      the event in the table.</P> 
+
+    <P>Chainsaw also supports loading a events logged to a file using
+      the <A href="../xml/XMLLayout.html">XMLLayout</A> format. This
+      is great for analysing log files, and means you do not need to
+      keep Chainsaw running continously. It is easy to add support
+      for loading events from other sources like JDBC.</P> 
+
+    <P>A picture is worth a thousand words: </P>
+
+    <P align=center><A
+      href="doc-files/screen_01.png"><IMG
+      height="50%" alt="Screen shot of chainsaw"
+      src="doc-files/screen_01.png"
+      width="50%"></A>.</P> 
+
+    <P>Finally, why is it called chainsaw?
+      Because it cuts your log (file) down to size. :-)
+    </P>
+
+
+    <H2>Requirements</H2> 
+
+    <P>Chainsaw is based on the Swing API which requires JDK 1.2 or later.</P>
+
+
+    <H2>Running chainsaw</H2>
+
+    <H3>Setup</H3>
+    <P>You need to include the <code>log4j.jar</code> in the classpath.
+
+    <H3>Usage</H3>
+
+    <P>The command line usage is:</P>
+
+    <PRE>  java -D&lt;property&gt;=&lt;value&gt; org.apache.log4j.chainsaw.Main </PRE>
+
+    <P>The default behaviour of chainsaw can be changed by setting system properties 
+      using the <CODE>-D&lt;property&gt;=&lt;value&gt;</CODE> arguments to java. The 
+      following table describes what properties can be set:</P>
+
+    <TABLE cellSpacing=0 cellPadding=2 border=1>
+
+      <TR>
+	<TD vAlign=top><B>Property</B></TD>
+	<TD vAlign=top><B>Description</B></TD></TR>
+      <TR>
+	<TD vAlign=top>chainsaw.port</TD>
+	<TD vAlign=top>Indicates which port to listen for connections on. Defaults 
+	  to <SPAN class=default>"4445"</SPAN>.
+	</TD>
+      </TR>
+    </TBODY>
+    </TABLE>
+
+    <H2>Configuring Log4J</H2>
+
+    <P>You will need to configure log4j to send logging events to
+      Chainsaw.  Here is a sample <CODE>log4j.properties</CODE> file
+      for sending logging events to Chainsaw.</P>
+
+<PRE>
+log4j.rootLogger=DEBUG, CHAINSAW_CLIENT
+
+log4j.appender.CHAINSAW_CLIENT=org.apache.log4j.net.SocketAppender
+log4j.appender.CHAINSAW_CLIENT.RemoteHost=localhost
+log4j.appender.CHAINSAW_CLIENT.Port=4445
+log4j.appender.CHAINSAW_CLIENT.LocationInfo=true
+</PRE>
+
+
+
+  </body>
+</html>
\ No newline at end of file

Copied: logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS (from r1345481, logging/log4j/branches/log4j12modules/contribs/CONTENTS)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS?p2=logging/log4j/branches/log4j12modules/modules/contribs/CONTENTS&p1=logging/log4j/branches/log4j12modules/contribs/CONTENTS&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Added: logging/log4j/branches/log4j12modules/modules/contribs/pom.xml
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/pom.xml?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/contribs/pom.xml (added)
+++ logging/log4j/branches/log4j12modules/modules/contribs/pom.xml Sat Jun  2 11:40:31 2012
@@ -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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+      <groupId>org.apache.log4j</groupId>
+      <artifactId>log4j-modules</artifactId>
+      <version>1.4.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.apache.log4j</groupId>
+  <artifactId>log4j-contribs</artifactId>
+  <name>Apache Log4j-Contribtutions</name>
+  <packaging>bundle</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.log4j</groupId>
+      <artifactId>log4j-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+    	<groupId>org.apache.log4j</groupId>
+    	<artifactId>log4j-net</artifactId>
+    	<version>1.4.0-SNAPSHOT</version>
+    	<type>bundle</type>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>2.0.1</version>
+        <extensions>true</extensions>
+        <configuration>
+            <instructions>
+                <Export-Package>org.apache.log4j.contribs.*</Export-Package>
+            </instructions>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
\ No newline at end of file

Propchange: logging/log4j/branches/log4j12modules/modules/contribs/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java?rev=1345492&view=auto
==============================================================================
--- logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java (added)
+++ logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java Sat Jun  2 11:40:31 2012
@@ -0,0 +1,211 @@
+/*
+ * 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.io.*;
+import org.apache.log4j.*;
+
+
+/**
+ * An OutputStream that flushes out to a Category.<p>
+ * 
+ * Note that no data is written out to the Category until the stream is
+ *   flushed or closed.<p>
+ * 
+ * Example:<pre>
+ * // make sure everything sent to System.err is logged
+ * System.setErr(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.WARN), true));
+ * 
+ * // make sure everything sent to System.out is also logged
+ * System.setOut(new PrintStream(new LoggingOutputStream(Category.getRoot(), Priority.INFO), true));
+ * </pre>
+ * 
+ * @author <a href="mailto://Jim.Moore@rocketmail.com">Jim Moore</a>
+ * @see Category
+ */
+public class LoggingOutputStream extends OutputStream {
+  protected static final String LINE_SEPERATOR = System.getProperty("line.separator");
+
+
+  /**
+   * Used to maintain the contract of {@link #close()}.
+   */
+  protected boolean hasBeenClosed = false;
+
+  /**
+   * The internal buffer where data is stored. 
+   */
+  protected byte[] buf;
+
+  /**
+   * The number of valid bytes in the buffer. This value is always 
+   *   in the range <tt>0</tt> through <tt>buf.length</tt>; elements 
+   *   <tt>buf[0]</tt> through <tt>buf[count-1]</tt> contain valid 
+   *   byte data.
+   */
+  protected int count;
+
+
+  /**
+   * Remembers the size of the buffer for speed.
+   */
+  private int bufLength;
+
+  /**
+   * The default number of bytes in the buffer. =2048
+   */
+  public static final int DEFAULT_BUFFER_LENGTH = 2048;
+
+
+  /**
+   * The category to write to.
+   */
+  protected Category category;
+
+  /**
+   * The priority to use when writing to the Category.
+   */
+  protected Priority priority;
+
+
+  private LoggingOutputStream() {
+    // illegal
+  }
+
+
+  /**
+   * Creates the LoggingOutputStream to flush to the given Category.
+   * 
+   * @param cat        the Category to write to
+   * 
+   * @param priority   the Priority to use when writing to the Category
+   * 
+   * @exception IllegalArgumentException
+   *                   if cat == null or priority == null
+   */
+  public LoggingOutputStream(Category cat, Priority priority)
+  throws IllegalArgumentException {
+    if (cat == null) {
+      throw new IllegalArgumentException("cat == null");
+    }
+    if (priority == null) {
+      throw new IllegalArgumentException("priority == null");
+    }
+
+    this.priority = priority;
+    category = cat;
+    bufLength = DEFAULT_BUFFER_LENGTH;
+    buf = new byte[DEFAULT_BUFFER_LENGTH];
+    count = 0;
+  }
+
+
+  /**
+   * Closes this output stream and releases any system resources
+   *   associated with this stream. The general contract of <code>close</code>
+   *   is that it closes the output stream. A closed stream cannot perform
+   *   output operations and cannot be reopened.
+   */
+  public void close() {
+    flush();
+    hasBeenClosed = true;
+  }
+
+
+  /**
+   * Writes the specified byte to this output stream. The general
+   * contract for <code>write</code> is that one byte is written
+   * to the output stream. The byte to be written is the eight
+   * low-order bits of the argument <code>b</code>. The 24
+   * high-order bits of <code>b</code> are ignored.
+   * 
+   * @param b          the <code>byte</code> to write
+   * 
+   * @exception IOException
+   *                   if an I/O error occurs. In particular,
+   *                   an <code>IOException</code> may be thrown if the
+   *                   output stream has been closed.
+   */
+  public void write(final int b) throws IOException {
+    if (hasBeenClosed) {
+      throw new IOException("The stream has been closed.");
+    }
+
+    // don't log nulls
+    if (b == 0) {
+      return;
+    }
+
+    // would this be writing past the buffer?
+    if (count == bufLength) {
+      // grow the buffer
+      final int newBufLength = bufLength+DEFAULT_BUFFER_LENGTH;
+      final byte[] newBuf = new byte[newBufLength];
+
+      System.arraycopy(buf, 0, newBuf, 0, bufLength);
+
+      buf = newBuf;
+      bufLength = newBufLength;
+    }
+
+    buf[count] = (byte)b;
+    count++;
+  }
+
+
+  /**
+   * Flushes this output stream and forces any buffered output bytes
+   *   to be written out. The general contract of <code>flush</code> is
+   *   that calling it is an indication that, if any bytes previously
+   *   written have been buffered by the implementation of the output
+   *   stream, such bytes should immediately be written to their
+   *   intended destination.
+   */
+  public void flush() {
+    if (count == 0) {
+      return;
+    }
+
+    // don't print out blank lines; flushing from PrintStream puts out these
+    if (count == LINE_SEPERATOR.length()) {
+      if ( ((char)buf[0]) == LINE_SEPERATOR.charAt(0)  &&
+           ( ( count == 1 ) ||  // <- Unix & Mac, -> Windows
+             ( (count == 2) && ((char)buf[1]) == LINE_SEPERATOR.charAt(1) ) ) ) {
+        reset();
+        return;
+      }
+    }
+
+    final byte[] theBytes = new byte[count];
+
+    System.arraycopy(buf, 0, theBytes, 0, count);
+
+    category.log(priority, new String(theBytes));
+
+    reset();
+  }
+
+
+  private void reset() {
+    // not resetting the buffer -- assuming that if it grew that it
+    //   will likely grow similarly again
+    count = 0;
+  }
+
+}
+

Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/LoggingOutputStream.java
------------------------------------------------------------------------------
    svn:eol-style = native

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18 (from r1345481, logging/log4j/branches/log4j12modules/contribs/EirikLygre/mail-2001-01-18)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/EirikLygre/mail-2001-01-18&p1=logging/log4j/branches/log4j12modules/contribs/EirikLygre/mail-2001-01-18&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JamesHouse/mail-2001-01-23)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamesHouse/mail-2001-01-23&p1=logging/log4j/branches/log4j12modules/contribs/JamesHouse/mail-2001-01-23&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20 (from r1345481, logging/log4j/branches/log4j12modules/contribs/Jamie Tsao/mail-2001-06-20)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JamieTsao/mail-2001-06-20&p1=logging/log4j/branches/log4j12modules/contribs/Jamie%20Tsao/mail-2001-06-20&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1326)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1326&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1326&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1454)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-12T1454&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-12T1454&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646 (from r1345481, logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-13T0646)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/JimMoore/mail-2001-03-13T0646&p1=logging/log4j/branches/log4j12modules/contribs/JimMoore/mail-2001-03-13T0646&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01 (from r1345481, logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2001-02-01)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2001-02-01&p1=logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2001-02-01&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt (from r1345481, logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2002-03-27.txt)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt&p1=logging/log4j/branches/log4j12modules/contribs/KevinSteppe/mail-2002-03-27.txt&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)

Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KevinSteppe/mail-2002-03-27.txt
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Copied: logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07 (from r1345481, logging/log4j/branches/log4j12modules/contribs/KitchingSimon/mail-2001-02-07)
URL: http://svn.apache.org/viewvc/logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07?p2=logging/log4j/branches/log4j12modules/modules/contribs/src/main/java/org/apache/log4j/contribs/KitchingSimon/mail-2001-02-07&p1=logging/log4j/branches/log4j12modules/contribs/KitchingSimon/mail-2001-02-07&r1=1345481&r2=1345492&rev=1345492&view=diff
==============================================================================
    (empty)



Mime
View raw message