All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.aoju.bus.http.RealCall Maven / Gradle / Ivy

/*********************************************************************************
 *                                                                               *
 * The MIT License (MIT)                                                         *
 *                                                                               *
 * Copyright (c) 2015-2022 aoju.org and other contributors.                      *
 *                                                                               *
 * Permission is hereby granted, free of charge, to any person obtaining a copy  *
 * of this software and associated documentation files (the "Software"), to deal *
 * in the Software without restriction, including without limitation the rights  *
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell     *
 * copies of the Software, and to permit persons to whom the Software is         *
 * furnished to do so, subject to the following conditions:                      *
 *                                                                               *
 * The above copyright notice and this permission notice shall be included in    *
 * all copies or substantial portions of the Software.                           *
 *                                                                               *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR    *
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,      *
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE   *
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER        *
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN     *
 * THE SOFTWARE.                                                                 *
 *                                                                               *
 ********************************************************************************/
package org.aoju.bus.http;

import org.aoju.bus.core.io.timout.Timeout;
import org.aoju.bus.core.lang.Normal;
import org.aoju.bus.core.toolkit.IoKit;
import org.aoju.bus.http.accord.ConnectInterceptor;
import org.aoju.bus.http.accord.Transmitter;
import org.aoju.bus.http.cache.CacheInterceptor;
import org.aoju.bus.http.metric.Interceptor;
import org.aoju.bus.http.metric.NamedRunnable;
import org.aoju.bus.http.metric.http.BridgeInterceptor;
import org.aoju.bus.http.metric.http.CallServerInterceptor;
import org.aoju.bus.http.metric.http.RealInterceptorChain;
import org.aoju.bus.http.metric.http.RetryAndFollowUp;
import org.aoju.bus.logger.Logger;

import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 实际调用准备执行的请求
 *
 * @author Kimi Liu
 * @since Java 17+
 */
public class RealCall implements NewCall {

    /**
     * 调用客户端
     */
    public final Httpd client;
    /**
     * 应用程序的原始请求未掺杂重定向或验证标头.
     */
    public final Request originalRequest;
    public final boolean forWebSocket;
    /**
     * 在{@link NewCall}和{@link Transmitter}之间有一个循环
     * 这是在创建调用实例之后立即设置的
     */
    private Transmitter transmitter;
    /**
     * 进程守护
     */
    private boolean executed;

    private RealCall(Httpd client, Request originalRequest, boolean forWebSocket) {
        this.client = client;
        this.originalRequest = originalRequest;
        this.forWebSocket = forWebSocket;
    }

    static RealCall newRealCall(Httpd client, Request originalRequest, boolean forWebSocket) {
        // 安全地将Call实例发布到EventListener
        RealCall call = new RealCall(client, originalRequest, forWebSocket);
        call.transmitter = new Transmitter(client, call);
        return call;
    }

    @Override
    public Request request() {
        return originalRequest;
    }

    @Override
    public Response execute() throws IOException {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.timeoutEnter();
        transmitter.callStart();
        try {
            client.dispatcher().executed(this);
            return getResponseWithInterceptorChain();
        } finally {
            client.dispatcher().finished(this);
        }
    }

    @Override
    public void enqueue(Callback responseCallback) {
        synchronized (this) {
            if (executed) throw new IllegalStateException("Already Executed");
            executed = true;
        }
        transmitter.callStart();
        client.dispatcher().enqueue(new AsyncCall(responseCallback));
    }

    @Override
    public void cancel() {
        transmitter.cancel();
    }

    @Override
    public Timeout timeout() {
        return transmitter.timeout();
    }

    @Override
    public synchronized boolean isExecuted() {
        return executed;
    }

    @Override
    public boolean isCanceled() {
        return transmitter.isCanceled();
    }

    @Override
    public RealCall clone() {
        return RealCall.newRealCall(client, originalRequest, forWebSocket);
    }

    /**
     * 返回描述此调用的字符串
     * 不包含完整的URL,因为它可能包含敏感信息
     */
    public String toLoggableString() {
        return (isCanceled() ? "canceled " : Normal.EMPTY)
                + (forWebSocket ? "web socket" : "call")
                + " to " + redactedUrl();
    }

    public String redactedUrl() {
        return originalRequest.url().redact();
    }

    public Response getResponseWithInterceptorChain() throws IOException {
        // Build a full stack of interceptors.
        List interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(new RetryAndFollowUp(client));
        interceptors.add(new BridgeInterceptor(client.cookieJar()));
        interceptors.add(new CacheInterceptor(client.internalCache()));
        interceptors.add(new ConnectInterceptor(client));
        if (!forWebSocket) {
            interceptors.addAll(client.networkInterceptors());
        }
        interceptors.add(new CallServerInterceptor(forWebSocket));

        Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
                originalRequest, this, client.connectTimeoutMillis(),
                client.readTimeoutMillis(), client.writeTimeoutMillis());

        boolean calledNoMoreExchanges = false;
        try {
            Response response = chain.proceed(originalRequest);
            if (transmitter.isCanceled()) {
                IoKit.close(response);
                throw new IOException("Canceled");
            }
            return response;
        } catch (IOException e) {
            calledNoMoreExchanges = true;
            throw transmitter.noMoreExchanges(e);
        } finally {
            if (!calledNoMoreExchanges) {
                transmitter.noMoreExchanges(null);
            }
        }
    }

    public class AsyncCall extends NamedRunnable {

        private final Callback responseCallback;
        private volatile AtomicInteger callsPerHost = new AtomicInteger(0);

        AsyncCall(Callback responseCallback) {
            super("Http %s", redactedUrl());
            this.responseCallback = responseCallback;
        }

        public AtomicInteger callsPerHost() {
            return callsPerHost;
        }

        public void reuseCallsPerHostFrom(AsyncCall other) {
            this.callsPerHost = other.callsPerHost;
        }

        public String host() {
            return originalRequest.url().host();
        }

        Request request() {
            return originalRequest;
        }

        public RealCall get() {
            return RealCall.this;
        }

        /**
         * 尝试在{@code executorService}上排队这个异步调用
         * 如果执行程序已经关闭,则将尝试通过调用失败来进行清理
         */
        public void executeOn(ExecutorService executorService) {
            assert (!Thread.holdsLock(client.dispatcher()));
            boolean success = false;
            try {
                executorService.execute(this);
                success = true;
            } catch (RejectedExecutionException e) {
                InterruptedIOException ioException = new InterruptedIOException("executor rejected");
                ioException.initCause(e);
                transmitter.noMoreExchanges(ioException);
                responseCallback.onFailure(RealCall.this, ioException);
            } finally {
                if (!success) {
                    // 这个回调不再运行
                    client.dispatcher().finished(RealCall.this);
                }
            }
        }

        @Override
        protected void execute() {
            boolean signalledCallback = false;
            transmitter.timeoutEnter();
            try {
                Response response = getResponseWithInterceptorChain();
                signalledCallback = true;
                responseCallback.onResponse(RealCall.this, response);
            } catch (IOException e) {
                if (signalledCallback) {
                    // 不要第二次发送回调信号
                    Logger.info("Callback failure for " + toLoggableString(), e);
                } else {
                    responseCallback.onFailure(RealCall.this, e);
                }
            } catch (Throwable t) {
                cancel();
                if (!signalledCallback) {
                    IOException canceledException = new IOException("canceled due to " + t);
                    canceledException.addSuppressed(t);
                    responseCallback.onFailure(RealCall.this, canceledException);
                }
                throw t;
            } finally {
                client.dispatcher().finished(RealCall.this);
            }
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy