net.hasor.rsf.rpc.caller.RsfRequestManager.java Source code

Java tutorial

Introduction

Here is the source code for net.hasor.rsf.rpc.caller.RsfRequestManager.java

Source

/*
 * Copyright 2008-2009 the original author or authors.
 *
 * 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 net.hasor.rsf.rpc.caller;

import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import net.hasor.core.Hasor;
import net.hasor.core.Provider;
import net.hasor.core.future.FutureCallback;
import net.hasor.core.provider.InstanceProvider;
import net.hasor.rsf.*;
import net.hasor.rsf.container.RsfBeanContainer;
import net.hasor.rsf.domain.*;
import net.hasor.rsf.domain.provider.AddressProvider;
import net.hasor.rsf.utils.ProtocolUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * ? RSF ?Manager?????.
 * @version : 2014912
 * @author (zyc@hasor.net)
 */
public abstract class RsfRequestManager {
    protected static Logger logger = LoggerFactory.getLogger(RsfRequestManager.class);
    protected static Logger invLogger = LoggerFactory.getLogger(RsfConstants.LoggerName_Invoker);
    private final ConcurrentMap<Long, RsfFuture> rsfResponse;
    private final RsfContext rsfContext;
    private final AtomicInteger requestCount;
    private final SenderListener senderListener;

    //
    public RsfRequestManager(RsfContext rsfContext, SenderListener senderListener) {
        senderListener = Hasor.assertIsNotNull(senderListener, "not found SendData.");
        this.rsfContext = rsfContext;
        this.rsfResponse = new ConcurrentHashMap<Long, RsfFuture>();
        this.requestCount = new AtomicInteger(0);
        this.senderListener = senderListener;
    }

    /**?RSF*/
    public RsfContext getContext() {
        return this.rsfContext;
    }

    /**?{@link RsfBeanContainer}*/
    public abstract RsfBeanContainer getContainer();

    /**???*/
    private void sendData(Provider<InterAddress> target, RequestInfo info) {
        this.senderListener.sendRequest(target, info);
    }

    //
    /**
     * ?
     * @param requestID ID
     * @return RsfFuture
     */
    public RsfFuture getRequest(long requestID) {
        return this.rsfResponse.get(requestID);
    }

    /**
     * ?Request
     * @param info ?
     */
    public boolean putResponse(ResponseInfo info) {
        long requestID = info.getRequestID();
        RsfFuture rsfFuture = this.rsfResponse.get(requestID);
        if (rsfFuture == null) {
            invLogger.warn("response({}) -> timeoutFailed, RsfFuture is not exist. -> maybe is timeout!",
                    requestID);
            return false;
        }
        //
        // 1.?ACK -> (Invoke,??ACK)
        if (info.getStatus() == ProtocolStatus.Accept) {
            if (!rsfFuture.getRequest().isMessage()) {
                invLogger.info("response({}) -> ignore, rpcType = Invoke, status = Accept", requestID);
                return true;/* Invokerrequest?? ack ,?Message?ACKresponse? */
            }
        }
        //
        // 2.?response
        rsfFuture = this.removeRsfFuture(requestID);
        if (rsfFuture == null) {
            invLogger.warn("response({}) -> timeoutFailed, RsfFuture is not exist. -> maybe is timeout!",
                    requestID);
            return false;
        }
        //
        // 3.???
        RsfRequest rsfRequest = rsfFuture.getRequest();
        RsfResponseObject local = new RsfResponseObject(rsfRequest);
        local.addOptionMap(info);
        local.sendStatus(info.getStatus());
        String serializeType = info.getSerializeType();
        String bindID = local.getBindInfo().getBindID();
        Method callMethod = rsfRequest.getMethod();
        int length = info.getReturnData() == null ? 0 : info.getReturnData().length;
        invLogger.info(
                "response({}) -> receiveTime ={}, serializeType ={}, status ={}, dataLength ={}, isMessage ={}, bindID ={}, callMethod ={}.", //
                requestID, info.getReceiveTime(), serializeType, info.getStatus(), length, rsfRequest.isMessage(),
                bindID, callMethod);
        //
        // - Message 
        if (rsfRequest.isMessage()) {
            Class<?> returnType = rsfRequest.getMethod().getReturnType();
            RsfResultDO returnObject = null;
            if (info.getStatus() == ProtocolStatus.Accept) {
                returnObject = new RsfResultDO(requestID, true);
            } else {
                returnObject = new RsfResultDO(requestID, false);
                returnObject.setErrorCode(info.getStatus());
                returnObject.setErrorMessage(info.getOption("message"));
            }
            //
            if (returnObject.isSuccess()) {
                invLogger.info("response({}) -> successful.", requestID);
                if (returnType.isAssignableFrom(RsfResult.class)) {
                    local.sendData(returnObject);
                    return rsfFuture.completed(local);
                }
                if (returnObject.isSuccess()) {
                    local.sendData(null);
                    return rsfFuture.completed(local);
                }
            }
            //
            String errorInfo = "errorCode = " + returnObject.getErrorCode() + ", errorMessage="
                    + returnObject.getErrorMessage();
            invLogger.error("response({}) -> invokeFailed, {}", requestID, errorInfo);
            return rsfFuture.failed(new RsfException(local.getStatus(), errorInfo));
        }
        // - Invoker 
        if (info.getStatus() == ProtocolStatus.OK) {
            SerializeCoder coder = this.getContext().getEnvironment().getSerializeCoder(serializeType);
            Class<?> returnType = rsfRequest.getMethod().getReturnType();
            try {
                byte[] returnDataData = info.getReturnData();
                Object returnObject = coder.decode(returnDataData, returnType);
                local.sendData(returnObject);
            } catch (Throwable e) {
                invLogger.error(
                        "response({}) -> serializeFailed, bindID ={}, serializeType ={}, callMethod ={}, dataType ={}, message ={}.", //
                        requestID, bindID, serializeType, callMethod, returnType, e.getMessage(), e);
                return rsfFuture.failed(e);
            }
            return rsfFuture.completed(local);
        } else {
            invLogger.error("response({}) -> statusFailed, bindID ={}, status ={}.", //
                    requestID, bindID, local.getStatus());
            return rsfFuture.failed(new RsfException(local.getStatus(), "status."));
        }
    }

    /**
     * ?Request
     * @param requestID ID
     * @param e ?
     */
    public void putResponse(long requestID, Throwable e) {
        RsfFuture rsfFuture = this.removeRsfFuture(requestID);
        if (rsfFuture != null) {
            invLogger.error("response({}) -> errorFailed, {}", requestID, e.getMessage(), e);
            rsfFuture.failed(e);
        } else {
            invLogger.error("response({}) -> errorFailed, RsfFuture is not exist. -> maybe is timeout! ,error= {}.",
                    requestID, e.getMessage(), e);
        }
    }

    private RsfFuture removeRsfFuture(long requestID) {
        RsfFuture rsfFuture = this.rsfResponse.remove(requestID);
        if (rsfFuture != null) {
            this.requestCount.decrementAndGet();// i--;
        }
        return rsfFuture;
    }

    /**
     * ??RSF
     * @param rsfRequest rsf
     * @param listener FutureCallback?
     * @return RsfFuture
     */
    protected RsfFuture doSendRequest(RsfRequestFormLocal rsfRequest, FutureCallback<RsfResponse> listener) {
        RsfBindInfo<?> bindInfo = rsfRequest.getBindInfo();
        String serviceID = bindInfo.getBindID();
        final RsfFuture rsfFuture = new RsfFuture(rsfRequest, listener);
        invLogger.info("request({}) -> doSendRequest, bindID ={}, callMethod ={}, isMessage ={}.", //
                rsfRequest.getRequestID(), serviceID, rsfRequest.getMethod(), bindInfo.isMessage());
        //
        if (bindInfo.isMessage()) {
            rsfRequest.addOption("RPC_TYPE", "MESSAGE");
        } else {
            rsfRequest.addOption("RPC_TYPE", "INVOKER");
        }
        rsfRequest.addOptionMap(this.getContext().getSettings().getClientOption());//??Server
        Provider<RsfFilter>[] rsfFilterList = this.getContainer().getFilterProviders(serviceID);
        RsfResponseObject res = new RsfResponseObject(rsfRequest);
        //
        try {
            /*??? -> rsfFiltersendRequest??*/
            new RsfFilterHandler(rsfFilterList, new RsfFilterChain() {
                public void doFilter(RsfRequest request, RsfResponse response) throws Throwable {
                    if (response.isResponse()) {
                        invLogger.info("request({}) -> sendRequest, response form local.", request.getRequestID());
                        rsfFuture.completed(response);//???????
                    } else {
                        invLogger.info("request({}) -> sendRequest, response wait for remote.",
                                request.getRequestID());
                        sendRequest(rsfFuture);//??
                    }
                }
            }).doFilter(rsfRequest, res);
        } catch (Throwable e) {
            invLogger.error("request({}) -> errorFailed, sendRequest, doRsfFilterChain. error ={}.",
                    rsfRequest.getRequestID(), e.getMessage(), e);
            try {
                rsfFuture.failed(e);
            } catch (Throwable e2) {
                logger.error("request({}) -> {}.", rsfRequest.getRequestID(), e2.getMessage(), e2);
            }
        }
        return rsfFuture;
    }

    /**???*/
    private void sendRequest(final RsfFuture rsfFuture) throws Throwable {
        /*1.*/
        final RsfRequestFormLocal rsfRequest = (RsfRequestFormLocal) rsfFuture.getRequest();
        final AddressProvider target = rsfRequest.getTarget();
        String serviceID = rsfRequest.getBindInfo().getBindID();
        invLogger.info(
                "request({}) -> bindID ={}, callMethod ={}, serializeType ={}, isMessage ={}, isP2PCalls ={}.", //
                rsfRequest.getRequestID(), serviceID, rsfRequest.getMethod(), rsfRequest.getSerializeType(),
                rsfRequest.isMessage(), rsfRequest.isP2PCalls());
        //
        /*2.?????*/
        RsfSettings rsfSettings = this.getContainer().getEnvironment().getSettings();
        if (this.requestCount.get() >= rsfSettings.getMaximumRequest()) {
            SendLimitPolicy sendPolicy = rsfSettings.getSendLimitPolicy();
            String errorMessage = "request(" + rsfRequest.getRequestID()
                    + ") -> sendDataFailed, maximum number of requests, apply SendPolicy = " + sendPolicy.name();
            invLogger.error(errorMessage);
            if (sendPolicy == SendLimitPolicy.Reject) {
                // - A.
                throw new RsfException(ProtocolStatus.SendLimitPolicy, errorMessage);
            } else {
                // - B.1??????
                try {
                    Thread.sleep(1000);/*SendLimitPolicy.WaitSecond*/
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(), e);
                }
                if (this.requestCount.get() >= rsfSettings.getMaximumRequest()) {
                    invLogger.error(errorMessage);
                    throw new RsfException(ProtocolStatus.SendLimitPolicy, errorMessage);
                }
            }
        }
        /*3.???*/
        String methodName = rsfRequest.getMethod().getName();
        Object[] args = rsfRequest.getParameterObject();
        InterAddress address = target.get(serviceID, methodName, args);
        if (address == null) {
            invLogger.warn("request({}) -> targetAddress Unavailable, bindID ={}.", rsfRequest.getRequestID(),
                    serviceID);
            rsfFuture.failed(
                    new RsfException(ProtocolStatus.Forbidden, "Service [" + serviceID + "] Address Unavailable."));
            return;
        }
        if (rsfRequest.isP2PCalls()) {
            rsfRequest.addOption(OptionKeys.TargetAddress, address.toHostSchema());
        }
        /*4.??*/
        try {
            Provider<InterAddress> targetProvider = new InstanceProvider<InterAddress>(address);
            invLogger.warn("request({}) -> pre sendData, bindID ={}, targetAddress ={}.", rsfRequest.getRequestID(),
                    serviceID, address);
            RsfEnvironment environment = this.getContext().getEnvironment();
            startRequest(rsfFuture); // <- 1.request
            RequestInfo info = ProtocolUtils.buildRequestInfo(environment, rsfRequest); // <- 2.?RequestInfo
            sendData(targetProvider, info); // <- 3.???
        } catch (Throwable e) {
            invLogger.error("request(" + rsfRequest.getRequestID() + ") send error, " + e.getMessage(), e);
            putResponse(rsfRequest.getRequestID(), e);
        }
    }

    /**
     * ?
     * @param rsfFuture 
     */
    private void startRequest(RsfFuture rsfFuture) {
        this.requestCount.incrementAndGet();// i++;
        this.rsfResponse.put(rsfFuture.getRequest().getRequestID(), rsfFuture);
        final RsfRequestFormLocal request = (RsfRequestFormLocal) rsfFuture.getRequest();
        TimerTask timeTask = new TimerTask() {
            public void run(Timeout timeoutObject) throws Exception {
                RsfFuture rsfCallBack = getRequest(request.getRequestID());
                /*???*/
                if (rsfCallBack == null)
                    return;
                /*?*/
                String errorInfo = "request(" + request.getRequestID() + ") -> timeout for client.";
                invLogger.error(errorInfo);
                /*Response*/
                putResponse(request.getRequestID(), new RsfTimeoutException(errorInfo));
            }
        };
        invLogger.info("request({}) -> startRequest, timeout at {} ,bindID ={}, callMethod ={}.", //
                request.getRequestID(), request.getTimeout(), request.getBindInfo().getBindID(),
                request.getMethod());
        this.getContext().getEnvironment().atTime(timeTask, request.getTimeout());
    }
}