Add a registry of open Serial Ports.

This will be used by components that need to pause an open serial
port to run some other functionality over the port. For example,
Arduino needs to pause the port to run the bootloader. This removes
the need for Serial ports to use o.e.remote.

Change-Id: Idb14598541ccf4e87c702cf2e5442335c64a6c65
diff --git a/native/org.eclipse.cdt.native.serial/META-INF/MANIFEST.MF b/native/org.eclipse.cdt.native.serial/META-INF/MANIFEST.MF
index 5ad3d5c..299809f 100644
--- a/native/org.eclipse.cdt.native.serial/META-INF/MANIFEST.MF
+++ b/native/org.eclipse.cdt.native.serial/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: Serial Port
 Bundle-SymbolicName: org.eclipse.cdt.native.serial
-Bundle-Version: 1.0.0.qualifier
+Bundle-Version: 1.1.0.qualifier
 Bundle-Vendor: Eclipse CDT
 Bundle-RequiredExecutionEnvironment: JavaSE-1.8
 Export-Package: org.eclipse.cdt.serial
diff --git a/native/org.eclipse.cdt.native.serial/src/org/eclipse/cdt/serial/SerialPort.java b/native/org.eclipse.cdt.native.serial/src/org/eclipse/cdt/serial/SerialPort.java
index fb1d39c..24c9002 100644
--- a/native/org.eclipse.cdt.native.serial/src/org/eclipse/cdt/serial/SerialPort.java
+++ b/native/org.eclipse.cdt.native.serial/src/org/eclipse/cdt/serial/SerialPort.java
@@ -15,8 +15,13 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 import org.eclipse.cdt.serial.internal.Messages;
@@ -38,6 +43,8 @@
 
 	private static final String PORT_OPEN = Messages.getString("SerialPort.PortIsOpen"); //$NON-NLS-1$
 
+	private static final Map<String, LinkedList<WeakReference<SerialPort>>> openPorts = new HashMap<>();
+
 	static {
 		try {
 			System.loadLibrary("serial"); //$NON-NLS-1$
@@ -251,6 +258,36 @@
 	}
 
 	/**
+	 * Return an the SerialPort with the given name or null if it hasn't been allocated yet. This
+	 * would be used by components that need to pause and resume a serial port.
+	 * 
+	 * @param portName
+	 * @return
+	 * @since 1.1
+	 */
+	public static SerialPort get(String portName) {
+		synchronized (openPorts) {
+			LinkedList<WeakReference<SerialPort>> list = openPorts.get(portName);
+			if (list == null) {
+				return null;
+			}
+
+			Iterator<WeakReference<SerialPort>> i = list.iterator();
+			while (i.hasNext()) {
+				WeakReference<SerialPort> ref = i.next();
+				SerialPort port = ref.get();
+				if (port == null) {
+					i.remove();
+				} else {
+					return port;
+				}
+			}
+
+			return null;
+		}
+	}
+
+	/**
 	 * Return the name for this serial port.
 	 * 
 	 * @return serial port name
@@ -270,6 +307,15 @@
 	public void open() throws IOException {
 		handle = open0(portName, baudRate.getRate(), byteSize.getSize(), parity.ordinal(), stopBits.ordinal());
 		isOpen = true;
+
+		synchronized (openPorts) {
+			LinkedList<WeakReference<SerialPort>> list = openPorts.get(portName);
+			if (list == null) {
+				list = new LinkedList<>();
+				openPorts.put(portName, list);
+			}
+			list.addFirst(new WeakReference<>(this));
+		}
 	}
 
 	public synchronized void close() throws IOException {
@@ -277,6 +323,21 @@
 			isOpen = false;
 			close0(handle);
 			handle = 0;
+
+			synchronized (openPorts) {
+				LinkedList<WeakReference<SerialPort>> list = openPorts.get(portName);
+				if (list != null) {
+					Iterator<WeakReference<SerialPort>> i = list.iterator();
+					while (i.hasNext()) {
+						WeakReference<SerialPort> ref = i.next();
+						SerialPort port = ref.get();
+						if (port == null || port.equals(this)) {
+							i.remove();
+						}
+					}
+				}
+			}
+
 			try {
 				// Sleep for a second since some serial ports take a while to actually close
 				Thread.sleep(500);