/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.communication.routing.internal;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.core.communication.common.InstanceNodeSessionId;
import de.rcenvironment.core.communication.model.NetworkRequest;
import de.rcenvironment.core.communication.model.NetworkResponse;
import de.rcenvironment.core.communication.model.NetworkResponseHandler;
import de.rcenvironment.core.communication.protocol.NetworkResponseFactory;
import de.rcenvironment.core.utils.common.LogUtils;
import de.rcenvironment.core.utils.incubator.DebugSettings;
/**
* A helper class for waiting asynchronously for a single {@link NetworkResponse}. Used for connecting callback- and Future-based call
* variants.
*
* @author Robert Mischke
*/
public class WaitForResponseBlocker implements NetworkResponseHandler {
private static final boolean VERBOSE_LOGGING = DebugSettings.getVerboseLoggingEnabled(WaitForResponseBlocker.class);
// this class is instantiated frequently, so save the overhead of logger fetching with a static instance - misc_ro
private static final Log sharedLog = LogFactory.getLog(WaitForResponseBlocker.class);
private final NetworkRequest request;
private final InstanceNodeSessionId eventNodeId;
private final CountDownLatch responseReceivedLatch;
private NetworkResponse response;
private volatile String logMarker = null;
public WaitForResponseBlocker(NetworkRequest request, InstanceNodeSessionId localNodeId) {
this.request = request;
this.eventNodeId = localNodeId;
this.responseReceivedLatch = new CountDownLatch(1);
}
@Override
public void onResponseAvailable(NetworkResponse receivedResponse) {
this.response = receivedResponse;
responseReceivedLatch.countDown();
}
/**
* Waits until a {@link NetworkResponse} was received via {@link #onResponseAvailable(NetworkResponse)}, or until the given timeout has
* elapsed. In both cases, a {@link NetworkResponse} is returned; there are no timeout exceptions.
*
* @param requestTimeoutMsec the maximum time to wait, in msec
* @return the result wrapper; either the actual response, or a timeout representation
*/
public NetworkResponse await(long requestTimeoutMsec) {
if (VERBOSE_LOGGING) {
sharedLog.debug("Waiting for response callback (" + logMarker + ")");
}
try {
if (responseReceivedLatch.await(requestTimeoutMsec, TimeUnit.MILLISECONDS)) {
if (VERBOSE_LOGGING) {
sharedLog.debug("Received response callback (" + logMarker + ")");
}
return response;
} else {
sharedLog.debug("Timeout reached while waiting for a network response to request " + request.getRequestId());
// TODO test/verify that a "null" cause does not trigger downstream NPEs
return NetworkResponseFactory.generateResponseForTimeoutWaitingForResponse(request, eventNodeId);
}
} catch (InterruptedException e) {
String errorId = LogUtils.logErrorAndAssignUniqueMarker(sharedLog,
"Interrupted while waiting for a network response: " + e.toString()); // stacktrace irrelevant
return NetworkResponseFactory.generateResponseForErrorDuringDelivery(request, eventNodeId, errorId);
}
}
public void setLogMarker(String logMarker) {
this.logMarker = logMarker;
}
}