package de.swm.gwt.client.mobile.network;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.inject.Inject;
import de.swm.gwt.client.eventbus.IDispatcher;
import de.swm.gwt.client.mobile.network.rpcservice.NetworkServiceAsync;
import java.util.logging.Logger;
/**
* Ueberwacht die Netzwerkverbindung und sendet Events wenn die Netzwerkverbindung ausfaellt.
*
* @author wiese.daniel <br>
* copyright (C) 2011, SWM Services GmbH
*/
public class NetworkMonitor implements INetworkMonitor {
private static final int DEFAULT_NETWORK_CHECK_INTERVALL_MS = 30 * 1000;
private static final int DEFAULT_NETWORK_CHECK_DELAY_MS = 50;
public static final int MIN_TIMEOUT_MS = 2000;
private static final Logger LOGGER = Logger.getLogger(NetworkMonitor.class.getName());
/**
* Defines the first check intervall after the service was started. *
*/
private int network_check_intervall_network_available_ms;
/**
* Defines the first check intervall after the service was started. *
*/
private int network_check_intervall_network_unavailable_ms;
/**
* Defines the timeout. *
*/
private int timeoutIntervallMs;
/**
* Defines the first check intervall after the service was started. *
*/
private int network_check_delay_ms;
@Inject
private IDispatcher dispatcher;
@Inject
private IVersionControlMonitor versionControlMonitor;
private final NetworkServiceAsync networkService;
private boolean networkAvailable = true;
private Timer timer;
private boolean isStarted = false;
private NativeNetworkHandler nativeNetworkHandler;
/**
* Guice constructor.
*
* @param networkService netwerk service endpoint
*/
@Inject
public NetworkMonitor(NetworkServiceAsync networkService) {
this.networkService = networkService;
//define default check interval > equal for available / unavaiable
setNetworkCheckInterval(DEFAULT_NETWORK_CHECK_INTERVALL_MS);
setNetworkCheckIntervalWhenNotAvailable(DEFAULT_NETWORK_CHECK_INTERVALL_MS);
//define default first initial delay (after the service was started)
setNetworkCheckDelay(DEFAULT_NETWORK_CHECK_DELAY_MS);
calculateTimeout();
}
@Override
public void setNetworkCheckInterval(int pollingFrequenceInMs) {
this.network_check_intervall_network_available_ms = pollingFrequenceInMs;
}
@Override
public void setNetworkCheckIntervalWhenNotAvailable(int networkMonCheckIntervalUnavailableInMs) {
this.network_check_intervall_network_unavailable_ms = networkMonCheckIntervalUnavailableInMs;
}
@Override
public void setNetworkCheckDelay(int delayInMs) {
this.network_check_delay_ms = delayInMs;
}
@Override
public void setNativeHandler(NativeNetworkHandler nativeNetworkHandler) {
this.nativeNetworkHandler = nativeNetworkHandler;
}
/**
* Liefert den aktuellen Network monitoring service.
*
* @return den aktuellen Network monitoring service.
*/
@Override
public NetworkServiceAsync getServiceEndpoint() {
return this.networkService;
}
/**
* {@inheritDoc}
*
* @see INetworkMonitor#startService()
*/
@Override
public void startService() {
startService(NetworkEvents.NETWORK_AVAILABLE);
}
/**
* Starts the service with an default state.
*
* @param defaultState default state
*/
@Override
public void startService(NetworkEvents defaultState) {
if (!isStarted) {
isStarted = true;
// first network request
new NetworkCheckTimer().schedule(network_check_delay_ms);
// repeating network requests
timer = new NetworkCheckTimer();
int initialRepeatInterval = (defaultState.equals(NetworkEvents.NETWORK_AVAILABLE)) ?
network_check_intervall_network_available_ms : network_check_intervall_network_unavailable_ms;
timer.scheduleRepeating(initialRepeatInterval);
// assume the default state
if (defaultState.equals(NetworkEvents.NETWORK_AVAILABLE)) {
networkAvailable = true;
} else {
networkAvailable = false;
}
dispatcher.fireMobileEvent(defaultState);
}
}
/**
* Sendet einen mit einem Timer befirsteten Request zum Server.
*/
public void sendNetworkRequest() {
final AsyncCallback<String> networkCheckResult = new AsyncCallback<String>() {
@Override
public void onFailure(Throwable caught) {
if (networkAvailable) {
networkAvailable = false;
LOGGER.info("Sending Network-Unavailable Event");
if (timer != null) {
timer.cancel();
}
timer = new NetworkCheckTimer();
timer.scheduleRepeating(network_check_intervall_network_unavailable_ms);
dispatcher.fireMobileEvent(NetworkEvents.NETWORK_UNAVAILABLE);
}
}
@Override
public void onSuccess(String result) {
if (result != null && !result.equalsIgnoreCase("OK")) {
// send timestamp to version monitor
versionControlMonitor.publishServerSideVersion(result);
}
if (!networkAvailable) {
networkAvailable = true;
LOGGER.info("Sending Network-Available Event");
if (timer != null) {
timer.cancel();
}
timer = new NetworkCheckTimer();
timer.scheduleRepeating(network_check_intervall_network_available_ms);
dispatcher.fireMobileEvent(NetworkEvents.NETWORK_AVAILABLE);
}
}
};
if (isStarted) {
if (this.nativeNetworkHandler != null && this.nativeNetworkHandler.hasNetwork()) {
networkService.checkNetwork(new AsyncCallbackWithTimeout<String>(networkCheckResult, timeoutIntervallMs));
} else if (this.nativeNetworkHandler == null) {
networkService.checkNetwork(new AsyncCallbackWithTimeout<String>(networkCheckResult, timeoutIntervallMs));
} else {
networkCheckResult.onFailure(null);
}
}
}
@Override
public void stopService() {
if (isStarted) {
isStarted = false;
if (timer != null) {
timer.cancel();
}
//Annahme: Fwenn der service gestoppt wird ist das netz nicht verfugbar
dispatcher.fireMobileEvent(NetworkEvents.NETWORK_UNAVAILABLE);
}
}
private void calculateTimeout() {
this.timeoutIntervallMs = Math.max((Math.min(network_check_intervall_network_available_ms, network_check_intervall_network_unavailable_ms) / 2), MIN_TIMEOUT_MS);
}
private class NetworkCheckTimer extends Timer {
@Override
public void run() {
sendNetworkRequest();
}
}
}