[MERCURY-124] - http retrieval client pool added to the transport

git-svn-id: https://svn.apache.org/repos/asf/maven/mercury/trunk@772389 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DefaultHttpClientPool.java b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DefaultHttpClientPool.java
deleted file mode 100644
index a3c8431..0000000
--- a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/DefaultHttpClientPool.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
- */
-
-package org.apache.maven.mercury.spi.http.client;
-
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.codehaus.plexus.lang.DefaultLanguage;
-import org.codehaus.plexus.lang.Language;
-import org.mortbay.jetty.client.HttpClient;
-
-/**
- * @author Oleg Gusakov
- * @version $Id$
- */
-public class DefaultHttpClientPool
-    implements HttpClientPool
-{
-    private static final Language LANG = new DefaultLanguage( DefaultHttpClientPool.class );
-
-    private static int _poolSize = DEFAULT_POOL_SIZE;
-
-    private static ConcurrentLinkedQueue<HttpClient> _pool = new ConcurrentLinkedQueue<HttpClient>();
-
-    public DefaultHttpClientPool()
-    {
-        this( DEFAULT_POOL_SIZE );
-    }
-
-    public DefaultHttpClientPool( int sz )
-    {
-        for ( int i = 0; i < sz; i++ )
-            _pool.offer( new HttpClient() );
-    }
-
-    public HttpClient getHttpClient()
-        throws HttpClientPoolException
-    {
-        if ( _pool.isEmpty() )
-            throw new HttpClientPoolException( LANG.getMessage( "pool.empty" ) );
-
-        return _pool.poll();
-    }
-
-    public void returnHttpClient( HttpClient client )
-        throws HttpClientPoolException
-    {
-        _pool.offer( client );
-    }
-
-}
diff --git a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
index 24c2b53..8668ce2 100644
--- a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
+++ b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientException.java
@@ -17,19 +17,6 @@
  * under the License.
  */
 
-//========================================================================
-//Copyright 2008 Sonatype Inc.
-//------------------------------------------------------------------------
-//Licensed 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.maven.mercury.spi.http.client;
 
 import org.apache.maven.mercury.transport.api.Binding;
@@ -39,6 +26,7 @@
  * <p/>
  * Exception that occurs whilst deploying or retrieving files asynchronously.
  */
+@SuppressWarnings("serial")
 public class HttpClientException
     extends Exception
 {
diff --git a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPool.java b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPool.java
index b793cbf..afa7f75 100644
--- a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPool.java
+++ b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPool.java
@@ -19,21 +19,115 @@
 
 package org.apache.maven.mercury.spi.http.client;
 
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.codehaus.plexus.lang.DefaultLanguage;
+import org.codehaus.plexus.lang.Language;
 import org.mortbay.jetty.client.HttpClient;
 
 /**
- * an abstraction to use instead actual HttpClient
+ * a pool to use instead actual HttpClient. A singleton that stores all HttpClient's 
+ * known to mercury transport layer.
+ * 
+ * At this point - writing files to the server can tolerate creating a new HttpClient, so
+ * the code supporting it is not utilized.
  * 
  * @author Oleg Gusakov
  * @version $Id$
  */
-public interface HttpClientPool
+public class HttpClientPool
 {
-    public static final int DEFAULT_POOL_SIZE = 3;
+    public static final String SYSTEM_PROPERTY_HTTP_CLIENT_POOL_SIZE = "mercury.http.client.pool.size";
+    
+    /** default initial pool size */
+    public static final int POOL_SIZE = Integer.valueOf( System.getProperty( SYSTEM_PROPERTY_HTTP_CLIENT_POOL_SIZE, "5" ) );
+    
+    public static final String SYSTEM_PROPERTY_HTTP_DAV_CLIENT_POOL_SIZE = "mercury.http.dav.client.pool.size";
+    
+    /** default initial dav pool size */
+    public static final int DAV_POOL_SIZE = Integer.valueOf( System.getProperty( SYSTEM_PROPERTY_HTTP_DAV_CLIENT_POOL_SIZE, "3" ) );
 
-    HttpClient getHttpClient()
-        throws HttpClientPoolException;
+    private static PoolImpl _readPool  = new PoolImpl( POOL_SIZE, null );
+    private static PoolImpl _writePool = new PoolImpl( DAV_POOL_SIZE, "org.mortbay.jetty.client.webdav.WebdavListener");
 
-    void returnHttpClient( HttpClient client )
-        throws HttpClientPoolException;
+    public static HttpClient getHttpClient( boolean davEnabledClient )
+    throws HttpClientException
+    {
+        if( davEnabledClient )
+            return _writePool.getHttpClient();
+        
+        return _readPool.getHttpClient();
+    }
+
+    public static void returnHttpClient( HttpClient client, boolean davEnabledClient )
+    {
+        if( davEnabledClient )
+            _writePool.returnHttpClient( client );
+        else
+            _readPool.returnHttpClient( client );
+    }
+
 }
+
+class PoolImpl
+{
+    private static final Language LANG = new DefaultLanguage( PoolImpl.class );
+
+    private final int POOL_SIZE;
+
+    /** current pool size. Will not grow beyond POOL_SIZE */
+    private static int _poolSize = 0;
+
+    /** the pool itself */
+    private ConcurrentLinkedQueue<HttpClient> _pool = new ConcurrentLinkedQueue<HttpClient>();
+    
+    private String _listener; 
+
+    PoolImpl( int maxSize, String listener )
+    {
+        this.POOL_SIZE = maxSize;
+        
+        this._listener = listener;
+    }
+
+    synchronized HttpClient getHttpClient()
+    throws HttpClientException
+    {
+        if ( _pool.isEmpty() )
+        {
+            if( _poolSize < POOL_SIZE )
+            {
+                ++_poolSize;
+                
+                // TODO Oleg 2009.05.06: add "http client configuration" configuration
+                HttpClient hc = new HttpClient();
+
+                hc.setConnectorType( HttpClient.CONNECTOR_SELECT_CHANNEL );
+
+                if( _listener != null )
+                    hc.registerListener( _listener );
+
+                try
+                {
+                    hc.start();
+                }
+                catch ( Exception e )
+                {
+                    throw new HttpClientException( null, e.getMessage() );
+                }
+                
+                _pool.offer( hc );
+            }
+            else    
+                throw new HttpClientException( null, LANG.getMessage( "pool.empty", ""+_poolSize ) );
+        }
+
+        return _pool.poll();
+    }
+    
+    void returnHttpClient( HttpClient client )
+    {
+        if( client != null)
+            _pool.offer( client );
+    }
+}
\ No newline at end of file
diff --git a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPoolException.java b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPoolException.java
deleted file mode 100644
index 71c6e97..0000000
--- a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/HttpClientPoolException.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
- */
-
-package org.apache.maven.mercury.spi.http.client;
-
-/**
- * @author Oleg Gusakov
- * @version $Id$
- */
-public class HttpClientPoolException
-    extends Exception
-{
-
-    /**
-     * 
-     */
-    public HttpClientPoolException()
-    {
-        // TODO Auto-generated constructor stub
-    }
-
-    /**
-     * @param message
-     */
-    public HttpClientPoolException( String message )
-    {
-        super( message );
-        // TODO Auto-generated constructor stub
-    }
-
-    /**
-     * @param cause
-     */
-    public HttpClientPoolException( Throwable cause )
-    {
-        super( cause );
-        // TODO Auto-generated constructor stub
-    }
-
-    /**
-     * @param message
-     * @param cause
-     */
-    public HttpClientPoolException( String message, Throwable cause )
-    {
-        super( message, cause );
-        // TODO Auto-generated constructor stub
-    }
-
-}
diff --git a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java
index 0a5ad8e..ef99131 100644
--- a/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java
+++ b/mercury-core/src/main/java/org/apache/maven/mercury/spi/http/client/retrieve/DefaultRetriever.java
@@ -37,6 +37,7 @@
 import org.apache.maven.mercury.logging.MercuryLoggerManager;
 import org.apache.maven.mercury.spi.http.client.DestinationRealmResolver;
 import org.apache.maven.mercury.spi.http.client.HttpClientException;
+import org.apache.maven.mercury.spi.http.client.HttpClientPool;
 import org.apache.maven.mercury.transport.api.Binding;
 import org.apache.maven.mercury.transport.api.Server;
 import org.mortbay.jetty.client.HttpClient;
@@ -54,20 +55,20 @@
         throws HttpClientException
     {
         // TODO take the default settings for now
-        _httpClient = new HttpClient();
-        _httpClient.setConnectorType( HttpClient.CONNECTOR_SELECT_CHANNEL );
-        try
-        {
-            // TODO: What are all the reasons that the httpclient couldn't start up correctly?
-            _httpClient.start();
-        }
-        catch ( Exception e )
-        {
-            throw new HttpClientException( null, "Unable to start http client.", e );
-        }
+//      _httpClient = new HttpClient();
+//        _httpClient.setConnectorType( HttpClient.CONNECTOR_SELECT_CHANNEL );
+//        try
+//        {
+//            // TODO: What are all the reasons that the httpclient couldn't start up correctly?
+//            _httpClient.start();
+//        }
+//        catch ( Exception e )
+//        {
+//            throw new HttpClientException( null, "Unable to start http client.", e );
+//        }
     }
 
-    public DefaultRetriever( HttpClient client )
+    private DefaultRetriever( HttpClient client )
         throws HttpClientException
     {
         // TODO take the default settings for now
@@ -89,7 +90,7 @@
     {
         _servers.clear();
         _servers.addAll( servers );
-        _httpClient.setRealmResolver( new DestinationRealmResolver( _servers ) );
+//        _httpClient.setRealmResolver( new DestinationRealmResolver( _servers ) );
     }
 
     public Set<Server> getServers()
@@ -166,6 +167,17 @@
         Binding[] bindings = new Binding[request.getBindings().size()];
         request.getBindings().toArray( bindings );
 
+        if( _httpClient == null )
+            try
+            {
+                _httpClient = HttpClientPool.getHttpClient(false);
+                _httpClient.setRealmResolver( new DestinationRealmResolver( _servers ) );
+            }
+            catch ( HttpClientException e1 )
+            {
+                response.add( new HttpClientException( bindings[0], e1 ) );
+            }
+
         for ( int i = 0; i < bindings.length && count.get() > 0; i++ )
         {
             final Binding binding = bindings[i];
@@ -212,6 +224,7 @@
                             if ( DefaultRetriever.this.isComplete( count, request, response, targets ) )
                             {
                                 callback.onComplete( response );
+                                stop();
                             }
                         }
 
@@ -221,6 +234,7 @@
                             if ( DefaultRetriever.this.isComplete( count, request, response, targets ) )
                             {
                                 callback.onComplete( response );
+                                stop();
                             }
                         }
                     };
@@ -233,6 +247,7 @@
                 if ( isComplete( count, request, response, targets ) )
                 {
                     callback.onComplete( response );
+                    stop();
                 }
             }
         }
@@ -339,20 +354,22 @@
 
     public void stop()
     {
-        if ( _httpClient == null )
-            return;
-
-        if ( _httpClient.isStopped() || _httpClient.isStopping() )
-            return;
-
-        try
-        {
-            _httpClient.stop();
-        }
-        catch ( Exception e )
-        {
-            LOG.error( e.getMessage() );
-        }
+        HttpClientPool.returnHttpClient( _httpClient, false );
+        _httpClient = null;
+//        if ( _httpClient == null )
+//            return;
+//
+//        if ( _httpClient.isStopped() || _httpClient.isStopping() )
+//            return;
+//
+//        try
+//        {
+//            _httpClient.stop();
+//        }
+//        catch ( Exception e )
+//        {
+//            LOG.error( e.getMessage() );
+//        }
 
     }
 
diff --git a/mercury-core/src/main/resources/org/apache/maven/mercury/spi/http/client/Messages.properties b/mercury-core/src/main/resources/org/apache/maven/mercury/spi/http/client/Messages.properties
index 209b2a0..fb05e63 100644
--- a/mercury-core/src/main/resources/org/apache/maven/mercury/spi/http/client/Messages.properties
+++ b/mercury-core/src/main/resources/org/apache/maven/mercury/spi/http/client/Messages.properties
@@ -1 +1 @@
-pool.empty=HttpClientPool of initial size {0}, is empty
+pool.empty=HttpClientPool of size {0}, is empty. Cannot grow it beyond this size.