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ülcü
+ */
+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:[email protected]";>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:[email protected]";>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 ([email protected])
+ */
+
+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 ([email protected])
+ *
+ */
+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;
+    }
+  }
+
+}

Reply via email to