mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Converted ReliabilityLayer into an interface for better testability.
This commit is contained in:
@@ -5,12 +5,15 @@ import java.util.concurrent.Executor;
|
||||
class ModemFactoryImpl implements ModemFactory {
|
||||
|
||||
private final Executor executor;
|
||||
private final ReliabilityLayerFactory reliabilityFactory;
|
||||
|
||||
ModemFactoryImpl(Executor executor) {
|
||||
ModemFactoryImpl(Executor executor,
|
||||
ReliabilityLayerFactory reliabilityFactory) {
|
||||
this.executor = executor;
|
||||
this.reliabilityFactory = reliabilityFactory;
|
||||
}
|
||||
|
||||
public Modem createModem(Modem.Callback callback, String portName) {
|
||||
return new ModemImpl(executor, callback, portName);
|
||||
return new ModemImpl(executor, reliabilityFactory, callback, portName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
private static final int CONNECT_TIMEOUT = 2 * 60 * 1000; // Milliseconds
|
||||
|
||||
private final Executor executor;
|
||||
private final ReliabilityLayerFactory reliabilityFactory;
|
||||
private final Callback callback;
|
||||
private final SerialPort port;
|
||||
private final Semaphore stateChange;
|
||||
@@ -36,11 +37,13 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
|
||||
private int lineLen = 0;
|
||||
|
||||
private ReliabilityLayer reliabilityLayer = null; // Locking: this
|
||||
private ReliabilityLayer reliability = null; // Locking: this
|
||||
private boolean initialised = false, connected = false; // Locking: this
|
||||
|
||||
ModemImpl(Executor executor, Callback callback, String portName) {
|
||||
ModemImpl(Executor executor, ReliabilityLayerFactory reliabilityFactory,
|
||||
Callback callback, String portName) {
|
||||
this.executor = executor;
|
||||
this.reliabilityFactory = reliabilityFactory;
|
||||
this.callback = callback;
|
||||
port = new SerialPort(portName);
|
||||
stateChange = new Semaphore(1);
|
||||
@@ -142,18 +145,18 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
|
||||
// Locking: stateChange
|
||||
private void hangUpInner() throws IOException {
|
||||
ReliabilityLayer reliabilityLayer;
|
||||
ReliabilityLayer reliability;
|
||||
synchronized(this) {
|
||||
if(this.reliabilityLayer == null) {
|
||||
if(this.reliability == null) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Not hanging up - already on the hook");
|
||||
return;
|
||||
}
|
||||
reliabilityLayer = this.reliabilityLayer;
|
||||
this.reliabilityLayer = null;
|
||||
reliability = this.reliability;
|
||||
this.reliability = null;
|
||||
connected = false;
|
||||
}
|
||||
reliabilityLayer.stop();
|
||||
reliability.stop();
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Hanging up");
|
||||
try {
|
||||
port.setDTR(false);
|
||||
@@ -170,22 +173,22 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
ReliabilityLayer reliabilityLayer =
|
||||
new ReliabilityLayer(executor, this);
|
||||
ReliabilityLayer reliability =
|
||||
reliabilityFactory.createReliabilityLayer(this);
|
||||
synchronized(this) {
|
||||
if(!initialised) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Not dialling - modem not initialised");
|
||||
return false;
|
||||
}
|
||||
if(this.reliabilityLayer != null) {
|
||||
if(this.reliability != null) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Not dialling - call in progress");
|
||||
return false;
|
||||
}
|
||||
this.reliabilityLayer = reliabilityLayer;
|
||||
this.reliability = reliability;
|
||||
}
|
||||
reliabilityLayer.start();
|
||||
reliability.start();
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Dialling");
|
||||
try {
|
||||
String dial = "ATDT" + number + "\r\n";
|
||||
@@ -218,21 +221,21 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException {
|
||||
ReliabilityLayer reliabilityLayer;
|
||||
ReliabilityLayer reliability;
|
||||
synchronized(this) {
|
||||
reliabilityLayer = this.reliabilityLayer;
|
||||
reliability = this.reliability;
|
||||
}
|
||||
if(reliabilityLayer == null) throw new IOException("Not connected");
|
||||
return reliabilityLayer.getInputStream();
|
||||
if(reliability == null) throw new IOException("Not connected");
|
||||
return reliability.getInputStream();
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
ReliabilityLayer reliabilityLayer;
|
||||
ReliabilityLayer reliability;
|
||||
synchronized(this) {
|
||||
reliabilityLayer = this.reliabilityLayer;
|
||||
reliability = this.reliability;
|
||||
}
|
||||
if(reliabilityLayer == null) throw new IOException("Not connected");
|
||||
return reliabilityLayer.getOutputStream();
|
||||
if(reliability == null) throw new IOException("Not connected");
|
||||
return reliability.getOutputStream();
|
||||
}
|
||||
|
||||
public void hangUp() throws IOException {
|
||||
@@ -280,12 +283,12 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
}
|
||||
|
||||
private boolean handleData(byte[] b) throws IOException {
|
||||
ReliabilityLayer reliabilityLayer;
|
||||
ReliabilityLayer reliability;
|
||||
synchronized(this) {
|
||||
reliabilityLayer = this.reliabilityLayer;
|
||||
reliability = this.reliability;
|
||||
}
|
||||
if(reliabilityLayer == null) return false;
|
||||
reliabilityLayer.handleRead(b);
|
||||
if(reliability == null) return false;
|
||||
reliability.handleRead(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -349,22 +352,22 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ReliabilityLayer reliabilityLayer =
|
||||
new ReliabilityLayer(executor, this);
|
||||
ReliabilityLayer reliability =
|
||||
reliabilityFactory.createReliabilityLayer(this);
|
||||
synchronized(this) {
|
||||
if(!initialised) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Not answering - modem not initialised");
|
||||
return;
|
||||
}
|
||||
if(this.reliabilityLayer != null) {
|
||||
if(this.reliability != null) {
|
||||
if(LOG.isLoggable(INFO))
|
||||
LOG.info("Not answering - call in progress");
|
||||
return;
|
||||
}
|
||||
this.reliabilityLayer = reliabilityLayer;
|
||||
this.reliability = reliability;
|
||||
}
|
||||
reliabilityLayer.start();
|
||||
reliability.start();
|
||||
if(LOG.isLoggable(INFO)) LOG.info("Answering");
|
||||
try {
|
||||
port.writeBytes("ATA\r\n".getBytes("US-ASCII"));
|
||||
|
||||
@@ -28,7 +28,10 @@ public class ModemPluginFactory implements DuplexPluginFactory {
|
||||
// This plugin is not enabled by default
|
||||
String enabled = callback.getConfig().get("enabled");
|
||||
if(StringUtils.isNullOrEmpty(enabled)) return null;
|
||||
ModemFactory modemFactory = new ModemFactoryImpl(pluginExecutor);
|
||||
ReliabilityLayerFactory reliabilityFactory =
|
||||
new ReliabilityLayerFactoryImpl(pluginExecutor);
|
||||
ModemFactory modemFactory = new ModemFactoryImpl(pluginExecutor,
|
||||
reliabilityFactory);
|
||||
return new ModemPlugin(pluginExecutor, modemFactory, callback,
|
||||
POLLING_INTERVAL);
|
||||
}
|
||||
|
||||
@@ -1,103 +1,15 @@
|
||||
package net.sf.briar.plugins.modem;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
class ReliabilityLayer implements ReadHandler, WriteHandler {
|
||||
interface ReliabilityLayer extends ReadHandler, WriteHandler {
|
||||
|
||||
private static final int TICK_INTERVAL = 500; // Milliseconds
|
||||
void start();
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ReliabilityLayer.class.getName());
|
||||
void stop();
|
||||
|
||||
private final Executor executor;
|
||||
private final WriteHandler writeHandler;
|
||||
private final BlockingQueue<byte[]> writes;
|
||||
InputStream getInputStream();
|
||||
|
||||
private volatile Receiver receiver = null;
|
||||
private volatile SlipDecoder decoder = null;
|
||||
private volatile ReceiverInputStream inputStream = null;
|
||||
private volatile SenderOutputStream outputStream = null;
|
||||
private volatile boolean running = false;
|
||||
|
||||
ReliabilityLayer(Executor executor, WriteHandler writeHandler) {
|
||||
this.executor = executor;
|
||||
this.writeHandler = writeHandler;
|
||||
writes = new LinkedBlockingQueue<byte[]>();
|
||||
}
|
||||
|
||||
void start() {
|
||||
SlipEncoder encoder = new SlipEncoder(this);
|
||||
final Sender sender = new Sender(encoder);
|
||||
receiver = new Receiver(sender);
|
||||
decoder = new SlipDecoder(receiver);
|
||||
inputStream = new ReceiverInputStream(receiver);
|
||||
outputStream = new SenderOutputStream(sender);
|
||||
running = true;
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
long now = System.currentTimeMillis();
|
||||
long next = now + TICK_INTERVAL;
|
||||
try {
|
||||
while(running) {
|
||||
byte[] b = null;
|
||||
while(now < next && b == null) {
|
||||
b = writes.poll(next - now, MILLISECONDS);
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
if(b == null) {
|
||||
sender.tick();
|
||||
while(next <= now) next += TICK_INTERVAL;
|
||||
} else {
|
||||
if(b.length == 0) return; // Poison pill
|
||||
writeHandler.handleWrite(b);
|
||||
}
|
||||
}
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.warning("Interrupted while waiting to write");
|
||||
Thread.currentThread().interrupt();
|
||||
running = false;
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
running = false;
|
||||
receiver.invalidate();
|
||||
writes.add(new byte[0]); // Poison pill
|
||||
}
|
||||
|
||||
// The modem calls this method to pass data up to the SLIP decoder
|
||||
public void handleRead(byte[] b) throws IOException {
|
||||
if(!running) throw new IOException("Connection closed");
|
||||
decoder.handleRead(b);
|
||||
}
|
||||
|
||||
// The SLIP encoder calls this method to pass data down to the modem
|
||||
public void handleWrite(byte[] b) throws IOException {
|
||||
if(!running) throw new IOException("Connection closed");
|
||||
if(b.length > 0) writes.add(b);
|
||||
}
|
||||
OutputStream getOutputStream();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.sf.briar.plugins.modem;
|
||||
|
||||
interface ReliabilityLayerFactory {
|
||||
|
||||
ReliabilityLayer createReliabilityLayer(WriteHandler writeHandler);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.sf.briar.plugins.modem;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
class ReliabilityLayerFactoryImpl implements ReliabilityLayerFactory {
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
ReliabilityLayerFactoryImpl(Executor executor) {
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
public ReliabilityLayer createReliabilityLayer(WriteHandler writeHandler) {
|
||||
return new ReliabilityLayerImpl(executor, writeHandler);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package net.sf.briar.plugins.modem;
|
||||
|
||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||
import static java.util.logging.Level.WARNING;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
class ReliabilityLayerImpl implements ReliabilityLayer {
|
||||
|
||||
private static final int TICK_INTERVAL = 500; // Milliseconds
|
||||
|
||||
private static final Logger LOG =
|
||||
Logger.getLogger(ReliabilityLayerImpl.class.getName());
|
||||
|
||||
private final Executor executor;
|
||||
private final WriteHandler writeHandler;
|
||||
private final BlockingQueue<byte[]> writes;
|
||||
|
||||
private volatile Receiver receiver = null;
|
||||
private volatile SlipDecoder decoder = null;
|
||||
private volatile ReceiverInputStream inputStream = null;
|
||||
private volatile SenderOutputStream outputStream = null;
|
||||
private volatile boolean running = false;
|
||||
|
||||
ReliabilityLayerImpl(Executor executor, WriteHandler writeHandler) {
|
||||
this.executor = executor;
|
||||
this.writeHandler = writeHandler;
|
||||
writes = new LinkedBlockingQueue<byte[]>();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
SlipEncoder encoder = new SlipEncoder(this);
|
||||
final Sender sender = new Sender(encoder);
|
||||
receiver = new Receiver(sender);
|
||||
decoder = new SlipDecoder(receiver);
|
||||
inputStream = new ReceiverInputStream(receiver);
|
||||
outputStream = new SenderOutputStream(sender);
|
||||
running = true;
|
||||
executor.execute(new Runnable() {
|
||||
public void run() {
|
||||
long now = System.currentTimeMillis();
|
||||
long next = now + TICK_INTERVAL;
|
||||
try {
|
||||
while(running) {
|
||||
byte[] b = null;
|
||||
while(now < next && b == null) {
|
||||
b = writes.poll(next - now, MILLISECONDS);
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
if(b == null) {
|
||||
sender.tick();
|
||||
while(next <= now) next += TICK_INTERVAL;
|
||||
} else {
|
||||
if(b.length == 0) return; // Poison pill
|
||||
writeHandler.handleWrite(b);
|
||||
}
|
||||
}
|
||||
} catch(InterruptedException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.warning("Interrupted while waiting to write");
|
||||
Thread.currentThread().interrupt();
|
||||
running = false;
|
||||
} catch(IOException e) {
|
||||
if(LOG.isLoggable(WARNING))
|
||||
LOG.log(WARNING, e.toString(), e);
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
running = false;
|
||||
receiver.invalidate();
|
||||
writes.add(new byte[0]); // Poison pill
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
return outputStream;
|
||||
}
|
||||
|
||||
// The transport calls this method to pass data up to the SLIP decoder
|
||||
public void handleRead(byte[] b) throws IOException {
|
||||
if(!running) throw new IOException("Connection closed");
|
||||
decoder.handleRead(b);
|
||||
}
|
||||
|
||||
// The SLIP encoder calls this method to pass data down to the transport
|
||||
public void handleWrite(byte[] b) throws IOException {
|
||||
if(!running) throw new IOException("Connection closed");
|
||||
if(b.length > 0) writes.add(b);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user