diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 32bd80d..ac413b3 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,5 +21,5 @@ For the best chance of getting your changes incorporated into the code base, ple
* Follow the coding style already established - same indentation, line spacing, naming convention etc.
* ALWAYS provide JUnit tests for your changes - copy existing ones, modify the current versions but there must be supporting unit tests
-* Thorougly comment your code and provide proper JavaDoc headers, even for private methods
+* Thoroughly comment your code and provide proper JavaDoc headers, even for private methods
diff --git a/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java b/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java
index f48af3a..53559bc 100644
--- a/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java
+++ b/src/main/java/com/ghgande/j2mod/modbus/facade/ModbusTCPMaster.java
@@ -21,6 +21,7 @@
import com.ghgande.j2mod.modbus.net.TCPMasterConnection;
import java.net.InetAddress;
+import java.net.SocketException;
import java.net.UnknownHostException;
/**
@@ -194,4 +195,32 @@ public AbstractModbusTransport getTransport() {
public boolean isConnected() {
return connection != null && connection.isConnected();
}
+
+ /**
+ * A {@link ModbusTCPMaster} is equal if the underlying {@link TCPMasterConnection} is equal. There can't be 2
+ * un-identical {@link ModbusTCPMaster}s with the same connection at the same time. One of the two, will raise a
+ * {@link SocketException} if you start both at the same time, since the socket is only usable by exactly on entity
+ *
+ * @param obj Entity to be checked for equality
+ * @return true
if object is equal, false
otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || ModbusTCPMaster.class != obj.getClass()) {
+ return false;
+ } else {
+ ModbusTCPMaster other = (ModbusTCPMaster) obj;
+ return this == obj || this.connection.equals(other.connection);
+ }
+ }
+
+ /**
+ * The unique value of the {@link ModbusTCPMaster} is calculated from the unique value of the {@link TCPMasterConnection}
+ *
+ * @return Unique integer hash code
+ */
+ @Override
+ public int hashCode() {
+ return connection.hashCode();
+ }
}
\ No newline at end of file
diff --git a/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java b/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java
index 14e2977..1352964 100644
--- a/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java
+++ b/src/main/java/com/ghgande/j2mod/modbus/net/TCPMasterConnection.java
@@ -27,6 +27,7 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.util.Objects;
/**
* Class that implements a TCPMasterConnection.
@@ -335,4 +336,33 @@ public void setUseRtuOverTcp(boolean useRtuOverTcp) throws Exception {
prepareTransport(useRtuOverTcp);
}
}
+
+ /**
+ * A {@link TCPMasterConnection} is equal if {@link InetAddress} & port are equal. There is no way how two
+ * different {@link TCPMasterConnection}s can use the same {@link Socket} at the same time, therefore this is good
+ * enough for an equality test
+ *
+ * @param obj Entity to be checked for equality
+ * @return true
if object is equal, false
otherwise
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == null || TCPMasterConnection.class != obj.getClass()) {
+ return false;
+ } else {
+ TCPMasterConnection other = (TCPMasterConnection) obj;
+ return this == obj || this.address.equals(other.address) && this.port == other.port;
+ }
+ }
+
+ /**
+ * The unique value of the {@link TCPMasterConnection} is calculated from the unique values of the
+ * {@link InetAddress} & port
+ *
+ * @return Unique integer hash code
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(address, port);
+ }
}
diff --git a/src/test/java/com/ghgande/j2mod/modbus/TestModbusTCPMasterEquality.java b/src/test/java/com/ghgande/j2mod/modbus/TestModbusTCPMasterEquality.java
new file mode 100644
index 0000000..424e283
--- /dev/null
+++ b/src/test/java/com/ghgande/j2mod/modbus/TestModbusTCPMasterEquality.java
@@ -0,0 +1,51 @@
+package com.ghgande.j2mod.modbus;
+
+import com.ghgande.j2mod.modbus.facade.ModbusTCPMaster;
+import com.ghgande.j2mod.modbus.utils.AbstractTestModbusTCPMaster;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.*;
+
+/**
+ * Testing class for {@link ModbusTCPMaster#equals} & {@link ModbusTCPMaster#hashCode} methods
+ */
+public class TestModbusTCPMasterEquality extends AbstractTestModbusTCPMaster {
+
+ private static final Logger logger = LoggerFactory.getLogger(AbstractTestModbusTCPMaster.class);
+ public static final String LOCALHOST_2 = "127.0.0.2";
+ public static final int PORT_2 = 2503;
+ protected static ModbusTCPMaster master_2, master_3;
+
+ @Test
+ public void testEquality() {
+ master_2 = new ModbusTCPMaster(LOCALHOST_2, PORT);
+ master_3 = new ModbusTCPMaster(LOCALHOST, PORT_2);
+
+ assertThat("2 unequal Modbus TCP masters identified as equal", master, not(equalTo(master_2)));
+ assertThat("2 unequal Modbus TCP masters identified as equal", master, not(equalTo(master_3)));
+ assertThat("2 unequal Modbus TCP masters identified as equal", master_2, not(equalTo(master_3)));
+
+ assertThat("2 equal Modbus TCP masters identified as unequal", master, equalTo(master));
+ assertThat("2 equal Modbus TCP masters identified as unequal", master_2, equalTo(master_2));
+ assertThat("2 equal Modbus TCP masters identified as unequal", master_3, equalTo(master_3));
+ }
+
+ @Test
+ public void testHashCode() {
+ master_2 = new ModbusTCPMaster(LOCALHOST_2, PORT);
+ master_3 = new ModbusTCPMaster(LOCALHOST, PORT_2);
+
+ assertThat("2 unequal Modbus TCP masters had same hash code", master.hashCode(), not(equalTo(master_2.hashCode())));
+ assertThat("2 unequal Modbus TCP masters had same hash code", master.hashCode(), not(equalTo(master_3.hashCode())));
+ assertThat("2 unequal Modbus TCP masters had same hash code", master_2.hashCode(), not(equalTo(master_3.hashCode())));
+
+ assertThat("2 equal Modbus TCP masters had NOT same hash code", master.hashCode(), equalTo(master.hashCode()));
+ assertThat("2 equal Modbus TCP masters had NOT same hash code", master_2.hashCode(), equalTo(master_2.hashCode()));
+ assertThat("2 equal Modbus TCP masters had NOT same hash code", master_3.hashCode(), equalTo(master_3.hashCode()));
+ }
+}