You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by ni...@apache.org on 2014/02/08 03:51:58 UTC

svn commit: r1565878 - in /logging/log4j/log4j2/trunk: log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/ log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/ log4j-core/src/main/java/org/apache/logging/log4j/core/a...

Author: nickwilliams
Date: Sat Feb  8 02:51:58 2014
New Revision: 1565878

URL: http://svn.apache.org/r1565878
Log:
Part 2 of 2-part commit for fixing LOG4J2-407, LOG4J2-438, LOG4J2-442, LOG4J2-457, and LOG4J2-489: Changed database appenders to connect (borrow from pool) on every flush or every non-buffered writeInternal.

Modified:
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java
    logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
    logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManagerTest.java
    logging/log4j/log4j2/trunk/src/changes/changes.xml

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManager.java Sat Feb  8 02:51:58 2014
@@ -106,6 +106,13 @@ public abstract class AbstractDatabaseMa
     }
 
     /**
+     * Connects to the database and starts a transaction (if applicable). With buffering enabled, this is called when
+     * flushing the buffer begins, before the first call to {@link #writeInternal}. With buffering disabled, this is
+     * called immediately before every invocation of {@link #writeInternal}.
+     */
+    protected abstract void connectAndStart();
+
+    /**
      * Performs the actual writing of the event in an implementation-specific way. This method is called immediately
      * from {@link #write(LogEvent)} if buffering is off, or from {@link #flush()} if the buffer has reached its limit.
      *
@@ -114,14 +121,24 @@ public abstract class AbstractDatabaseMa
     protected abstract void writeInternal(LogEvent event);
 
     /**
+     * Commits any active transaction (if applicable) and disconnects from the database (returns the connection to the
+     * connection pool). With buffering enabled, this is called when flushing the buffer completes, after the last call
+     * to {@link #writeInternal}. With buffering disabled, this is called immediately after every invocation of
+     * {@link #writeInternal}.
+     */
+    protected abstract void commitAndClose();
+
+    /**
      * This method is called automatically when the buffer size reaches its maximum or at the beginning of a call to
      * {@link #shutdown()}. It can also be called manually to flush events to the database.
      */
     public final synchronized void flush() {
         if (this.isRunning() && this.buffer.size() > 0) {
+            this.connectAndStart();
             for (final LogEvent event : this.buffer) {
                 this.writeInternal(event);
             }
+            this.commitAndClose();
             this.buffer.clear();
         }
     }
@@ -138,7 +155,9 @@ public abstract class AbstractDatabaseMa
                 this.flush();
             }
         } else {
+            this.connectAndStart();
             this.writeInternal(event);
+            this.commitAndClose();
         }
     }
 

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jdbc/JDBCDatabaseManager.java Sat Feb  8 02:51:58 2014
@@ -53,17 +53,27 @@ public final class JDBCDatabaseManager e
     }
 
     @Override
-    protected void startupInternal() throws SQLException {
-        this.connection = this.connectionSource.getConnection();
-        this.statement = this.connection.prepareStatement(this.sqlStatement);
+    protected void startupInternal() {
+        // nothing to see here
     }
 
     @Override
-    protected void shutdownInternal() throws SQLException {
+    protected void shutdownInternal() {
+        if (this.connection != null || this.statement != null) {
+            this.commitAndClose();
+        }
+    }
+
+    @Override
+    protected void connectAndStart() {
         try {
-            Closer.close(this.statement);
-        } finally {
-            Closer.close(this.connection);
+            this.connection = this.connectionSource.getConnection();
+            this.connection.setAutoCommit(false);
+            this.statement = this.connection.prepareStatement(this.sqlStatement);
+        } catch (SQLException e) {
+            throw new AppenderLoggingException(
+                    "Cannot write logging event or flush buffer; JDBC manager cannot connect to the database.", e
+            );
         }
     }
 
@@ -71,7 +81,8 @@ public final class JDBCDatabaseManager e
     protected void writeInternal(final LogEvent event) {
         StringReader reader = null;
         try {
-            if (!this.isRunning() || this.connection == null || this.connection.isClosed()) {
+            if (!this.isRunning() || this.connection == null || this.connection.isClosed() || this.statement == null
+                    || this.statement.isClosed()) {
                 throw new AppenderLoggingException(
                         "Cannot write logging event; JDBC manager not connected to the database.");
             }
@@ -110,6 +121,37 @@ public final class JDBCDatabaseManager e
         }
     }
 
+    @Override
+    protected void commitAndClose() {
+        try {
+            if (this.connection != null && !this.connection.isClosed()) {
+                this.connection.commit();
+            }
+        } catch (SQLException e) {
+            throw new AppenderLoggingException("Failed to commit transaction logging event or flushing buffer.", e);
+        } finally {
+            try {
+                if (this.statement != null) {
+                    this.statement.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close SQL statement logging event or flushing buffer.", e);
+            } finally {
+                this.statement = null;
+            }
+
+            try {
+                if (this.connection != null) {
+                    this.connection.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close database connection logging event or flushing buffer.", e);
+            } finally {
+                this.connection = null;
+            }
+        }
+    }
+
     /**
      * Creates a JDBC manager for use within the {@link JDBCAppender}, or returns a suitable one if it already exists.
      *

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/jpa/JPADatabaseManager.java Sat Feb  8 02:51:58 2014
@@ -39,6 +39,9 @@ public final class JPADatabaseManager ex
 
     private EntityManagerFactory entityManagerFactory;
 
+    private EntityManager entityManager;
+    private EntityTransaction transaction;
+
     private JPADatabaseManager(final String name, final int bufferSize,
                                final Class<? extends AbstractLogEventWrapperEntity> entityClass,
                                final Constructor<? extends AbstractLogEventWrapperEntity> entityConstructor,
@@ -56,14 +59,31 @@ public final class JPADatabaseManager ex
 
     @Override
     protected void shutdownInternal() {
+        if (this.entityManager != null || this.transaction != null) {
+            this.commitAndClose();
+        }
         if (this.entityManagerFactory != null && this.entityManagerFactory.isOpen()) {
             this.entityManagerFactory.close();
         }
     }
 
     @Override
+    protected void connectAndStart() {
+        try {
+            this.entityManager = this.entityManagerFactory.createEntityManager();
+            this.transaction = this.entityManager.getTransaction();
+            this.transaction.begin();
+        } catch (Exception e) {
+            throw new AppenderLoggingException(
+                    "Cannot write logging event or flush buffer; manager cannot create EntityManager or transaction.", e
+            );
+        }
+    }
+
+    @Override
     protected void writeInternal(final LogEvent event) {
-        if (!this.isRunning() || this.entityManagerFactory == null) {
+        if (!this.isRunning() || this.entityManagerFactory == null || this.entityManager == null
+                || this.transaction == null) {
             throw new AppenderLoggingException(
                     "Cannot write logging event; JPA manager not connected to the database.");
         }
@@ -75,23 +95,38 @@ public final class JPADatabaseManager ex
             throw new AppenderLoggingException("Failed to instantiate entity class [" + this.entityClassName + "].", e);
         }
 
-        EntityManager entityManager = null;
-        EntityTransaction transaction = null;
         try {
-            entityManager = this.entityManagerFactory.createEntityManager();
-            transaction = entityManager.getTransaction();
-            transaction.begin();
-            entityManager.persist(entity);
-            transaction.commit();
+            this.entityManager.persist(entity);
         } catch (final Exception e) {
-            if (transaction != null && transaction.isActive()) {
-                transaction.rollback();
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.rollback();
+                this.transaction = null;
             }
-            throw new AppenderLoggingException("Failed to insert record for log event in JDBC manager: " +
+            throw new AppenderLoggingException("Failed to insert record for log event in JPA manager: " +
                     e.getMessage(), e);
+        }
+    }
+
+    @Override
+    protected void commitAndClose() {
+        try {
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.commit();
+            }
+        } catch (Exception e) {
+            if (this.transaction != null && this.transaction.isActive()) {
+                this.transaction.rollback();
+            }
         } finally {
-            if (entityManager != null && entityManager.isOpen()) {
-                entityManager.close();
+            this.transaction = null;
+            try {
+                if (this.entityManager != null && this.entityManager.isOpen()) {
+                    this.entityManager.close();
+                }
+            } catch (Exception e) {
+                LOGGER.warn("Failed to close entity manager while logging event or flushing buffer.", e);
+            } finally {
+                this.entityManager = null;
             }
         }
     }

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLConnection.java Sat Feb  8 02:51:58 2014
@@ -55,7 +55,11 @@ public interface NoSQLConnection<W, T ex
     /**
      * Closes the underlying connection. This method call should be idempotent. Only the first call should have any
      * effect; all further calls should be ignored. It's possible the underlying connection is stateless (such as an
-     * HTTP web service), in which case this method would be a no-op.
+     * HTTP web service), in which case this method would be a no-op. This method should also commit any open
+     * transactions, if applicable and if not already committed.<br />
+     * <br />
+     * If this connection is part of a connection pool, executing this method should commit the transaction and return
+     * the connection to the pool, but it should not actually close the underlying connection.
      */
     @Override
     void close();

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManager.java Sat Feb  8 02:51:58 2014
@@ -45,13 +45,22 @@ public final class NoSQLDatabaseManager<
 
     @Override
     protected void startupInternal() {
-        this.connection = this.provider.getConnection();
+        // nothing to see here
     }
 
     @Override
     protected void shutdownInternal() {
-        if (this.connection != null && !this.connection.isClosed()) {
-            this.connection.close();
+        if (this.connection != null) {
+            this.commitAndClose();
+        }
+    }
+
+    @Override
+    protected void connectAndStart() {
+        try {
+            this.connection = this.provider.getConnection();
+        } catch (Exception e) {
+            throw new AppenderLoggingException("Failed to get connection from NoSQL connection provider.", e);
         }
     }
 
@@ -139,6 +148,17 @@ public final class NoSQLDatabaseManager<
         this.connection.insertObject(entity);
     }
 
+    @Override
+    protected void commitAndClose() {
+        try {
+            if (this.connection != null && !this.connection.isClosed()) {
+                this.connection.close();
+            }
+        } catch (Exception e) {
+            throw new AppenderLoggingException("Failed to commit and close NoSQL connection in manager.", e);
+        }
+    }
+
     private NoSQLObject<W>[] convertStackTrace(final StackTraceElement[] stackTrace) {
         final NoSQLObject<W>[] stackTraceEntities = this.connection.createList(stackTrace.length);
         for (int i = 0; i < stackTrace.length; i++) {

Modified: logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLProvider.java Sat Feb  8 02:51:58 2014
@@ -26,7 +26,10 @@ public interface NoSQLProvider<C extends
     /**
      * Obtains a connection from this provider. The concept of a connection in this case is not strictly an active
      * duplex UDP or TCP connection to the underlying database. It can be thought of more as a gateway, a path for
-     * inserting objects that may use a persistent connection or may use HTTP web service calls, etc.
+     * inserting objects that may use a persistent connection or may use HTTP web service calls, etc.<br />
+     * <br />
+     * Where applicable, this method should return a connection from the connection pool as opposed to opening a
+     * brand new connection every time.
      *
      * @return a connection that can be used to create and persist objects to this database.
      * @see NoSQLConnection

Modified: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseAppenderTest.java Sat Feb  8 02:51:58 2014
@@ -126,16 +126,24 @@ public class AbstractDatabaseAppenderTes
         final LogEvent event1 = createStrictMock(LogEvent.class);
         final LogEvent event2 = createStrictMock(LogEvent.class);
 
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event1));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager, this.appender);
 
         this.appender.append(event1);
 
         verify(this.manager, this.appender);
         reset(this.manager, this.appender);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event2));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager, this.appender);
 
         this.appender.append(event2);

Modified: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/AbstractDatabaseManagerTest.java Sat Feb  8 02:51:58 2014
@@ -123,26 +123,42 @@ public class AbstractDatabaseManagerTest
 
         this.manager.startupInternal();
         expectLastCall();
-        this.manager.writeInternal(same(event1));
-        expectLastCall();
         replay(this.manager);
 
         this.manager.startup();
 
+        verify(this.manager);
+        reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
+        this.manager.writeInternal(same(event1));
+        expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
+        replay(this.manager);
+
         this.manager.write(event1);
 
         verify(this.manager);
         reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event2));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager);
 
         this.manager.write(event2);
 
         verify(this.manager);
         reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event3));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager);
 
         this.manager.write(event3);
@@ -169,6 +185,8 @@ public class AbstractDatabaseManagerTest
 
         verify(this.manager);
         reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event1));
         expectLastCall();
         this.manager.writeInternal(same(event2));
@@ -177,6 +195,8 @@ public class AbstractDatabaseManagerTest
         expectLastCall();
         this.manager.writeInternal(same(event4));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager);
 
         this.manager.write(event4);
@@ -202,12 +222,16 @@ public class AbstractDatabaseManagerTest
 
         verify(this.manager);
         reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event1));
         expectLastCall();
         this.manager.writeInternal(same(event2));
         expectLastCall();
         this.manager.writeInternal(same(event3));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         replay(this.manager);
 
         this.manager.flush();
@@ -233,12 +257,16 @@ public class AbstractDatabaseManagerTest
 
         verify(this.manager);
         reset(this.manager);
+        this.manager.connectAndStart();
+        expectLastCall();
         this.manager.writeInternal(same(event1));
         expectLastCall();
         this.manager.writeInternal(same(event2));
         expectLastCall();
         this.manager.writeInternal(same(event3));
         expectLastCall();
+        this.manager.commitAndClose();
+        expectLastCall();
         this.manager.shutdownInternal();
         expectLastCall();
         replay(this.manager);

Modified: logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManagerTest.java
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManagerTest.java?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManagerTest.java (original)
+++ logging/log4j/log4j2/trunk/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/nosql/NoSQLDatabaseManagerTest.java Sat Feb  8 02:51:58 2014
@@ -69,7 +69,7 @@ public class NoSQLDatabaseManagerTest {
             expect(this.provider.getConnection()).andReturn(this.connection);
             replay(this.provider, this.connection);
 
-            manager.startupInternal();
+            manager.connectAndStart();
 
             verify(this.provider, this.connection);
             reset(this.provider, this.connection);
@@ -78,7 +78,7 @@ public class NoSQLDatabaseManagerTest {
             expectLastCall();
             replay(this.provider, this.connection);
 
-            manager.shutdownInternal();
+            manager.commitAndClose();
         } finally {
             try {
                 manager.release();
@@ -120,16 +120,22 @@ public class NoSQLDatabaseManagerTest {
 
     @Test
     public void testWriteInternalNotConnected02() {
-        expect(this.provider.getConnection()).andReturn(this.connection);
-        replay(this.provider, this.connection);
-
         final NoSQLDatabaseManager<?> manager = NoSQLDatabaseManager.getNoSQLDatabaseManager("name", 0, this.provider);
 
         try {
+            replay(this.provider, this.connection);
+
             manager.startup();
 
             verify(this.provider, this.connection);
             reset(this.provider, this.connection);
+            expect(this.provider.getConnection()).andReturn(this.connection);
+            replay(this.provider, this.connection);
+
+            manager.connectAndStart();
+
+            verify(this.provider, this.connection);
+            reset(this.provider, this.connection);
 
             final LogEvent event = createStrictMock(LogEvent.class);
             expect(this.connection.isClosed()).andReturn(true);
@@ -159,16 +165,22 @@ public class NoSQLDatabaseManagerTest {
 
     @Test
     public void testWriteInternal01() {
-        expect(this.provider.getConnection()).andReturn(this.connection);
-        replay(this.provider, this.connection);
-
         final NoSQLDatabaseManager<?> manager = NoSQLDatabaseManager.getNoSQLDatabaseManager("name", 0, this.provider);
 
         try {
+            replay(this.provider, this.connection);
+
             manager.startup();
 
             verify(this.provider, this.connection);
             reset(this.provider, this.connection);
+            expect(this.provider.getConnection()).andReturn(this.connection);
+            replay(this.provider, this.connection);
+
+            manager.connectAndStart();
+
+            verify(this.provider, this.connection);
+            reset(this.provider, this.connection);
 
             final Capture<NoSQLObject<Map<String, Object>>> capture = new Capture<NoSQLObject<Map<String, Object>>>();
 
@@ -245,16 +257,22 @@ public class NoSQLDatabaseManagerTest {
 
     @Test
     public void testWriteInternal02() {
-        expect(this.provider.getConnection()).andReturn(this.connection);
-        replay(this.provider, this.connection);
-
         final NoSQLDatabaseManager<?> manager = NoSQLDatabaseManager.getNoSQLDatabaseManager("name", 0, this.provider);
 
         try {
+            replay(this.provider, this.connection);
+
             manager.startup();
 
             verify(this.provider, this.connection);
             reset(this.provider, this.connection);
+            expect(this.provider.getConnection()).andReturn(this.connection);
+            replay(this.provider, this.connection);
+
+            manager.connectAndStart();
+
+            verify(this.provider, this.connection);
+            reset(this.provider, this.connection);
 
             final Capture<NoSQLObject<Map<String, Object>>> capture = new Capture<NoSQLObject<Map<String, Object>>>();
 
@@ -379,16 +397,22 @@ public class NoSQLDatabaseManagerTest {
 
     @Test
     public void testWriteInternal03() {
-        expect(this.provider.getConnection()).andReturn(this.connection);
-        replay(this.provider, this.connection);
-
         final NoSQLDatabaseManager<?> manager = NoSQLDatabaseManager.getNoSQLDatabaseManager("name", 0, this.provider);
 
         try {
+            replay(this.provider, this.connection);
+
             manager.startup();
 
             verify(this.provider, this.connection);
             reset(this.provider, this.connection);
+            expect(this.provider.getConnection()).andReturn(this.connection);
+            replay(this.provider, this.connection);
+
+            manager.connectAndStart();
+
+            verify(this.provider, this.connection);
+            reset(this.provider, this.connection);
 
             final Capture<NoSQLObject<Map<String, Object>>> capture = new Capture<NoSQLObject<Map<String, Object>>>();
 

Modified: logging/log4j/log4j2/trunk/src/changes/changes.xml
URL: http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/src/changes/changes.xml?rev=1565878&r1=1565877&r2=1565878&view=diff
==============================================================================
--- logging/log4j/log4j2/trunk/src/changes/changes.xml (original)
+++ logging/log4j/log4j2/trunk/src/changes/changes.xml Sat Feb  8 02:51:58 2014
@@ -21,6 +21,25 @@
   </properties>
   <body>
     <release version="2.0-RC1" date="2014-MM-DD" description="Bug fixes and enhancements">
+      <action issue="LOG4J2-489" dev="nickwilliams" type="fix">
+        Fixed the JPAAppender's overuse of transactions by connecting (borrowing from pool) on new write internal or on
+        flush.
+      </action>
+      <action issue="LOG4J2-457" dev="nickwilliams" type="fix">
+        Fixed failure of JDBC and JPA appender to properly release database connections by connecting (borrowing from
+        pool) on new write internal or on flush.
+      </action>
+      <action issue="LOG4J2-442" dev="nickwilliams" type="fix">
+        Fixed problem with JDBC and JPA appender connectivity in WebSphere by connecting (borrowing from pool) on new
+        write internal or on flush.
+      </action>
+      <action issue="LOG4J2-438" dev="nickwilliams" type="fix">
+        Ensured the JDBCAppender commits transactions after a single write or a flush of multiple writes.
+      </action>
+      <action issue="LOG4J2-407" dev="nickwilliams" type="fix">
+        Fixed inability to recover from lost database connection in database appenders by connecting (borrowing from
+        pool) on new write internal or on flush.
+      </action>
       <action dev="nickwilliams" type="delete">
         Removed the DataSourceConnectionSource and the &lt;DriverManager&gt; plugin for the JDBC Appender. It is not
         safe to use. Please use the DataSource or factory connection sources backed by a connection pool.