/** * Copyright (c) 2010-2016 by the respective copyright holders. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.openhab.binding.lcn.connection; /** * Manages timeout and retry logic for an LCN request. * * @author Tobias J�ttner */ public class RequestStatus { /** Interval for forced updates. -1 if not used. */ private final long maxAgeMSec; /** Tells how often a request will be sent if no response was received. */ private final int numTries; /** true if request logic is activated. */ private boolean isActive; /** The time the current request was sent out or 0. */ private long currRequestTimeStamp; /** The time stamp of the next scheduled request or 0. */ private long nextRequestTimeStamp; /** Number of retries left until the request is marked as failed. */ private int numRetriesLeft; /** * Constructor. * * @param maxAgeMSec the forced-updates interval (-1 if not used) * @param numTries the maximum number of tries until the request is marked as failed */ RequestStatus(long maxAgeMSec, int numTries) { this.maxAgeMSec = maxAgeMSec; this.numTries = numTries; this.reset(); } /** Resets the runtime data to the initial states. */ void reset() { this.isActive = false; this.currRequestTimeStamp = 0; this.nextRequestTimeStamp = 0; this.numRetriesLeft = 0; } /** * Checks whether the request logic is active. * * @return true if active */ public boolean isActive() { return this.isActive; } /** * Checks whether a request is waiting for a response. * * @return true if waiting for a response */ boolean isPending() { return this.currRequestTimeStamp != 0; } /** * Checks whether the request is active and ran into timeout while waiting for a response. * * @param timeoutMSec the timeout in milliseconds * @param currTime the current time stamp * @return true if request timed out */ boolean isTimeout(long timeoutMSec, long currTime) { return this.isPending() && currTime - this.currRequestTimeStamp >= timeoutMSec * 1000000L; } /** * Checks for failed requests (active and out of retries). * * @param timeoutMSec the timeout in milliseconds * @param currTime the current time stamp * @return true if no response was received and no retries are left */ boolean isFailed(long timeoutMSec, long currTime) { return this.isTimeout(timeoutMSec, currTime) && this.numRetriesLeft == 0; } /** * Schedules the next request. * * @param delayMSec the delay in milliseconds * @param currTime the current time stamp */ public void nextRequestIn(long delayMSec, long currTime) { this.isActive = true; this.nextRequestTimeStamp = currTime + delayMSec * 1000000L; } /** * Checks whether sending a new request is required (should be called periodically). * * @param timeoutMSec the time to wait for a response before retrying the request * @param currTime the current time stamp * @return true to indicate a new request should be sent */ boolean shouldSendNextRequest(long timeoutMSec, long currTime) { if (this.isActive) { if (this.nextRequestTimeStamp != 0 && currTime >= this.nextRequestTimeStamp) { return true; } // Retry of current request (after no response was received) if (this.isTimeout(timeoutMSec, currTime)) { return this.numRetriesLeft > 0; } } return false; } /** * Must be called right after a new request has been sent. * Must be activated first. * * @param currTime the current time stamp */ public void onRequestSent(long currTime) { if (!this.isActive) { throw new Error(); } // Updates retry counter if (this.currRequestTimeStamp == 0) { this.numRetriesLeft = this.numTries - 1; } else if (this.numRetriesLeft > 0) { // Should not happen if used correctly --this.numRetriesLeft; } // Mark request as pending this.currRequestTimeStamp = currTime; // Schedule next request if (this.maxAgeMSec != -1) { this.nextRequestIn(this.maxAgeMSec, currTime); } else { this.nextRequestTimeStamp = 0; } } /** Must be called when a response (requested or not) has been received. */ public void onResponseReceived() { if (this.isActive) { this.currRequestTimeStamp = 0; // Mark request (if any) as successful } } }