From cfb90597bd07aee0cdd5e53d5c837a903cbb1bd4 Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Sat, 15 Dec 2012 23:05:41 +0000
Subject: [PATCH] Wrapped jSSC's SerialPort and SerialPortList classes for
 testability.

---
 .../briar/plugins/modem/ModemFactoryImpl.java |  2 +-
 .../net/sf/briar/plugins/modem/ModemImpl.java | 43 ++++-------
 .../sf/briar/plugins/modem/ModemPlugin.java   | 11 +--
 .../plugins/modem/ModemPluginFactory.java     |  6 +-
 .../sf/briar/plugins/modem/SerialPort.java    | 23 ++++++
 .../briar/plugins/modem/SerialPortImpl.java   | 73 +++++++++++++++++++
 .../briar/plugins/modem/SerialPortList.java   |  6 ++
 .../plugins/modem/SerialPortListImpl.java     |  8 ++
 8 files changed, 136 insertions(+), 36 deletions(-)
 create mode 100644 briar-core/src/net/sf/briar/plugins/modem/SerialPort.java
 create mode 100644 briar-core/src/net/sf/briar/plugins/modem/SerialPortImpl.java
 create mode 100644 briar-core/src/net/sf/briar/plugins/modem/SerialPortList.java
 create mode 100644 briar-core/src/net/sf/briar/plugins/modem/SerialPortListImpl.java

diff --git a/briar-core/src/net/sf/briar/plugins/modem/ModemFactoryImpl.java b/briar-core/src/net/sf/briar/plugins/modem/ModemFactoryImpl.java
index e51498c458..c6129d6a1f 100644
--- a/briar-core/src/net/sf/briar/plugins/modem/ModemFactoryImpl.java
+++ b/briar-core/src/net/sf/briar/plugins/modem/ModemFactoryImpl.java
@@ -21,6 +21,6 @@ class ModemFactoryImpl implements ModemFactory {
 
 	public Modem createModem(Modem.Callback callback, String portName) {
 		return new ModemImpl(executor, reliabilityFactory, clock, callback,
-				portName);
+				new SerialPortImpl(portName));
 	}
 }
diff --git a/briar-core/src/net/sf/briar/plugins/modem/ModemImpl.java b/briar-core/src/net/sf/briar/plugins/modem/ModemImpl.java
index d227965bbf..44eefebde7 100644
--- a/briar-core/src/net/sf/briar/plugins/modem/ModemImpl.java
+++ b/briar-core/src/net/sf/briar/plugins/modem/ModemImpl.java
@@ -12,10 +12,8 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.logging.Logger;
 
-import jssc.SerialPort;
 import jssc.SerialPortEvent;
 import jssc.SerialPortEventListener;
-import jssc.SerialPortException;
 import net.sf.briar.api.clock.Clock;
 import net.sf.briar.api.reliability.ReliabilityLayer;
 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
 
 	ModemImpl(Executor executor, ReliabilityLayerFactory reliabilityFactory,
-			Clock clock, Callback callback, String portName) {
+			Clock clock, Callback callback, SerialPort port) {
 		this.executor = executor;
 		this.reliabilityFactory = reliabilityFactory;
 		this.clock = clock;
 		this.callback = callback;
-		port = new SerialPort(portName);
+		this.port = port;
 		stateChange = new Semaphore(1);
 		line = new byte[MAX_LINE_LENGTH];
 	}
@@ -67,12 +65,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 		}
 		try {
 			// Open the serial port
-			try {
-				if(!port.openPort())
-					throw new IOException("Failed to open serial port");
-			} catch(SerialPortException e) {
-				throw new IOException(e.toString());
-			}
+				port.openPort();
 			// Find a suitable baud rate and initialise the modem
 			try {
 				boolean foundBaudRate = false;
@@ -90,9 +83,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 				port.addEventListener(this);
 				port.writeBytes("ATZ\r\n".getBytes("US-ASCII")); // Reset
 				port.writeBytes("ATE0\r\n".getBytes("US-ASCII")); // Echo off
-			} catch(SerialPortException e) {
+			} catch(IOException e) {
 				tryToClose(port);
-				throw new IOException(e.toString());
+				throw e;
 			}
 			// Wait for the event thread to receive "OK"
 			boolean success = false;
@@ -122,7 +115,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 	private void tryToClose(SerialPort port) {
 		try {
 			port.closePort();
-		} catch(SerialPortException e) {
+		} catch(IOException e) {
 			if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
 		}
 	}
@@ -145,11 +138,7 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 		}
 		try {
 			hangUpInner();
-			try {
-				port.closePort();
-			} catch(SerialPortException e) {
-				throw new IOException(e.toString());
-			}
+			port.closePort();
 		} finally {
 			stateChange.release();
 		}
@@ -179,9 +168,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 			tryToClose(port);
 			Thread.currentThread().interrupt();
 			throw new IOException("Interrupted while hanging up");
-		} catch(SerialPortException e) {
+		} catch(IOException e) {
 			tryToClose(port);
-			throw new IOException(e.toString());
+			throw e;
 		}
 	}
 
@@ -212,9 +201,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 			try {
 				String dial = "ATDT" + number + "\r\n";
 				port.writeBytes(dial.getBytes("US-ASCII"));
-			} catch(SerialPortException e) {
+			} catch(IOException e) {
 				tryToClose(port);
-				throw new IOException(e.toString());
+				throw e;
 			}
 			// Wait for the event thread to receive "CONNECT"
 			try {
@@ -275,9 +264,9 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 	public void handleWrite(byte[] b) throws IOException {
 		try {
 			port.writeBytes(b);
-		} catch(SerialPortException e) {
+		} catch(IOException e) {
 			tryToClose(port);
-			throw new IOException(e.toString());
+			throw e;
 		}
 	}
 
@@ -297,8 +286,6 @@ class ModemImpl implements Modem, WriteHandler, SerialPortEventListener {
 			}
 		} catch(IOException 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");
 			try {
 				port.writeBytes("ATA\r\n".getBytes("US-ASCII"));
-			} catch(SerialPortException e) {
+			} catch(IOException e) {
 				tryToClose(port);
-				throw new IOException(e.toString());
+				throw e;
 			}
 			// Wait for the event thread to receive "CONNECT"
 			boolean success = false;
diff --git a/briar-core/src/net/sf/briar/plugins/modem/ModemPlugin.java b/briar-core/src/net/sf/briar/plugins/modem/ModemPlugin.java
index 269b289116..7cd0e0af07 100644
--- a/briar-core/src/net/sf/briar/plugins/modem/ModemPlugin.java
+++ b/briar-core/src/net/sf/briar/plugins/modem/ModemPlugin.java
@@ -17,7 +17,6 @@ import java.util.concurrent.Executor;
 import java.util.concurrent.Semaphore;
 import java.util.logging.Logger;
 
-import jssc.SerialPortList;
 import net.sf.briar.api.ContactId;
 import net.sf.briar.api.TransportProperties;
 import net.sf.briar.api.crypto.PseudoRandom;
@@ -41,6 +40,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 
 	private final Executor pluginExecutor;
 	private final ModemFactory modemFactory;
+	private final SerialPortList serialPortList;
 	private final DuplexPluginCallback callback;
 	private final long pollingInterval;
 	private final Semaphore polling;
@@ -49,10 +49,11 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 	private volatile Modem modem = null;
 
 	ModemPlugin(@PluginExecutor Executor pluginExecutor,
-			ModemFactory modemFactory, DuplexPluginCallback callback,
-			long pollingInterval) {
+			ModemFactory modemFactory, SerialPortList serialPortList,
+			DuplexPluginCallback callback, long pollingInterval) {
 		this.pluginExecutor = pluginExecutor;
 		this.modemFactory = modemFactory;
+		this.serialPortList = serialPortList;
 		this.callback = callback;
 		this.pollingInterval = pollingInterval;
 		polling = new Semaphore(1);
@@ -67,7 +68,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 	}
 
 	public boolean start() {
-		for(String portName : SerialPortList.getPortNames()) {
+		for(String portName : serialPortList.getPortNames()) {
 			if(LOG.isLoggable(INFO))
 				LOG.info("Trying to initialise modem on " + portName);
 			modem = modemFactory.createModem(this, portName);
@@ -97,7 +98,7 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback {
 
 	private boolean resetModem() {
 		if(!running) return false;
-		for(String portName : SerialPortList.getPortNames()) {
+		for(String portName : serialPortList.getPortNames()) {
 			modem = modemFactory.createModem(this, portName);
 			try {
 				modem.start();
diff --git a/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java b/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
index d01ec6ab8b..3afdde1d2a 100644
--- a/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
+++ b/briar-core/src/net/sf/briar/plugins/modem/ModemPluginFactory.java
@@ -16,11 +16,13 @@ public class ModemPluginFactory implements DuplexPluginFactory {
 
 	private final Executor pluginExecutor;
 	private final ModemFactory modemFactory;
+	private final SerialPortList serialPortList;
 
 	public ModemPluginFactory(@PluginExecutor Executor pluginExecutor,
 			ReliabilityLayerFactory reliabilityFactory) {
 		this.pluginExecutor = pluginExecutor;
 		modemFactory = new ModemFactoryImpl(pluginExecutor, reliabilityFactory);
+		serialPortList = new SerialPortListImpl();
 	}
 
 	public TransportId getId() {
@@ -31,7 +33,7 @@ public class ModemPluginFactory implements DuplexPluginFactory {
 		// This plugin is not enabled by default
 		String enabled = callback.getConfig().get("enabled");
 		if(StringUtils.isNullOrEmpty(enabled)) return null;
-		return new ModemPlugin(pluginExecutor, modemFactory, callback,
-				POLLING_INTERVAL);
+		return new ModemPlugin(pluginExecutor, modemFactory, serialPortList,
+				callback, POLLING_INTERVAL);
 	}
 }
diff --git a/briar-core/src/net/sf/briar/plugins/modem/SerialPort.java b/briar-core/src/net/sf/briar/plugins/modem/SerialPort.java
new file mode 100644
index 0000000000..0d2b5e4aba
--- /dev/null
+++ b/briar-core/src/net/sf/briar/plugins/modem/SerialPort.java
@@ -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;
+}
diff --git a/briar-core/src/net/sf/briar/plugins/modem/SerialPortImpl.java b/briar-core/src/net/sf/briar/plugins/modem/SerialPortImpl.java
new file mode 100644
index 0000000000..71761e0493
--- /dev/null
+++ b/briar-core/src/net/sf/briar/plugins/modem/SerialPortImpl.java
@@ -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());
+		}
+	}
+}
diff --git a/briar-core/src/net/sf/briar/plugins/modem/SerialPortList.java b/briar-core/src/net/sf/briar/plugins/modem/SerialPortList.java
new file mode 100644
index 0000000000..55e195c61e
--- /dev/null
+++ b/briar-core/src/net/sf/briar/plugins/modem/SerialPortList.java
@@ -0,0 +1,6 @@
+package net.sf.briar.plugins.modem;
+
+interface SerialPortList {
+
+	String[] getPortNames();
+}
diff --git a/briar-core/src/net/sf/briar/plugins/modem/SerialPortListImpl.java b/briar-core/src/net/sf/briar/plugins/modem/SerialPortListImpl.java
new file mode 100644
index 0000000000..b48caa8259
--- /dev/null
+++ b/briar-core/src/net/sf/briar/plugins/modem/SerialPortListImpl.java
@@ -0,0 +1,8 @@
+package net.sf.briar.plugins.modem;
+
+class SerialPortListImpl implements SerialPortList {
+
+	public String[] getPortNames() {
+		return jssc.SerialPortList.getPortNames();
+	}
+}
-- 
GitLab