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

org.bdware.doip.endpoint.client.v3.ResponseWait Maven / Gradle / Ivy

/*
 *    Copyright (c) [2021] [Peking University]
 *    [BDWare DOIP SDK] is licensed under Mulan PSL v2.
 *    You can use this software according to the terms and conditions of the Mulan PSL v2.
 *    You may obtain a copy of Mulan PSL v2 at:
 *             http://license.coscl.org.cn/MulanPSL2
 *    THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *    See the Mulan PSL v2 for more details.
 */

package org.bdware.doip.endpoint.client.v3;

import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bdware.doip.codec.v3.TimeoutMsgFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


public class ResponseWait {
    static Logger LOGGER = LogManager.getLogger(ResponseWait.class);
    public final static HashedWheelTimer HASHED_WHEEL_TIMER = new HashedWheelTimer(r -> {
        Thread t = Executors.defaultThreadFactory().newThread(r);
        t.setDaemon(true);
        return t;
    }, 5, TimeUnit.MILLISECONDS, 2);
    private final TimeoutMsgFactory factory;
    // RecvCounter counter = new RecvCounter("(ResponseWait.java:84)");

    public ResponseWait(TimeoutMsgFactory factory) {
        this.factory = factory;
        //   counter.start();
    }

    // use static map to ensure requestid is !UNIC!
    // in a client(With multiple connection)
    final Map, Timeout>> waitObj = new ConcurrentHashMap<>();

    public static class Pair {
        final T first;
        final U second;

        Pair(T t, U u) {
            this.first = t;
            this.second = u;
        }
    }

    public void wakeUpAndRemove(long requestID, T result) {
        Pair, Timeout> ob = getAndRemove(requestID);
        wakeup(ob, result);
    }

    //DO NOT use synchronized like "private synchronized ..."
    //Because the waitObj is static
    private Pair, Timeout> getAndRemove(long requestID) {
        Pair, Timeout> ob = waitObj.remove(requestID);
        if (ob != null && ob.second != null) {
            ob.second.cancel();
            return ob;
        }
        return null;
    }

    public boolean waitResponseFor5Secs(final long requestID, MessageCallback cb) {
        return waitResponse(requestID, cb, 5);
    }

    public boolean waitResponse(long requestID, MessageCallback cb, int seconds) {
        TimerTask tt = timeout -> {
            T timeOutMessage = factory.createTimoutMessage((long) requestID, null, seconds, "[ResponseWait.waitResponse]");
            wakeUpAndRemove(requestID, timeOutMessage);
            // TODO: 修复潜在的bug
            // 如果requestID重复,可能会移除未处理的回调。
        };
        Timeout timeout = HASHED_WHEEL_TIMER.newTimeout(tt, seconds, TimeUnit.SECONDS);
        Pair, Timeout> value = new Pair<>(cb, timeout);
        Pair, Timeout> oldValue = waitObj.putIfAbsent(requestID, value);
        if (oldValue == null) {
            return true;
        } else {
            LOGGER.debug("Response Wait 返回false,再次尝试!");
            timeout.cancel();
            return false;
        }
    }

    public void wakeup(long requestID, T result) {
        Pair, Timeout> ob = waitObj.get(requestID);
        wakeup(ob, result);
    }

    public void wakeup(Pair, Timeout> ob, T result) {
        if (ob != null) {
            LOGGER.info("cancel timeout timertask");
            ob.second.cancel();
            ob.first.onResult(result);
        } else {
//            LOGGER.info(total.incrementAndGet() + "Try to wakeup empty callback, maybe return too late:" + new Gson().toJson(result));
        }
    }

    static AtomicInteger total = new AtomicInteger(0);
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy