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.util.concurrent.Callable;
030import java.util.concurrent.atomic.AtomicBoolean;
031
032import org.apache.http.client.HttpClient;
033import org.apache.http.client.ResponseHandler;
034import org.apache.http.client.methods.HttpUriRequest;
035import org.apache.http.concurrent.FutureCallback;
036import org.apache.http.protocol.HttpContext;
037
038class HttpRequestTaskCallable<V> implements Callable<V> {
039
040    private final HttpUriRequest request;
041    private final HttpClient httpclient;
042    private final AtomicBoolean cancelled = new AtomicBoolean(false);
043
044    private final long scheduled = System.currentTimeMillis();
045    private long started = -1;
046    private long ended = -1;
047
048    private final HttpContext context;
049    private final ResponseHandler<V> responseHandler;
050    private final FutureCallback<V> callback;
051
052    private final FutureRequestExecutionMetrics metrics;
053
054    HttpRequestTaskCallable(
055            final HttpClient httpClient,
056            final HttpUriRequest request,
057            final HttpContext context,
058            final ResponseHandler<V> responseHandler,
059            final FutureCallback<V> callback,
060            final FutureRequestExecutionMetrics metrics) {
061        this.httpclient = httpClient;
062        this.responseHandler = responseHandler;
063        this.request = request;
064        this.context = context;
065        this.callback = callback;
066        this.metrics = metrics;
067    }
068
069    public long getScheduled() {
070        return scheduled;
071    }
072
073    public long getStarted() {
074        return started;
075    }
076
077    public long getEnded() {
078        return ended;
079    }
080
081    @Override
082    public V call() throws Exception {
083        if (!cancelled.get()) {
084            try {
085                metrics.getActiveConnections().incrementAndGet();
086                started = System.currentTimeMillis();
087                try {
088                    metrics.getScheduledConnections().decrementAndGet();
089                    final V result = httpclient.execute(request, responseHandler, context);
090                    ended = System.currentTimeMillis();
091                    metrics.getSuccessfulConnections().increment(started);
092                    if (callback != null) {
093                        callback.completed(result);
094                    }
095                    return result;
096                } catch (final Exception e) {
097                    metrics.getFailedConnections().increment(started);
098                    ended = System.currentTimeMillis();
099                    if (callback != null) {
100                        callback.failed(e);
101                    }
102                    throw e;
103                }
104            } finally {
105                metrics.getRequests().increment(started);
106                metrics.getTasks().increment(started);
107                metrics.getActiveConnections().decrementAndGet();
108            }
109        } else {
110            throw new IllegalStateException("call has been cancelled for request " + request.getURI());
111        }
112    }
113
114    public void cancel() {
115        cancelled.set(true);
116        if (callback != null) {
117            callback.cancelled();
118        }
119    }
120}