Wrapped jSSC's SerialPort and SerialPortList classes for testability.

This commit is contained in:
akwizgran
2012-12-15 23:05:41 +00:00
parent b090a12b7f
commit cfb90597bd
8 changed files with 136 additions and 36 deletions

View File

@@ -21,6 +21,6 @@ class ModemFactoryImpl implements ModemFactory {
public Modem createModem(Modem.Callback callback, String portName) { public Modem createModem(Modem.Callback callback, String portName) {
return new ModemImpl(executor, reliabilityFactory, clock, callback, return new ModemImpl(executor, reliabilityFactory, clock, callback,
portName); new SerialPortImpl(portName));
} }
} }

View File

@@ -12,10 +12,8 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.logging.Logger; import java.util.logging.Logger;
import jssc.SerialPort;
import jssc.SerialPortEvent; import jssc.SerialPortEvent;
import jssc.SerialPortEventListener; import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import net.sf.briar.api.clock.Clock; import net.sf.briar.api.clock.Clock;
import net.sf.briar.api.reliability.ReliabilityLayer; import net.sf.briar.api.reliability.ReliabilityLayer;
import net.sf.briar.api.reliability.ReliabilityLayerFactory; import net.sf.briar.api.reliability.ReliabilityLayerFactory;
@@ -47,12 +45,12 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private boolean initialised = false, connected = false; // Locking: this private boolean initialised = false, connected = false; // Locking: this
ModemImpl(Executor executor, ReliabilityLayerFactory reliabilityFactory, ModemImpl(Executor executor, ReliabilityLayerFactory reliabilityFactory,
Clock clock, Callback callback, String portName) { Clock clock, Callback callback, SerialPort port) {
this.executor = executor; this.executor = executor;
this.reliabilityFactory = reliabilityFactory; this.reliabilityFactory = reliabilityFactory;
this.clock = clock; this.clock = clock;
this.callback = callback; this.callback = callback;
port = new SerialPort(portName); this.port = port;
stateChange = new Semaphore(1); stateChange = new Semaphore(1);
line = new byte[MAX_LINE_LENGTH]; line = new byte[MAX_LINE_LENGTH];
} }
@@ -67,12 +65,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
} }
try { try {
// Open the serial port // Open the serial port
try { port.openPort();
if(!port.openPort())
throw new IOException("Failed to open serial port");
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
// Find a suitable baud rate and initialise the modem // Find a suitable baud rate and initialise the modem
try { try {
boolean foundBaudRate = false; boolean foundBaudRate = false;
@@ -90,9 +83,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
port.addEventListener(this); port.addEventListener(this);
port.writeBytes("ATZ\r\n".getBytes("US-ASCII")); // Reset port.writeBytes("ATZ\r\n".getBytes("US-ASCII")); // Reset
port.writeBytes("ATE0\r\n".getBytes("US-ASCII")); // Echo off port.writeBytes("ATE0\r\n".getBytes("US-ASCII")); // Echo off
} catch(SerialPortException e) { } catch(IOException e) {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw e;
} }
// Wait for the event thread to receive "OK" // Wait for the event thread to receive "OK"
boolean success = false; boolean success = false;
@@ -122,7 +115,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
private void tryToClose(SerialPort port) { private void tryToClose(SerialPort port) {
try { try {
port.closePort(); port.closePort();
} catch(SerialPortException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -145,11 +138,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
} }
try { try {
hangUpInner(); hangUpInner();
try { port.closePort();
port.closePort();
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
} finally { } finally {
stateChange.release(); stateChange.release();
} }
@@ -179,9 +168,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
tryToClose(port); tryToClose(port);
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
throw new IOException("Interrupted while hanging up"); throw new IOException("Interrupted while hanging up");
} catch(SerialPortException e) { } catch(IOException e) {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw e;
} }
} }
@@ -212,9 +201,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
try { try {
String dial = "ATDT" + number + "\r\n"; String dial = "ATDT" + number + "\r\n";
port.writeBytes(dial.getBytes("US-ASCII")); port.writeBytes(dial.getBytes("US-ASCII"));
} catch(SerialPortException e) { } catch(IOException e) {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw e;
} }
// Wait for the event thread to receive "CONNECT" // Wait for the event thread to receive "CONNECT"
try { try {
@@ -275,9 +264,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
public void handleWrite(byte[] b) throws IOException { public void handleWrite(byte[] b) throws IOException {
try { try {
port.writeBytes(b); port.writeBytes(b);
} catch(SerialPortException e) { } catch(IOException e) {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw e;
} }
} }
@@ -297,8 +286,6 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
} }
} catch(IOException e) { } catch(IOException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} catch(SerialPortException e) {
if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} }
} }
@@ -391,9 +378,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
if(LOG.isLoggable(INFO)) LOG.info("Answering"); if(LOG.isLoggable(INFO)) LOG.info("Answering");
try { try {
port.writeBytes("ATA\r\n".getBytes("US-ASCII")); port.writeBytes("ATA\r\n".getBytes("US-ASCII"));
} catch(SerialPortException e) { } catch(IOException e) {
tryToClose(port); tryToClose(port);
throw new IOException(e.toString()); throw e;
} }
// Wait for the event thread to receive "CONNECT" // Wait for the event thread to receive "CONNECT"
boolean success = false; boolean success = false;

View File

@@ -17,7 +17,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.logging.Logger; import java.util.logging.Logger;
import jssc.SerialPortList;
import net.sf.briar.api.ContactId; import net.sf.briar.api.ContactId;
import net.sf.briar.api.TransportProperties; import net.sf.briar.api.TransportProperties;
import net.sf.briar.api.crypto.PseudoRandom; import net.sf.briar.api.crypto.PseudoRandom;
@@ -41,6 +40,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
private final Executor pluginExecutor; private final Executor pluginExecutor;
private final ModemFactory modemFactory; private final ModemFactory modemFactory;
private final SerialPortList serialPortList;
private final DuplexPluginCallback callback; private final DuplexPluginCallback callback;
private final long pollingInterval; private final long pollingInterval;
private final Semaphore polling; private final Semaphore polling;
@@ -49,10 +49,11 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
private volatile Modem modem = null; private volatile Modem modem = null;
ModemPlugin(@PluginExecutor Executor pluginExecutor, ModemPlugin(@PluginExecutor Executor pluginExecutor,
ModemFactory modemFactory, DuplexPluginCallback callback, ModemFactory modemFactory, SerialPortList serialPortList,
long pollingInterval) { DuplexPluginCallback callback, long pollingInterval) {
this.pluginExecutor = pluginExecutor; this.pluginExecutor = pluginExecutor;
this.modemFactory = modemFactory; this.modemFactory = modemFactory;
this.serialPortList = serialPortList;
this.callback = callback; this.callback = callback;
this.pollingInterval = pollingInterval; this.pollingInterval = pollingInterval;
polling = new Semaphore(1); polling = new Semaphore(1);
@@ -67,7 +68,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
} }
public boolean start() { public boolean start() {
for(String portName : SerialPortList.getPortNames()) { for(String portName : serialPortList.getPortNames()) {
if(LOG.isLoggable(INFO)) if(LOG.isLoggable(INFO))
LOG.info("Trying to initialise modem on " + portName); LOG.info("Trying to initialise modem on " + portName);
modem = modemFactory.createModem(this, portName); modem = modemFactory.createModem(this, portName);
@@ -97,7 +98,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
private boolean resetModem() { private boolean resetModem() {
if(!running) return false; if(!running) return false;
for(String portName : SerialPortList.getPortNames()) { for(String portName : serialPortList.getPortNames()) {
modem = modemFactory.createModem(this, portName); modem = modemFactory.createModem(this, portName);
try { try {
modem.start(); modem.start();

View File

@@ -16,11 +16,13 @@ public class ModemPluginFactory implements DuplexPluginFactory {
private final Executor pluginExecutor; private final Executor pluginExecutor;
private final ModemFactory modemFactory; private final ModemFactory modemFactory;
private final SerialPortList serialPortList;
public ModemPluginFactory(@PluginExecutor Executor pluginExecutor, public ModemPluginFactory(@PluginExecutor Executor pluginExecutor,
ReliabilityLayerFactory reliabilityFactory) { ReliabilityLayerFactory reliabilityFactory) {
this.pluginExecutor = pluginExecutor; this.pluginExecutor = pluginExecutor;
modemFactory = new ModemFactoryImpl(pluginExecutor, reliabilityFactory); modemFactory = new ModemFactoryImpl(pluginExecutor, reliabilityFactory);
serialPortList = new SerialPortListImpl();
} }
public TransportId getId() { public TransportId getId() {
@@ -31,7 +33,7 @@ public class ModemPluginFactory implements DuplexPluginFactory {
// This plugin is not enabled by default // This plugin is not enabled by default
String enabled = callback.getConfig().get("enabled"); String enabled = callback.getConfig().get("enabled");
if(StringUtils.isNullOrEmpty(enabled)) return null; if(StringUtils.isNullOrEmpty(enabled)) return null;
return new ModemPlugin(pluginExecutor, modemFactory, callback, return new ModemPlugin(pluginExecutor, modemFactory, serialPortList,
POLLING_INTERVAL); callback, POLLING_INTERVAL);
} }
} }

View File

@@ -0,0 +1,23 @@
package net.sf.briar.plugins.modem;
import java.io.IOException;
import jssc.SerialPortEventListener;
interface SerialPort {
void openPort() throws IOException;
void closePort() throws IOException;
boolean setParams(int baudRate, int dataBits, int stopBits, int parityBits)
throws IOException;
void purgePort(int flags) throws IOException;
void addEventListener(SerialPortEventListener l) throws IOException;
byte[] readBytes() throws IOException;
void writeBytes(byte[] b) throws IOException;
}

View File

@@ -0,0 +1,73 @@
package net.sf.briar.plugins.modem;
import java.io.IOException;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
class SerialPortImpl implements SerialPort {
private final jssc.SerialPort port;
SerialPortImpl(String portName) {
port = new jssc.SerialPort(portName);
}
public void openPort() throws IOException {
try {
if(!port.openPort()) throw new IOException("Failed to open port");
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public void closePort() throws IOException {
try {
if(!port.closePort()) throw new IOException("Failed to close port");
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public boolean setParams(int baudRate, int dataBits, int stopBits,
int parityBits) throws IOException {
try {
return port.setParams(baudRate, dataBits, stopBits, parityBits);
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public void purgePort(int flags) throws IOException {
try {
if(!port.purgePort(flags))
throw new IOException("Failed to purge port");
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public void addEventListener(SerialPortEventListener l) throws IOException {
try {
port.addEventListener(l);
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public byte[] readBytes() throws IOException {
try {
return port.readBytes();
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
public void writeBytes(byte[] b) throws IOException {
try {
if(!port.writeBytes(b)) throw new IOException("Failed to write");
} catch(SerialPortException e) {
throw new IOException(e.toString());
}
}
}

View File

@@ -0,0 +1,6 @@
package net.sf.briar.plugins.modem;
interface SerialPortList {
String[] getPortNames();
}

View File

@@ -0,0 +1,8 @@
package net.sf.briar.plugins.modem;
class SerialPortListImpl implements SerialPortList {
public String[] getPortNames() {
return jssc.SerialPortList.getPortNames();
}
}