001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027package org.apache.http.impl.client; 028 029import java.io.Closeable; 030import java.io.IOException; 031import java.util.concurrent.ExecutorService; 032import java.util.concurrent.atomic.AtomicBoolean; 033 034import org.apache.http.annotation.Contract; 035import org.apache.http.annotation.ThreadingBehavior; 036import org.apache.http.client.HttpClient; 037import org.apache.http.client.ResponseHandler; 038import org.apache.http.client.methods.HttpUriRequest; 039import org.apache.http.concurrent.FutureCallback; 040import org.apache.http.protocol.HttpContext; 041 042/** 043 * HttpAsyncClientWithFuture wraps calls to execute with a {@link HttpRequestFutureTask} 044 * and schedules them using the provided executor service. Scheduled calls may be cancelled. 045 */ 046@Contract(threading = ThreadingBehavior.SAFE) 047public class FutureRequestExecutionService implements Closeable { 048 049 private final HttpClient httpclient; 050 private final ExecutorService executorService; 051 private final FutureRequestExecutionMetrics metrics = new FutureRequestExecutionMetrics(); 052 private final AtomicBoolean closed = new AtomicBoolean(false); 053 054 /** 055 * Create a new FutureRequestExecutionService. 056 * 057 * @param httpclient 058 * you should tune your httpclient instance to match your needs. You should 059 * align the max number of connections in the pool and the number of threads 060 * in the executor; it doesn't make sense to have more threads than connections 061 * and if you have less connections than threads, the threads will just end up 062 * blocking on getting a connection from the pool. 063 * @param executorService 064 * any executorService will do here. E.g. 065 * {@link java.util.concurrent.Executors#newFixedThreadPool(int)} 066 */ 067 public FutureRequestExecutionService( 068 final HttpClient httpclient, 069 final ExecutorService executorService) { 070 this.httpclient = httpclient; 071 this.executorService = executorService; 072 } 073 074 /** 075 * Schedule a request for execution. 076 * 077 * @param <T> 078 * 079 * @param request 080 * request to execute 081 * @param responseHandler 082 * handler that will process the response. 083 * @return HttpAsyncClientFutureTask for the scheduled request. 084 */ 085 public <T> HttpRequestFutureTask<T> execute( 086 final HttpUriRequest request, 087 final HttpContext context, 088 final ResponseHandler<T> responseHandler) { 089 return execute(request, context, responseHandler, null); 090 } 091 092 /** 093 * Schedule a request for execution. 094 * 095 * @param <T> 096 * 097 * @param request 098 * request to execute 099 * @param context 100 * optional context; use null if not needed. 101 * @param responseHandler 102 * handler that will process the response. 103 * @param callback 104 * callback handler that will be called when the request is scheduled, 105 * started, completed, failed, or cancelled. 106 * @return HttpAsyncClientFutureTask for the scheduled request. 107 */ 108 public <T> HttpRequestFutureTask<T> execute( 109 final HttpUriRequest request, 110 final HttpContext context, 111 final ResponseHandler<T> responseHandler, 112 final FutureCallback<T> callback) { 113 if(closed.get()) { 114 throw new IllegalStateException("Close has been called on this httpclient instance."); 115 } 116 metrics.getScheduledConnections().incrementAndGet(); 117 final HttpRequestTaskCallable<T> callable = new HttpRequestTaskCallable<T>( 118 httpclient, request, context, responseHandler, callback, metrics); 119 final HttpRequestFutureTask<T> httpRequestFutureTask = new HttpRequestFutureTask<T>( 120 request, callable); 121 executorService.execute(httpRequestFutureTask); 122 123 return httpRequestFutureTask; 124 } 125 126 /** 127 * @return metrics gathered for this instance. 128 * @see FutureRequestExecutionMetrics 129 */ 130 public FutureRequestExecutionMetrics metrics() { 131 return metrics; 132 } 133 134 @Override 135 public void close() throws IOException { 136 closed.set(true); 137 executorService.shutdownNow(); 138 if (httpclient instanceof Closeable) { 139 ((Closeable) httpclient).close(); 140 } 141 } 142}