package com.openxc.sources;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import com.openxc.messages.VehicleMessage;
/**
* A common parent for all vehicle data sources.
*
* This class encapsulates functionality common to most data sources. It accepts
* and stores a SourceCallback reference (required by the
* {@link com.openxc.sources.VehicleDataSource} interface) and implements a
* {@link #handleMessage(VehicleMessage)} method for subclass to call
* with each new message, regardless of its origin.
*/
public abstract class BaseVehicleDataSource implements VehicleDataSource {
private final static String TAG = "BaseVehicleDataSource";
private SourceCallback mCallback;
private final Lock mCallbackLock = new ReentrantLock();
private final Condition mCallbackChanged = mCallbackLock.newCondition();
public BaseVehicleDataSource() { }
/**
* Construct a new instance and set the callback.
*
* @param callback An object implementing the
* SourceCallback interface that should receive data from this
* source.
*/
public BaseVehicleDataSource(SourceCallback callback) {
setCallback(callback);
}
/**
* Set the current source callback to the given value.
*
* @param callback a valid callback or null if you wish to stop the source
* from sending updates.
*/
@Override
public void setCallback(SourceCallback callback) {
try {
mCallbackLock.lock();
mCallback = callback;
mCallbackChanged.signal();
} finally {
mCallbackLock.unlock();
}
}
protected void disconnected() {
if(mCallback != null) {
mCallback.sourceDisconnected(this);
}
}
protected void connected() {
if(mCallback != null) {
mCallback.sourceConnected(this);
}
}
public abstract boolean isConnected();
/**
* Clear the callback so no further updates are sent.
*
* Subclasses should be sure to call super.stop() so they also stop sending
* updates when killed by a user.
*/
@Override
public void stop() {
disconnected();
setCallback(null);
}
/**
* Pass a new message to the callback, if set.
*
* @param message the new message object.
*/
protected void handleMessage(VehicleMessage message) {
if(message != null) {
message.timestamp();
if(mCallback != null) {
mCallback.receive(message);
}
}
}
protected void waitForCallback() {
try {
mCallbackLock.lock();
if(mCallback == null) {
mCallbackChanged.await();
}
} catch(InterruptedException e) {
} finally {
mCallbackLock.unlock();
}
}
@Override
public void onPipelineActivated() { }
@Override
public void onPipelineDeactivated() { }
/**
* Return a string suitable as a tag for logging.
*/
protected String getTag() {
return TAG;
}
}