Project: fed4j
/*
 * Copyright (C) <2009>  Hugo Zhu <[email protected]
 * 
 * This program is free software: you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation, either version 3 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 */
 
package com.jute.fed4j.engine.component.http; 
 
import com.jute.fed4j.engine.component.HttpComponent; 
import org.apache.http.conn.ClientConnectionManager; 
import org.apache.http.conn.routing.HttpRoutePlanner; 
import org.apache.http.conn.params.ConnManagerParams; 
import org.apache.http.conn.params.ConnRoutePNames; 
import org.apache.http.conn.ssl.SSLSocketFactory; 
import org.apache.http.conn.scheme.SchemeRegistry; 
import org.apache.http.conn.scheme.Scheme; 
import org.apache.http.conn.scheme.PlainSocketFactory; 
import org.apache.http.params.HttpParams; 
import org.apache.http.params.HttpProtocolParams; 
import org.apache.http.params.BasicHttpParams; 
import org.apache.http.params.HttpConnectionParams; 
import org.apache.http.*; 
import org.apache.http.util.EntityUtils; 
import org.apache.http.protocol.HttpRequestExecutor; 
import org.apache.http.protocol.HttpProcessor; 
import org.apache.http.protocol.HttpContext; 
import org.apache.http.client.HttpClient; 
import org.apache.http.client.ClientProtocolException; 
import org.apache.http.client.ResponseHandler; 
import org.apache.http.client.HttpResponseException; 
import org.apache.http.client.methods.HttpUriRequest; 
import org.apache.http.client.methods.HttpRequestBase; 
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; 
import org.apache.http.impl.conn.SingleClientConnManager; 
import org.apache.http.impl.conn.DefaultHttpRoutePlanner; 
import org.apache.http.impl.client.DefaultHttpClient; 
 
import java.net.SocketTimeoutException; 
import java.net.URI; 
import java.io.IOException; 
 
public class HttpDispatcherImpl_Jakarta extends HttpDispatcher { 
    private static ClientConnectionManager sharedConnectionManager = null
    private static SchemeRegistry schemeRegistry = new SchemeRegistry(); 
 
 
    static { 
        schemeRegistry.register( 
                new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); 
        schemeRegistry.register( 
                new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));      
    } 
 
 
    private final static Object locker = new Object(); 
     
    /**
     * get a connection manager 
     * @param params 
     * @return 
     */
 
    private ClientConnectionManager getConnectionManager(HttpParams params, boolean enablePersistentConnection) { 
        ClientConnectionManager connectionManager; 
        if (enablePersistentConnection) { 
            //be careful, somehow the ThreadSafeClientConnManager dosn't perform well with high traffic 
            if (sharedConnectionManager==null) { 
                synchronized (locker) { 
                    if (sharedConnectionManager==null) { 
                        ConnManagerParams.setMaxTotalConnections(params, 100); 
                        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); 
                        ConnManagerParams.setTimeout(params, 10); 
                        sharedConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry); 
                    } 
                } 
            } 
            connectionManager = sharedConnectionManager; 
        } 
        else { 
            connectionManager = new SingleClientConnManager(params,schemeRegistry); 
        } 
        return connectionManager; 
    } 
 
    private HttpComponent commponent; 
 
    public void run(HttpComponent component) { 
        this.commponent = component; 
        HttpParams params = new BasicHttpParams(); 
        HttpConnectionParams.setConnectionTimeout(params, component.connectTimeout); 
        HttpConnectionParams.setSoTimeout(params, component.readTimeout); 
 
        try { 
            this.init(component); 
            HttpClient httpclient = new MyHttpClient(getConnectionManager(params,component.enablePersistentConnection), params); 
            if (component.enableProxy && "http".equals(component.proxyType)) { 
                HttpHost proxy = new HttpHost(component.proxyHost, component.proxyPort, component.proxyType); 
                httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy); 
            } 
            HttpUriRequest request = new HttpRequest(component.method,component.uri); 
            MyHttpResponseHandler responseHandler = new MyHttpResponseHandler(component.responseCharset); 
            String body = httpclient.execute(request, responseHandler); 
            this.onResponse(component,responseHandler.code,body); 
        } catch (SocketTimeoutException e) { 
            onException(component,-2" socket timeout error occurs: "+e.getMessage()); 
        } catch (ClientProtocolException e) { 
            onException(component,-3" error resposed from server: "+e.getMessage()); 
        }  catch (IOException e) { 
            onException(component,-4" error occurs during dispatch: "+e.getMessage()); 
        } 
        catch (Exception e) { 
            onException(component,-5"error occurs during parsing xml:"+e.getMessage()); 
        } 
    } 
 
    static class MyClientConnManager extends ThreadSafeClientConnManager { 
        public MyClientConnManager(HttpParams params, SchemeRegistry schreg) { 
            super(params,schreg); 
        } 
    } 
 
    class MyHttpClient extends DefaultHttpClient { 
        public MyHttpClient
                final ClientConnectionManager conman, 
                final HttpParams params) { 
            super(conman, params); 
        } 
 
        @Override 
        protected HttpRequestExecutor createRequestExecutor() { 
            return new MyHttpRequestExecutor(); 
        } 
 
        /**
         * @todo 
         * @return 
         */
 
        @Override 
        protected HttpRoutePlanner createHttpRoutePlanner() { 
            return new DefaultHttpRoutePlanner 
                (getConnectionManager().getSchemeRegistry()); 
        } 
    } 
 
    class MyHttpRequestExecutor extends HttpRequestExecutor { 
         
        @Override 
        public void preProcess
                final org.apache.http.HttpRequest request, 
                final HttpProcessor processor, 
                final HttpContext context) 
                    throws HttpException, IOException { 
            onConnect(commponent); 
            super.preProcess(request,processor,context); 
        } 
 
        @Override 
        public void postProcess(HttpResponse response, HttpProcessor processor, HttpContext context) throws HttpException, IOException { 
            onRead(commponent); 
            super.postProcess(response, processor, context); 
        } 
    } 
 
    class MyHttpResponseHandler implements ResponseHandler<String> { 
        int code; 
        Header[] headers; 
        private String responseCharset = null
 
        MyHttpResponseHandler(String responseCharset) { 
            this.responseCharset = responseCharset; 
        } 
 
        /**
        * Returns the response body as a String if the response was successful (a 
        * 2xx status code). If no response body exists, this returns null. If the 
        * response was unsuccessful (>= 300 status code), throws an 
        * {@link org.apache.http.client.HttpResponseException}. 
        */
 
       public String handleResponse(final HttpResponse response) 
               throws HttpResponseException, IOException { 
           StatusLine statusLine = response.getStatusLine(); 
           code = statusLine.getStatusCode(); 
           headers = response.getAllHeaders(); 
 
           if (statusLine.getStatusCode() >= 300) { 
               throw new HttpResponseException(statusLine.getStatusCode(), 
                       statusLine.getReasonPhrase()); 
           } 
 
           HttpEntity entity = response.getEntity(); 
           return entity == null ? null : EntityUtils.toString(entity, responseCharset); 
       } 
    }     
 
class HttpRequest extends HttpRequestBase { 
    String method; 
 
    public HttpRequest() { 
        super(); 
    } 
 
    public HttpRequest(String method, final URI uri) { 
        super(); 
        this.method = method; 
        setURI(uri); 
    } 
 
    @Override 
    public String getMethod() { 
        return method; 
    } 
}