GERONIMO-4241 NPE when calling folder.getDeletedMessageCount() for POP3 store

Optimize thread pool usage to only use a single connection for single-threaded operation. 



git-svn-id: https://svn.apache.org/repos/asf/geronimo/javamail/trunk/geronimo-javamail_1.4@689140 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java b/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
index 6e59064..8fcfb4a 100644
--- a/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
+++ b/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Folder.java
@@ -53,8 +53,6 @@
 
     protected int mode;
 
-    protected POP3Connection currentConnection; 
-
     protected int msgCount;
 
     private POP3Message[] messageCache; 
@@ -199,15 +197,11 @@
         // Can only be performed on a closed folder
         checkClosed();
 
+        // get a connection object 
+        POP3Connection connection = getConnection(); 
+        
         try {
-            
-            // ask the store to kindly hook us up with a connection.
-            // We're going to hang on to this until we're closed, so store it in 
-            // the Folder field.  We need to make sure our mailbox is selected while 
-            // we're working things. 
-            currentConnection = ((POP3Store)store).getFolderConnection(this); 
-
-            POP3StatusResponse res = currentConnection.retrieveMailboxStatus();
+            POP3StatusResponse res = connection.retrieveMailboxStatus();
             this.mode = mode;
             this.isFolderOpen = true;
             this.msgCount = res.getNumMessages();
@@ -221,6 +215,10 @@
         } catch (Exception e) {
             throw new MessagingException("Unable to execute STAT command", e);
         }
+        finally {
+            // return the connection when finished 
+            releaseConnection(connection); 
+        }
 
         notifyConnectionListeners(ConnectionEvent.OPENED);
     }
@@ -235,14 +233,19 @@
     public void close(boolean expunge) throws MessagingException {
         // Can only be performed on an open folder
         checkOpen();
+
+        // get a connection object 
+        POP3Connection connection = getConnection(); 
         try {
             // we might need to reset the connection before we 
             // process deleted messages and send the QUIT.  The 
             // connection knows if we need to do this. 
-            currentConnection.reset(); 
+            connection.reset(); 
             // clean up any messages marked for deletion 
-            expungeDeletedMessages(); 
+            expungeDeletedMessages(connection); 
         } finally {
+            // return the connection when finished 
+            releaseConnection(connection); 
             // cleanup the the state even if exceptions occur when deleting the 
             // messages. 
             cleanupFolder(false); 
@@ -251,11 +254,11 @@
     
     /**
      * Mark any messages we've flagged as deleted from the 
-     * IMAP server before closing. 
+     * POP3 server before closing. 
      * 
      * @exception MessagingException
      */
-    protected void expungeDeletedMessages() throws MessagingException {
+    protected void expungeDeletedMessages(POP3Connection connection) throws MessagingException {
         if (mode == READ_WRITE) {
             for (int i = 0; i < messageCache.length; i++) {
                 POP3Message msg = messageCache[i]; 
@@ -265,7 +268,7 @@
                     // origin 1 value 
                     if (msg.isSet(Flags.Flag.DELETED)) {
                         try {
-                            currentConnection.deleteMessage(i + 1); 
+                            connection.deleteMessage(i + 1); 
                         } catch (MessagingException e) {
                             throw new MessagingException("Exception deleting message number " + (i + 1), e); 
                         }
@@ -292,20 +295,6 @@
     protected void cleanupFolder(boolean disconnected) throws MessagingException {
         messageCache = null;
         isFolderOpen = false;
-        // if we have a connection active at the moment
-        if (currentConnection != null) {
-            // was this a forced disconnect by the server?
-            if (disconnected) {
-                currentConnection.setClosed(); 
-            }
-            else {
-                // have this close the selected mailbox 
-                currentConnection.logout();           
-            }
-            // we need to release the connection to the Store once we're closed 
-            ((POP3Store)store).releaseFolderConnection(this, currentConnection); 
-            currentConnection = null; 
-        }
 		notifyConnectionListeners(ConnectionEvent.CLOSED);
     }
     
@@ -319,15 +308,9 @@
      * @exception MessagingException
      */
     synchronized POP3Connection getMessageConnection() throws MessagingException {
-        // if we're not open, the messages can't communicate either
-        if (currentConnection == null) {
-            throw new FolderClosedException(this, "No Folder connections available"); 
-        }
-        // return the current Folder connection.  At this point, we'll be sharing the 
-        // connection between the Folder and the Message (and potentially, other messages).  The 
-        // command operations on the connection are synchronized so only a single command can be 
-        // issued at one time. 
-        return currentConnection; 
+        // we always get one from the store.  If we're fully single threaded, then 
+        // we can get away with just a single one. 
+        return getConnection(); 
     }
     
     
@@ -339,7 +322,8 @@
      * @exception MessagingException
      */
     void releaseMessageConnection(POP3Connection connection) throws MessagingException {
-        // This is a NOP for this folder type. 
+        // give this back to the store 
+        releaseConnection(connection); 
     }
 
     public boolean isOpen() {
@@ -503,4 +487,29 @@
         super.notifyMessageChangedListeners(type, m);
     }
 
+    
+    /**
+     * Retrieve the connection attached to this folder.  Throws an
+     * exception if we don't have an active connection.
+     *
+     * @return The current connection object.
+     * @exception MessagingException
+     */
+    protected synchronized POP3Connection getConnection() throws MessagingException {
+        // request a connection from the central store. 
+        return ((POP3Store)store).getFolderConnection(this); 
+    }
+    
+    
+    /**
+     * Release our connection back to the Store.
+     * 
+     * @param connection The connection to release.
+     * 
+     * @exception MessagingException
+     */
+    protected void releaseConnection(POP3Connection connection) throws MessagingException {
+        // we need to release the connection to the Store once we're finished with it 
+        ((POP3Store)store).releaseFolderConnection(this, connection); 
+    }
 }
diff --git a/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java b/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
index 0778430..1c9d69e 100644
--- a/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
+++ b/geronimo-javamail_1.4_provider/src/main/java/org/apache/geronimo/javamail/store/pop3/POP3Store.java
@@ -171,25 +171,55 @@
     }
     
     
+    /**
+     * Get a connection for the store. 
+     * 
+     * @return The request connection object. 
+     * @exception MessagingException
+     */
     protected POP3Connection getConnection() throws MessagingException {
         return connectionPool.getConnection(); 
     }
     
+    /**
+     * Return a connection back to the connection pool after 
+     * it has been used for a request. 
+     * 
+     * @param connection The return connection.
+     * 
+     * @exception MessagingException
+     */
     protected void releaseConnection(POP3Connection connection) throws MessagingException {
         connectionPool.releaseConnection(connection); 
     }
     
+    /**
+     * Get a connection object for a folder to use. 
+     * 
+     * @param folder The requesting folder (always the inbox for POP3).
+     * 
+     * @return An active POP3Connection. 
+     * @exception MessagingException
+     */
     synchronized POP3Connection getFolderConnection(POP3Folder folder) throws MessagingException {
         POP3Connection connection = connectionPool.getConnection(); 
         openFolders.add(folder);
         return connection; 
     }
     
+    /**
+     * Release a connection object after a folder is 
+     * finished with a request. 
+     * 
+     * @param folder     The requesting folder.
+     * @param connection
+     * 
+     * @exception MessagingException
+     */
     synchronized void releaseFolderConnection(POP3Folder folder, POP3Connection connection) throws MessagingException {
         openFolders.remove(folder); 
-        // a connection returned from a folder is no longer usable. Just close it and 
-        // let it drift off. 
-        connection.close(); 
+        // return this back to the pool 
+        connectionPool.releaseConnection(connection); 
     }
     
     /**