mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-25 01:41:43 +00:00
Initial checkin of unified hierarchy of WPILib 2015
This commit is contained in:
84
networktables/java/Athena/pom.xml
Normal file
84
networktables/java/Athena/pom.xml
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<parent>
|
||||
<groupId>edu.wpi.first.wpilib.templates.athena</groupId>
|
||||
<artifactId>library-jar</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>WPILib Repository</id>
|
||||
<url>http://frcbuilder.wpi.edu:8348/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmock</groupId>
|
||||
<artifactId>jmock-junit4</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmock</groupId>
|
||||
<artifactId>jmock-legacy</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
<testExcludes>
|
||||
<exclude>edu/wpi/first/wpilibj/networktables2/system/SystemTest.java</exclude>
|
||||
</testExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>../src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,27 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* An object that will provide socket connections when a client connects to the server on the given port (for standard java VM)
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketServerStreamProvider implements IOStreamProvider{
|
||||
|
||||
private ServerSocket server = null;
|
||||
public SocketServerStreamProvider(int port) throws IOException{
|
||||
server = new ServerSocket(port);
|
||||
}
|
||||
|
||||
public IOStream accept() throws IOException {
|
||||
Socket socket = server.accept();
|
||||
return new SocketStream(socket);
|
||||
}
|
||||
public void close() throws IOException {
|
||||
if(server!=null)
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* A socket connection on a standard Java VM
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketStream extends SimpleIOStream{
|
||||
|
||||
private final Socket socket;
|
||||
public SocketStream(String host, int port) throws IOException {
|
||||
this(new Socket(host, port));
|
||||
}
|
||||
public SocketStream(Socket socket) throws IOException {
|
||||
super(socket.getInputStream(), socket.getOutputStream());
|
||||
this.socket = socket;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
try{
|
||||
socket.close();
|
||||
} catch(IOException e){}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketStreamFactory implements IOStreamFactory{
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
public SocketStreamFactory(String host, int port) throws IOException {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IOStream createStream() throws IOException {
|
||||
return new SocketStream(host, port);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
public final class SocketStreams {
|
||||
private SocketStreams(){}
|
||||
|
||||
public static IOStreamFactory newStreamFactory(String host, int port) throws IOException{
|
||||
return new SocketStreamFactory(host, port);
|
||||
}
|
||||
|
||||
public static IOStreamProvider newStreamProvider(int port) throws IOException {
|
||||
return new SocketServerStreamProvider(port);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.client.NetworkTableClient;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.IOStream;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.IOStreamFactory;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
import java.io.*;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.auto.Mock;
|
||||
import org.jmock.integration.junit4.JMock;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class NetworkTableListenerTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
private NetworkTableClient client;
|
||||
private NetworkTableProvider provider;
|
||||
private NetworkTable testTable1;
|
||||
private NetworkTable testTable2;
|
||||
private NetworkTable testTable3;
|
||||
private NetworkTable testSubTable1;
|
||||
private NetworkTable testSubTable2;
|
||||
private NetworkTable testSubTable3;
|
||||
private NetworkTable testSubTable4;
|
||||
|
||||
|
||||
|
||||
@Before
|
||||
public void init() throws IOException{
|
||||
client = new NetworkTableClient(new IOStreamFactory(){
|
||||
public IOStream createStream() throws IOException {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
provider = new NetworkTableProvider(client);
|
||||
testTable1 = (NetworkTable)provider.getTable("/test1");
|
||||
testTable2 = (NetworkTable)provider.getTable("/test2");
|
||||
testSubTable1 = (NetworkTable)provider.getTable("/test2/sub1");
|
||||
testSubTable2 = (NetworkTable)provider.getTable("/test2/sub2");
|
||||
testTable3 = (NetworkTable)provider.getTable("/test3");
|
||||
testSubTable3 = (NetworkTable)provider.getTable("/test3/suba");
|
||||
testSubTable4 = (NetworkTable)provider.getTable("/test3/suba/subb");
|
||||
}
|
||||
@After
|
||||
public void cleanup(){
|
||||
provider.close();
|
||||
}
|
||||
|
||||
@Mock ITableListener listener1;
|
||||
@Mock ITableListener listener2;
|
||||
|
||||
|
||||
@Test
|
||||
public void keyListenerImediateNotifyTest() throws IOException {
|
||||
testTable1.putBoolean("MyKey1", true);
|
||||
testTable1.putBoolean("MyKey1", false);
|
||||
testTable1.putBoolean("MyKey2", true);
|
||||
testTable1.putBoolean("MyKey4", false);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey1", false, true);
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey2", true, true);
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey4", false, true);
|
||||
}});
|
||||
testTable1.addTableListener(listener1, true);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey", false, true);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey", false);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey1", true, false);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey1", true);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey1", false, false);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey1", false);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey4", true, false);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey4", true);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void keyListenerNotImediateNotifyTest() throws IOException {
|
||||
testTable1.putBoolean("MyKey1", true);
|
||||
testTable1.putBoolean("MyKey1", false);
|
||||
testTable1.putBoolean("MyKey2", true);
|
||||
testTable1.putBoolean("MyKey4", false);
|
||||
testTable1.addTableListener(listener1, false);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey", false, true);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey", false);
|
||||
context.assertIsSatisfied();
|
||||
/*context.checking(new Expectations() {{Should not fire because value was previously false
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey1", false, false);
|
||||
}});*/
|
||||
testTable1.putBoolean("MyKey1", false);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey1", true, false);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey1", true);
|
||||
context.assertIsSatisfied();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable1, "MyKey4", true, false);
|
||||
}});
|
||||
testTable1.putBoolean("MyKey4", true);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subTableListenerTest() throws IOException {
|
||||
testTable2.putBoolean("MyKey1", true);
|
||||
testTable2.putBoolean("MyKey2", true);
|
||||
testTable2.addSubTableListener(listener1);
|
||||
testTable2.putBoolean("MyKey1", false);
|
||||
testTable2.putBoolean("MyKey4", false);
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable2, "sub1", testSubTable1, true);
|
||||
}});
|
||||
testSubTable1.putBoolean("MyKey1", false);
|
||||
context.assertIsSatisfied();
|
||||
testSubTable1.putBoolean("MyKey2", true);
|
||||
testSubTable1.putBoolean("MyKey1", true);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable2, "sub2", testSubTable2, true);
|
||||
}});
|
||||
testSubTable2.putBoolean("MyKey1", false);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subSubTableListenerTest() throws IOException {
|
||||
testTable3.addSubTableListener(listener1);
|
||||
testSubTable3.addSubTableListener(listener1);
|
||||
testSubTable4.addTableListener(listener1, true);
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testTable3, "suba", testSubTable3, true);
|
||||
oneOf(listener1).valueChanged(testSubTable3, "subb", testSubTable4, true);
|
||||
oneOf(listener1).valueChanged(testSubTable4, "MyKey1", false, true);
|
||||
}});
|
||||
testSubTable4.putBoolean("MyKey1", false);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener1).valueChanged(testSubTable4, "MyKey1", true, false);
|
||||
}});
|
||||
testSubTable4.putBoolean("MyKey1", true);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listener2).valueChanged(testTable3, "suba", testSubTable3, true);
|
||||
oneOf(listener2).valueChanged(testSubTable3, "subb", testSubTable4, true);
|
||||
oneOf(listener2).valueChanged(testSubTable4, "MyKey1", true, true);
|
||||
}});
|
||||
testTable3.addSubTableListener(listener2);
|
||||
testSubTable3.addSubTableListener(listener2);
|
||||
testSubTable4.addTableListener(listener2, true);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.client.NetworkTableClient;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.IOStream;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.IOStreamFactory;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
import java.io.*;
|
||||
import org.junit.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
public class NetworkTableTest {
|
||||
private NetworkTableClient client;
|
||||
private NetworkTableProvider provider;
|
||||
private NetworkTable testTable1;
|
||||
private NetworkTable testTable2;
|
||||
|
||||
@Before
|
||||
public void init() throws IOException{
|
||||
client = new NetworkTableClient(new IOStreamFactory(){
|
||||
public IOStream createStream() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
provider = new NetworkTableProvider(client);
|
||||
testTable1 = (NetworkTable)provider.getTable("/test1");
|
||||
testTable2 = (NetworkTable)provider.getTable("/test2");
|
||||
}
|
||||
@After
|
||||
public void cleanup(){
|
||||
provider.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putDoubleTest() throws IOException {
|
||||
double testDouble = 43.43;
|
||||
testTable1.putNumber("double", 42.42);
|
||||
try {
|
||||
testDouble = testTable1.getNumber("double");
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals(42.42, testDouble, 0.0);
|
||||
try {
|
||||
testDouble = testTable1.getNumber("Non-Existant");
|
||||
fail();
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
}
|
||||
testDouble = testTable1.getNumber("Non-Existant", 44.44);
|
||||
assertEquals(44.44, testDouble, 0.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putBooleanTest() throws IOException {
|
||||
boolean testBool = false;
|
||||
testTable1.putBoolean("boolean", true);
|
||||
try {
|
||||
testBool = testTable1.getBoolean("boolean");
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertTrue(testBool);
|
||||
try {
|
||||
testBool = testTable1.getBoolean("Non-Existant");
|
||||
fail();
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
}
|
||||
testBool = testTable1.getBoolean("Non-Existant", false);
|
||||
assertFalse(testBool);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putStringTest() throws IOException {
|
||||
String testString = "Initialized Test";
|
||||
testTable1.putString("String", "Test 1");
|
||||
try {
|
||||
testString = testTable1.getString("String");
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
assertEquals("Test 1", testString);
|
||||
try {
|
||||
testString = testTable1.getString("Non-Existant");
|
||||
fail();
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
}
|
||||
testString = testTable1.getString("Non-Existant", "Test 3");
|
||||
assertEquals("Test 3", testString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void putMultiDataTypeTest() throws TableKeyNotDefinedException, IOException {
|
||||
double double1 = 1;
|
||||
double double2 = 2;
|
||||
double double3 = 3;
|
||||
boolean bool1 = false;
|
||||
boolean bool2 = true;
|
||||
String string1 = "String 1";
|
||||
String string2 = "String 2";
|
||||
String string3 = "String 3";
|
||||
|
||||
testTable1.putNumber("double1", double1);
|
||||
testTable1.putNumber("double2", double2);
|
||||
testTable1.putNumber("double3", double3);
|
||||
testTable1.putBoolean("bool1", bool1);
|
||||
testTable1.putBoolean("bool2", bool2);
|
||||
testTable1.putString("string1", string1);
|
||||
testTable1.putString("string2", string2);
|
||||
testTable1.putString("string3", string3);
|
||||
|
||||
assertEquals(double1, testTable1.getNumber("double1"), 0.0);
|
||||
assertEquals(double2, testTable1.getNumber("double2"), 0.0);
|
||||
assertEquals(double3, testTable1.getNumber("double3"), 0.0);
|
||||
assertEquals(bool1, testTable1.getBoolean("bool1"));
|
||||
assertEquals(bool2, testTable1.getBoolean("bool2"));
|
||||
assertEquals(string1, testTable1.getString("string1"));
|
||||
assertEquals(string2, testTable1.getString("string2"));
|
||||
assertEquals(string3, testTable1.getString("string3"));
|
||||
|
||||
double1 = 4;
|
||||
double2 = 5;
|
||||
double3 = 6;
|
||||
bool1 = true;
|
||||
bool2 = false;
|
||||
string1 = "String 4";
|
||||
string2 = "String 5";
|
||||
string3 = "String 6";
|
||||
|
||||
testTable1.putNumber("double1", double1);
|
||||
testTable1.putNumber("double2", double2);
|
||||
testTable1.putNumber("double3", double3);
|
||||
testTable1.putBoolean("bool1", bool1);
|
||||
testTable1.putBoolean("bool2", bool2);
|
||||
testTable1.putString("string1", string1);
|
||||
testTable1.putString("string2", string2);
|
||||
testTable1.putString("string3", string3);
|
||||
|
||||
assertEquals(double1, testTable1.getNumber("double1"), 0.0);
|
||||
assertEquals(double2, testTable1.getNumber("double2"), 0.0);
|
||||
assertEquals(double3, testTable1.getNumber("double3"), 0.0);
|
||||
assertEquals(bool1, testTable1.getBoolean("bool1"));
|
||||
assertEquals(bool2, testTable1.getBoolean("bool2"));
|
||||
assertEquals(string1, testTable1.getString("string1"));
|
||||
assertEquals(string2, testTable1.getString("string2"));
|
||||
assertEquals(string3, testTable1.getString("string3"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiTableTest() throws IOException {
|
||||
double table1double = 1;
|
||||
double table2double = 2;
|
||||
boolean table1boolean = true;
|
||||
boolean table2boolean = false;
|
||||
String table1String = "Table 1";
|
||||
String table2String = "Table 2";
|
||||
|
||||
testTable1.putNumber("table1double", table1double);
|
||||
testTable1.putBoolean("table1boolean", table1boolean);
|
||||
testTable1.putString("table1String", table1String);
|
||||
|
||||
try {
|
||||
testTable2.getNumber("table1double");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
try {
|
||||
testTable2.getBoolean("table1boolean");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
try {
|
||||
testTable2.getString("table1String");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
|
||||
testTable2.putNumber("table2double", table2double);
|
||||
testTable2.putBoolean("table2boolean", table2boolean);
|
||||
testTable2.putString("table2String", table2String);
|
||||
|
||||
try {
|
||||
testTable1.getNumber("table2double");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
try {
|
||||
testTable1.getBoolean("table2boolean");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
try {
|
||||
testTable1.getString("table2String");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getTableTest() throws IOException{
|
||||
assertSame(testTable1, provider.getTable("/test1"));
|
||||
assertSame(testTable2, provider.getTable("/test2"));
|
||||
assertNotSame(testTable1, provider.getTable("/test2"));
|
||||
ITable testTable3 = provider.getTable("/test3");
|
||||
assertNotSame(testTable1, testTable3);
|
||||
assertNotSame(testTable2, testTable3);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.AbstractNetworkTableEntryStore.TableListenerManager;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class NetworkTableEntryTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testSendValue() throws IOException {
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final Object value = "MyValue";
|
||||
final NetworkTableEntry entry = new NetworkTableEntry((char)0, "MyKey", (char)0, type, value);
|
||||
final DataOutputStream os = context.mock(DataOutputStream.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(type).sendValue(value, os);
|
||||
}});
|
||||
|
||||
entry.sendValue(os);
|
||||
}
|
||||
|
||||
@Test public void testToString() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newBooleanEntry("MyKey", false);
|
||||
assertEquals( "Network Table Boolean entry: MyKey: 65535 - 0 - false", entry.toString());
|
||||
}
|
||||
|
||||
@Test public void testSend() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newBooleanEntry((char)0, "MyBoolean", (char)0, true);
|
||||
final NetworkTableConnection connection = context.mock(NetworkTableConnection.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connection).sendEntryAssignment(entry);
|
||||
}});
|
||||
|
||||
entry.send(connection);
|
||||
}
|
||||
|
||||
@Test public void testConstructor() throws IOException {
|
||||
final NetworkTableEntry entry = new NetworkTableEntry((char)10, "MyNotBoolean", (char)2, DefaultEntryTypes.STRING, "Test1");
|
||||
assertEquals((char)10, entry.getId());
|
||||
assertEquals("MyNotBoolean", entry.name);
|
||||
assertEquals((char)2, entry.getSequenceNumber());
|
||||
assertEquals(DefaultEntryTypes.STRING, entry.getType());
|
||||
assertEquals("Test1", entry.getValue());
|
||||
}
|
||||
|
||||
|
||||
@Test public void testPut() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry((char)10, "MyString", (char)2, "Test1");
|
||||
assertTrue(entry.putValue((char)3, "Test5"));
|
||||
assertEquals("Test5", entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
|
||||
assertTrue(entry.putValue((char)4, "Test2"));
|
||||
assertEquals("Test2", entry.getValue());
|
||||
assertEquals((char)4, entry.getSequenceNumber());
|
||||
|
||||
assertFalse(entry.putValue((char)3, "Test3"));
|
||||
assertEquals("Test2", entry.getValue());
|
||||
assertEquals((char)4, entry.getSequenceNumber());
|
||||
|
||||
assertFalse(entry.putValue((char)40000, "Test22"));
|
||||
assertEquals("Test2", entry.getValue());
|
||||
assertEquals((char)4, entry.getSequenceNumber());
|
||||
|
||||
assertTrue(entry.putValue((char)30000, "Test10"));
|
||||
assertEquals("Test10", entry.getValue());
|
||||
assertEquals((char)30000, entry.getSequenceNumber());
|
||||
|
||||
assertTrue(entry.putValue((char)40000, "Test23"));
|
||||
assertEquals("Test23", entry.getValue());
|
||||
assertEquals((char)40000, entry.getSequenceNumber());
|
||||
|
||||
assertFalse(entry.putValue((char)30000, "Test100"));
|
||||
assertEquals("Test23", entry.getValue());
|
||||
assertEquals((char)40000, entry.getSequenceNumber());
|
||||
|
||||
assertTrue(entry.putValue((char)0, "Test0"));
|
||||
assertEquals("Test0", entry.getValue());
|
||||
assertEquals((char)0, entry.getSequenceNumber());
|
||||
}
|
||||
|
||||
@Test public void testSetWhenValid() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry("MyString", "Test1");
|
||||
entry.setId((char)100);
|
||||
}
|
||||
@Test public void testSetWhenNotValid() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry((char)10, "MyString", (char)2, "Test1");
|
||||
try{
|
||||
entry.setId((char)100);
|
||||
fail();
|
||||
} catch(RuntimeException e){
|
||||
}
|
||||
}
|
||||
@Test public void testClearId() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newDoubleEntry("MyString", 203.2);
|
||||
entry.setId((char)10);
|
||||
assertEquals((char)10, entry.getId());
|
||||
entry.clearId();
|
||||
assertEquals(NetworkTableEntry.UNKNOWN_ID, entry.getId());
|
||||
entry.setId((char)22);
|
||||
assertEquals((char)22, entry.getId());
|
||||
}
|
||||
|
||||
@Test public void testDirtyness() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newDoubleEntry("MyString", 203.2);
|
||||
assertEquals(false, entry.isDirty());
|
||||
entry.makeClean();
|
||||
assertEquals(false, entry.isDirty());
|
||||
entry.makeDirty();
|
||||
assertEquals(true, entry.isDirty());
|
||||
entry.makeClean();
|
||||
assertEquals(false, entry.isDirty());
|
||||
}
|
||||
|
||||
@Test public void testForcePut() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry((char)10, "MyString", (char)2, "Test1");
|
||||
entry.forcePut((char)3, "Test5");
|
||||
assertEquals("Test5", entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)4, "Test2");
|
||||
assertEquals("Test2", entry.getValue());
|
||||
assertEquals((char)4, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)3, "Test3");
|
||||
assertEquals("Test3", entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)40000, "Test22");
|
||||
assertEquals("Test22", entry.getValue());
|
||||
assertEquals((char)40000, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)30000, "Test10");
|
||||
assertEquals("Test10", entry.getValue());
|
||||
assertEquals((char)30000, entry.getSequenceNumber());
|
||||
}
|
||||
|
||||
@Test public void testForcePutWithType() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry((char)10, "MyString", (char)2, "Test1");
|
||||
entry.forcePut((char)3, DefaultEntryTypes.BOOLEAN, true);
|
||||
assertEquals(DefaultEntryTypes.BOOLEAN, entry.getType());
|
||||
assertEquals(true, entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)4, DefaultEntryTypes.STRING, "HELLO");
|
||||
assertEquals("HELLO", entry.getValue());
|
||||
assertEquals(DefaultEntryTypes.STRING, entry.getType());
|
||||
assertEquals((char)4, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)3, DefaultEntryTypes.DOUBLE, 11.5);
|
||||
assertEquals(DefaultEntryTypes.DOUBLE, entry.getType());
|
||||
assertEquals(11.5, entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
|
||||
entry.forcePut((char)3, DefaultEntryTypes.STRING, "HI");
|
||||
assertEquals(DefaultEntryTypes.STRING, entry.getType());
|
||||
assertEquals("HI", entry.getValue());
|
||||
assertEquals((char)3, entry.getSequenceNumber());
|
||||
}
|
||||
|
||||
@Test public void testFireListener() throws IOException {
|
||||
final NetworkTableEntry entry = NetworkTableEntryUtil.newStringEntry((char)10, "MyString", (char)2, "Test1");
|
||||
final TableListenerManager listenerManager = context.mock(TableListenerManager.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listenerManager).fireTableListeners("MyString", "Test1", true);
|
||||
}});
|
||||
entry.fireListener(listenerManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listenerManager).fireTableListeners("MyString", "Test1", false);
|
||||
}});
|
||||
entry.fireListener(listenerManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
entry.forcePut((char)0, "TEST3");
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(listenerManager).fireTableListeners("MyString", "TEST3", false);
|
||||
}});
|
||||
entry.fireListener(listenerManager);
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.auto.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class TransactionDirtierTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Mock OutgoingEntryReceiver receiver;
|
||||
TransactionDirtier dirtier;
|
||||
@Before public void before(){
|
||||
dirtier = new TransactionDirtier(receiver);
|
||||
}
|
||||
|
||||
@Test public void testOutgoingCleanAssignment() throws IOException {
|
||||
final NetworkTableEntry entry = context.mock(NetworkTableEntry.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(entry).isDirty();will(returnValue(false));
|
||||
oneOf(entry).makeDirty();
|
||||
oneOf(receiver).offerOutgoingAssignment(entry);
|
||||
}});
|
||||
|
||||
dirtier.offerOutgoingAssignment(entry);
|
||||
}
|
||||
@Test public void testOutgoingCleanUpdate() throws IOException {
|
||||
final NetworkTableEntry entry = context.mock(NetworkTableEntry.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(entry).isDirty();will(returnValue(false));
|
||||
oneOf(entry).makeDirty();
|
||||
oneOf(receiver).offerOutgoingUpdate(entry);
|
||||
}});
|
||||
|
||||
dirtier.offerOutgoingUpdate(entry);
|
||||
}
|
||||
|
||||
|
||||
@Test public void testOutgoingDirtyAssignment() throws IOException {
|
||||
final NetworkTableEntry entry = context.mock(NetworkTableEntry.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(entry).isDirty();will(returnValue(true));
|
||||
}});
|
||||
|
||||
dirtier.offerOutgoingAssignment(entry);
|
||||
}
|
||||
@Test public void testOutgoingDirtyUpdate() throws IOException {
|
||||
final NetworkTableEntry entry = context.mock(NetworkTableEntry.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(entry).isDirty();will(returnValue(true));
|
||||
}});
|
||||
|
||||
dirtier.offerOutgoingUpdate(entry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.core.IsInstanceOf.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.hamcrest.Description;
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.BadMessageException;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ClientConnectionAdapterTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testKeepAlive() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
|
||||
ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
try{
|
||||
clientAdapter.keepAlive();
|
||||
} catch(BadMessageException e){
|
||||
fail();
|
||||
} catch(IOException e){
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void testClientHello() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
|
||||
ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
try{
|
||||
clientAdapter.clientHello((char)0);
|
||||
fail();
|
||||
} catch(BadMessageException e){
|
||||
} catch(IOException e){
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void testUnsupportedProtocol() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
final NTThread thread = context.mock(NTThread.class);
|
||||
|
||||
|
||||
ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
try {
|
||||
context.checking(new Expectations() {{
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread));
|
||||
oneOf(entryStore).clearIds();
|
||||
}});
|
||||
} catch (IOException e1) {}
|
||||
clientAdapter.reconnect();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(stream).close();
|
||||
oneOf(thread).stop();
|
||||
oneOf(entryStore).clearIds();
|
||||
}});
|
||||
clientAdapter.protocolVersionUnsupported((char)10);
|
||||
assertThat(clientAdapter.getConnectionState(), instanceOf(ClientConnectionState.ProtocolUnsuppotedByServer.class));
|
||||
assertEquals((char)10, ((ClientConnectionState.ProtocolUnsuppotedByServer)clientAdapter.getConnectionState()).getServerVersion());
|
||||
}
|
||||
|
||||
@Test public void testConnectionErrorBadMessage() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
final NTThread thread = context.mock(NTThread.class);
|
||||
|
||||
|
||||
ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
try {
|
||||
context.checking(new Expectations() {{
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread));
|
||||
oneOf(entryStore).clearIds();
|
||||
}});
|
||||
} catch (IOException e1) {}
|
||||
clientAdapter.reconnect();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(stream).close();
|
||||
oneOf(thread).stop();
|
||||
oneOf(entryStore).clearIds();
|
||||
}});
|
||||
BadMessageException e = new BadMessageException("");
|
||||
clientAdapter.badMessage(e);
|
||||
assertThat(clientAdapter.getConnectionState(), isClientConnectionErrorState(e));
|
||||
}
|
||||
|
||||
@Test public void testConnectionErrorIOException() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream1 = context.mock(IOStream.class, "stream1");
|
||||
final IOStream stream2 = context.mock(IOStream.class, "stream2");
|
||||
final NTThread thread1 = context.mock(NTThread.class, "thread1");
|
||||
final NTThread thread2 = context.mock(NTThread.class, "thread2");
|
||||
|
||||
final ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
try {
|
||||
context.checking(new Expectations() {{
|
||||
allowing(stream1).getInputStream();
|
||||
allowing(stream1).getOutputStream();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream1));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread1));
|
||||
oneOf(entryStore).clearIds();
|
||||
}});
|
||||
} catch (IOException e1) {}
|
||||
clientAdapter.reconnect();
|
||||
try {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(stream1).close();
|
||||
oneOf(thread1).stop();
|
||||
oneOf(entryStore).clearIds();
|
||||
allowing(stream2).getInputStream();
|
||||
allowing(stream2).getOutputStream();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream2));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread2));
|
||||
}});
|
||||
} catch (IOException e1) {}
|
||||
IOException e = new IOException("");
|
||||
clientAdapter.ioException(e);
|
||||
assertEquals(clientAdapter.getConnectionState(), ClientConnectionState.CONNECTED_TO_SERVER);
|
||||
}
|
||||
|
||||
@Test public void testGetEntryType() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
|
||||
final NetworkTableEntry entry1 = NetworkTableEntryUtil.newBooleanEntry("MyEntry", true);
|
||||
final NetworkTableEntry entry2 = NetworkTableEntryUtil.newDoubleEntry("MyEntry", 12);
|
||||
final NetworkTableEntry entry3 = NetworkTableEntryUtil.newStringEntry("MyEntry", "Value");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(entryStore).getEntry((char)16);will(returnValue(entry1));
|
||||
allowing(entryStore).getEntry((char)1);will(returnValue(entry2));
|
||||
allowing(entryStore).getEntry((char)22);will(returnValue(entry3));
|
||||
}});
|
||||
|
||||
ClientConnectionAdapter clientAdapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
|
||||
assertEquals(DefaultEntryTypes.BOOLEAN, clientAdapter.getEntry((char)16).getType());
|
||||
assertEquals(DefaultEntryTypes.DOUBLE, clientAdapter.getEntry((char)1).getType());
|
||||
assertEquals(DefaultEntryTypes.STRING, clientAdapter.getEntry((char)22).getType());
|
||||
}
|
||||
|
||||
|
||||
private Matcher<ClientConnectionState> isClientConnectionErrorState(final Exception e) {
|
||||
return new TypeSafeMatcher<ClientConnectionState>() {
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText(" a connection error state with the exception ").appendValue(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(ClientConnectionState item) {
|
||||
if(item instanceof ClientConnectionState.Error)
|
||||
return ((ClientConnectionState.Error) item).getException()==e;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ClientConnectionManagementTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testReconnect() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream1 = context.mock(IOStream.class, "stream1");
|
||||
final IOStream stream2 = context.mock(IOStream.class, "stream2");
|
||||
final NTThread thread1 = context.mock(NTThread.class, "thread1");
|
||||
final NTThread thread2 = context.mock(NTThread.class, "thread2");
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
try{
|
||||
allowing(stream1).getInputStream();
|
||||
allowing(stream1).getOutputStream();
|
||||
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream1));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread1));
|
||||
} catch(IOException e){}
|
||||
}});
|
||||
|
||||
ClientConnectionAdapter client = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
client.reconnect();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
try{
|
||||
allowing(stream2).getInputStream();
|
||||
allowing(stream2).getOutputStream();
|
||||
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(thread1).stop();
|
||||
oneOf(stream1).close();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream2));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread2));
|
||||
} catch(IOException e){}
|
||||
}});
|
||||
client.reconnect();
|
||||
}
|
||||
|
||||
@Test public void testClose() {
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream1 = context.mock(IOStream.class);
|
||||
final NTThread thread1 = context.mock(NTThread.class, "thread1");
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
try{
|
||||
allowing(stream1).getInputStream();
|
||||
allowing(stream1).getOutputStream();
|
||||
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream1));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread1));
|
||||
}catch(IOException e){}
|
||||
}});
|
||||
|
||||
ClientConnectionAdapter client = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
client.reconnect();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(thread1).stop();
|
||||
oneOf(stream1).close();
|
||||
}});
|
||||
client.close();
|
||||
}
|
||||
|
||||
|
||||
@Test public void testFailCreateStream() {
|
||||
final ClientNetworkTableEntryStore entryStore = context.mock(ClientNetworkTableEntryStore.class);
|
||||
final IOStreamFactory streamFactory = context.mock(IOStreamFactory.class);
|
||||
final IOStream stream1 = context.mock(IOStream.class, "stream1");
|
||||
final NTThread thread1 = context.mock(NTThread.class, "thread1");
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final ClientConnectionListenerManager connectionListenerManager = context.mock(ClientConnectionListenerManager.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
try{
|
||||
allowing(stream1).getInputStream();
|
||||
allowing(stream1).getOutputStream();
|
||||
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(streamFactory).createStream();will(returnValue(stream1));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Client Connection Reader Thread"));will(returnValue(thread1));
|
||||
} catch(IOException e){}
|
||||
}});
|
||||
|
||||
ClientConnectionAdapter client = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, connectionListenerManager, new NetworkTableEntryTypeManager());
|
||||
client.reconnect();
|
||||
context.checking(new Expectations() {{
|
||||
try{
|
||||
oneOf(entryStore).clearIds();
|
||||
oneOf(thread1).stop();
|
||||
oneOf(stream1).close();
|
||||
oneOf(streamFactory).createStream();will(returnValue(null));
|
||||
} catch(IOException e){}
|
||||
}});
|
||||
client.reconnect();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.hamcrest.Description;
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.AbstractNetworkTableEntryStore.TableListenerManager;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ClientNetworkTableEntryStoreTest {
|
||||
Mockery context = new JUnit4Mockery();
|
||||
|
||||
TableListenerManager tlm;
|
||||
OutgoingEntryReceiver oer;
|
||||
ClientNetworkTableEntryStore clientStore;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
tlm = context.mock(TableListenerManager.class);
|
||||
oer = context.mock(OutgoingEntryReceiver.class);
|
||||
clientStore = new ClientNetworkTableEntryStore(tlm);
|
||||
clientStore.setOutgoingReceiver(oer);
|
||||
}
|
||||
|
||||
@Test(expected=TableKeyExistsWithDifferentTypeException.class)
|
||||
public void testPutOfExistingKeyWithDifferentTypeThrowsException() {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(tlm).fireTableListeners(with("TestKey"), with(any(Double.class)), with(any(boolean.class)));
|
||||
|
||||
oneOf(oer).offerOutgoingAssignment(with(any(NetworkTableEntry.class)));
|
||||
}});
|
||||
|
||||
clientStore.putOutgoing("TestKey", DefaultEntryTypes.DOUBLE, new Double(3));
|
||||
|
||||
// This call should throw an exception, because the entry already exists
|
||||
// with type double.
|
||||
clientStore.putOutgoing("TestKey", DefaultEntryTypes.STRING, new String("abc"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.junit.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
public class ClientTest {
|
||||
Mockery context = new JUnit4Mockery();
|
||||
NetworkTableClient client;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
IOStreamFactory ioStreamFactory = context.mock(IOStreamFactory.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(WriteManager.class)), with("Write Manager Thread"));
|
||||
}});
|
||||
client = new NetworkTableClient(ioStreamFactory, new NetworkTableEntryTypeManager(), threadManager);
|
||||
}
|
||||
|
||||
@Test public void testOfflinePutGet() throws TableKeyNotDefinedException {
|
||||
client.putBoolean("MyKey", false);
|
||||
assertEquals(false, client.getBoolean("MyKey"));
|
||||
client.putBoolean("MyKey", true);
|
||||
assertEquals(true, client.getBoolean("MyKey"));
|
||||
client.putBoolean("MyKey", false);
|
||||
assertEquals(false, client.getBoolean("MyKey"));
|
||||
}
|
||||
|
||||
@Test public void testUndefinedKey() {
|
||||
try{
|
||||
client.getBoolean("MyKey");
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){
|
||||
assertEquals("Unkown Table Key: MyKey", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=TableKeyExistsWithDifferentTypeException.class)
|
||||
public void testPutToExistingKeyWithDifferentTypeThrowsExeption() {
|
||||
client.putDouble("TestKey", 3.0);
|
||||
client.putString("TestKey", "abc");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
public class BadMessageExceptionTest {
|
||||
|
||||
@Test
|
||||
public void throwExceptionTest(){
|
||||
try {
|
||||
throw new BadMessageException("Got some bad message");
|
||||
} catch (BadMessageException e) {
|
||||
assertEquals("Got some bad message", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.auto.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ConnectionMonitorThreadTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Mock ConnectionAdapter adapter;
|
||||
@Mock NetworkTableConnection connection;
|
||||
ConnectionMonitorThread thread;
|
||||
@Before public void before(){
|
||||
thread = new ConnectionMonitorThread(adapter, connection);
|
||||
}
|
||||
|
||||
@Test public void testSimpleRead() throws Exception {
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connection).read(adapter);
|
||||
}});
|
||||
thread.run();
|
||||
}
|
||||
@Test public void testReadIOException() throws Exception {
|
||||
final IOException e = new IOException();
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connection).read(adapter);will(throwException(e));
|
||||
oneOf(adapter).ioException(e);
|
||||
}});
|
||||
thread.run();
|
||||
}
|
||||
@Test public void testReadBadMessageException() throws Exception {
|
||||
final BadMessageException e = new BadMessageException("");
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connection).read(adapter);will(throwException(e));
|
||||
oneOf(adapter).badMessage(e);
|
||||
}});
|
||||
thread.run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static test.util.NetworkTableEntryUtil.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class NetworkTableConnectionEntryAssignmentTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
|
||||
@Test public void testBooleanEntryAssignmentSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryAssignment(NetworkTableEntryUtil.newBooleanEntry("My Entry", true));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 0, -1, -1, 0, 0, 1}, stream.getOutput());
|
||||
}
|
||||
@Test public void testBooleanEntryAssignmentReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 0, -1, -1, 0, 0, 1});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).offerIncomingAssignment(with(aBooleanEntry(0xFFFF, "My Entry", 0, true)));
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testDoubleEntryAssignmentSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryAssignment(newDoubleEntry("My Entry", 12.5));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 1, -1, -1, 0, 0, 64, 41, 0, 0, 0, 0, 0, 0}, stream.getOutput());
|
||||
}
|
||||
@Test public void testDoubleEntryAssignmentReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 1, -1, -1, 0, 0, 64, 41, 0, 0, 0, 0, 0, 0});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).offerIncomingAssignment(with(aDoubleEntry(0xFFFF, "My Entry", 0, 12.5)));
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testStringEntryAssignmentSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryAssignment(NetworkTableEntryUtil.newStringEntry("My Entry", "VaLuE"));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 2, -1, -1, 0, 0, 0, 5, 86, 97, 76, 117, 69}, stream.getOutput());
|
||||
}
|
||||
@Test public void testStringEntryAssignmentReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 2, -1, -1, 0, 0, 0, 5, 86, 97, 76, 117, 69});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).offerIncomingAssignment(with(aStringEntry(0xFFFF, "My Entry", 0, "VaLuE")));
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test public void testBadTypeEntryAssignmentReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{16, 0, 8, 77, 121, 32, 69, 110, 116, 114, 121, 127});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
try{
|
||||
connection.read(receiver);
|
||||
fail();
|
||||
} catch(BadMessageException e){
|
||||
} catch(IOException e){
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static test.util.NetworkTableEntryUtil.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class NetworkTableConnectionEntryUpdateTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
|
||||
@Test public void testBooleanEntryUpdateSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryUpdate(newBooleanEntry((char)16, "My Entry", (char)0, true));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{17, 0, 16, 0, 0, 1}, stream.getOutput());
|
||||
}
|
||||
@Test public void testBooleanEntryUpdateReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{17, 0, 16, 0, 0, 1});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
final NetworkTableEntry entry = newBooleanEntry((char)16, "MyEntry", (char)10, false);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).offerIncomingUpdate(entry, (char)0, true);
|
||||
allowing(receiver).getEntry((char)16);will(returnValue(entry));
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test public void testDoubleEntryUpdateSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryUpdate(newDoubleEntry((char)16, "My Entry", (char)0, 12.5));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{17, 0, 16, 0, 0, 64, 41, 0, 0, 0, 0, 0, 0}, stream.getOutput());
|
||||
}
|
||||
@Test public void testDoubleEntryUpdateReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{17, 0, 16, 0, 0, 64, 41, 0, 0, 0, 0, 0, 0});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
final NetworkTableEntry entry = newDoubleEntry((char)16, "MyEntry", (char)10, 3);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(receiver).getEntry((char)16);will(returnValue(entry));
|
||||
oneOf(receiver).offerIncomingUpdate(entry, (char)0, 12.5);
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testStringEntryUpdateSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendEntryUpdate(NetworkTableEntryUtil.newStringEntry((char)16, "My Entry", (char)0, "VaLuE"));
|
||||
connection.flush();
|
||||
|
||||
assertArrayEquals(new byte[]{17, 0, 16, 0, 0, 0, 5, 86, 97, 76, 117, 69}, stream.getOutput());
|
||||
}
|
||||
@Test public void testStringEntryUpdateReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{17, 0, 16, 0, 0, 0, 5, 86, 97, 76, 117, 69});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
final NetworkTableEntry entry = newStringEntry((char)16, "MyEntry", (char)10, "HI");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(receiver).getEntry((char)16);will(returnValue(entry));
|
||||
oneOf(receiver).offerIncomingUpdate(entry, (char)0, "VaLuE");
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class NetworkTableConnectionTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
|
||||
@Test public void testProperties() {
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(stream);
|
||||
}});
|
||||
@SuppressWarnings("unused")
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
}
|
||||
|
||||
@Test public void testClose() {
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
context.checking(new Expectations() {{
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
oneOf(stream).close();
|
||||
}});
|
||||
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.close();
|
||||
}
|
||||
|
||||
@Test public void testCloseTwice() {
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
context.checking(new Expectations() {{
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
oneOf(stream).close();
|
||||
}});
|
||||
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.close();
|
||||
connection.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testKeepAliveSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendKeepAlive();
|
||||
|
||||
assertArrayEquals(new byte[]{0}, stream.getOutput());
|
||||
}
|
||||
@Test public void testKeepAliveReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{0});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).keepAlive();
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testClientHelloSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
connection.sendClientHello();
|
||||
|
||||
assertArrayEquals(new byte[]{1, 2, 00}, stream.getOutput());
|
||||
}
|
||||
@Test public void testClientHelloReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{1, 0, 4});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).clientHello((char)4);
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test public void testProtocolVersionUnsupportedSend() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream();
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
|
||||
connection.sendProtocolVersionUnsupported();
|
||||
|
||||
assertArrayEquals(new byte[]{2, 2, 00}, stream.getOutput());
|
||||
}
|
||||
@Test public void testProtocolVersionUnsupportedReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{2, 0, 4});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(receiver).protocolVersionUnsupported((char)4);
|
||||
}});
|
||||
|
||||
connection.read(receiver);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test public void testBadMessageTypeReceive() throws IOException {
|
||||
ByteArrayStream stream = new ByteArrayStream(new byte[]{127});
|
||||
final ConnectionAdapter receiver = context.mock(ConnectionAdapter.class);
|
||||
NetworkTableConnection connection = new NetworkTableConnection(stream, new NetworkTableEntryTypeManager());
|
||||
|
||||
try{
|
||||
connection.read(receiver);
|
||||
fail();
|
||||
} catch(BadMessageException e){
|
||||
} catch(IOException e){
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.server;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import java.io.*;
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ConnectionListTest {
|
||||
Mockery context = new JUnit4Mockery(){{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testSendTransaction() throws IOException {
|
||||
final ServerConnectionAdapter adapter1 = context.mock(ServerConnectionAdapter.class, "adapter 1");
|
||||
final ServerConnectionAdapter adapter2 = context.mock(ServerConnectionAdapter.class, "adapter 2");
|
||||
final NetworkTableEntry entry1 = context.mock(NetworkTableEntry.class, "entry1");
|
||||
final NetworkTableEntry entry2 = context.mock(NetworkTableEntry.class, "entry2");
|
||||
|
||||
|
||||
ServerConnectionList connectionList = new ServerConnectionList();
|
||||
connectionList.add(adapter1);
|
||||
connectionList.add(adapter2);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(adapter1).offerOutgoingAssignment(entry1);
|
||||
oneOf(adapter2).offerOutgoingAssignment(entry1);
|
||||
}});
|
||||
connectionList.offerOutgoingAssignment(entry1);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(adapter1).offerOutgoingAssignment(entry2);
|
||||
oneOf(adapter2).offerOutgoingAssignment(entry2);
|
||||
}});
|
||||
connectionList.offerOutgoingAssignment(entry2);
|
||||
}
|
||||
|
||||
@Test public void testClose() throws IOException {
|
||||
final ServerConnectionAdapter adapter1 = context.mock(ServerConnectionAdapter.class, "adapter 1");
|
||||
final ServerConnectionAdapter adapter2 = context.mock(ServerConnectionAdapter.class, "adapter 2");
|
||||
final NetworkTableEntry entry1 = context.mock(NetworkTableEntry.class, "entry1");
|
||||
final NetworkTableEntry entry2 = context.mock(NetworkTableEntry.class, "entry2");
|
||||
|
||||
|
||||
ServerConnectionList connectionList = new ServerConnectionList();
|
||||
connectionList.add(adapter1);
|
||||
connectionList.add(adapter2);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(adapter1).offerOutgoingAssignment(entry1);
|
||||
oneOf(adapter2).offerOutgoingAssignment(entry1);
|
||||
}});
|
||||
connectionList.offerOutgoingAssignment(entry1);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(adapter1).shutdown(true);
|
||||
}});
|
||||
connectionList.close(adapter1, true);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(adapter2).offerOutgoingAssignment(entry2);
|
||||
}});
|
||||
connectionList.offerOutgoingAssignment(entry2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.BadMessageException;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ServerConnectionAdapterTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testServerConnectionState() throws IOException {
|
||||
assertEquals("GOT_CONNECTION_FROM_CLIENT", ServerConnectionState.GOT_CONNECTION_FROM_CLIENT.toString());
|
||||
assertEquals("CONNECTED_TO_CLIENT", ServerConnectionState.CONNECTED_TO_CLIENT.toString());
|
||||
assertEquals("CLIENT_DISCONNECTED", ServerConnectionState.CLIENT_DISCONNECTED.toString());
|
||||
assertEquals("SERVER_ERROR: class java.io.IOException: Something happended", new ServerConnectionState.Error(new IOException("Something happended")).toString());
|
||||
}
|
||||
@Test public void testKeepAlive() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
serverAdapter.keepAlive();
|
||||
}
|
||||
|
||||
@Test public void testClientHello() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
oneOf(entryStore).sendServerHello(serverAdapter.connection);
|
||||
}});
|
||||
|
||||
assertEquals(ServerConnectionState.GOT_CONNECTION_FROM_CLIENT, serverAdapter.getConnectionState());
|
||||
serverAdapter.clientHello((char)0x0200);
|
||||
assertEquals(ServerConnectionState.CONNECTED_TO_CLIENT, serverAdapter.getConnectionState());
|
||||
}
|
||||
|
||||
@Test public void testUnsupportedProtocol() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
try{
|
||||
serverAdapter.protocolVersionUnsupported((char)0);
|
||||
fail();
|
||||
} catch(BadMessageException e){
|
||||
}
|
||||
}
|
||||
|
||||
@Test public void testUnsupportedClientProtocol() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final ByteArrayStream stream = new ByteArrayStream();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
try{
|
||||
serverAdapter.clientHello((char)0);
|
||||
fail();
|
||||
} catch(BadMessageException e){
|
||||
}
|
||||
assertArrayEquals(new byte[]{0x02, 0x02, (byte)0x00}, stream.getOutput());
|
||||
}
|
||||
|
||||
@Test public void testConnectionErrorBadMessage() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
oneOf(connectionListener).close(serverAdapter, true);
|
||||
}});
|
||||
|
||||
serverAdapter.badMessage(new BadMessageException(""));
|
||||
}
|
||||
|
||||
@Test public void testConnectionErrorIOException() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectionListener).close(serverAdapter, false);
|
||||
}});
|
||||
|
||||
serverAdapter.ioException(new IOException(""));
|
||||
}
|
||||
@Test public void testClientDisconnect() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectionListener).close(serverAdapter, false);
|
||||
}});
|
||||
|
||||
serverAdapter.ioException(new EOFException());
|
||||
assertEquals(ServerConnectionState.CLIENT_DISCONNECTED, serverAdapter.getConnectionState());
|
||||
}
|
||||
|
||||
@Test public void testGetEntryType() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final IncomingEntryReceiver transactionReceiver = context.mock(IncomingEntryReceiver.class);
|
||||
final ServerAdapterManager connectionListener = context.mock(ServerAdapterManager.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final IOStream stream = context.mock(IOStream.class);
|
||||
context.checking(new Expectations() {{
|
||||
ignoring(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Connection Reader Thread"));
|
||||
allowing(stream).getInputStream();
|
||||
allowing(stream).getOutputStream();
|
||||
}});
|
||||
|
||||
|
||||
|
||||
final NetworkTableEntry entry1 = NetworkTableEntryUtil.newBooleanEntry("MyEntry", true);
|
||||
final NetworkTableEntry entry2 = NetworkTableEntryUtil.newDoubleEntry("MyEntry", 12);
|
||||
final NetworkTableEntry entry3 = NetworkTableEntryUtil.newStringEntry("MyEntry", "Value");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(entryStore).getEntry((char)16);will(returnValue(entry1));
|
||||
allowing(entryStore).getEntry((char)1);will(returnValue(entry2));
|
||||
allowing(entryStore).getEntry((char)22);will(returnValue(entry3));
|
||||
}});
|
||||
|
||||
final ServerConnectionAdapter serverAdapter = new ServerConnectionAdapter(stream, entryStore, transactionReceiver, connectionListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
assertEquals(DefaultEntryTypes.BOOLEAN, serverAdapter.getEntry((char)16).getType());
|
||||
assertEquals(DefaultEntryTypes.DOUBLE, serverAdapter.getEntry((char)1).getType());
|
||||
assertEquals(DefaultEntryTypes.STRING, serverAdapter.getEntry((char)22).getType());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.server;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.hamcrest.Description;
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ServerIncomingMonitorTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};;
|
||||
|
||||
@Test public void testReceiveConnections() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final ServerAdapterManager adapterListener = context.mock(ServerAdapterManager.class);
|
||||
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final TestThreadManager threadManager = new TestThreadManager();
|
||||
final IOStream stream1 = new ByteArrayStream();
|
||||
final IOStream stream2 = new ByteArrayStream();
|
||||
final ServerIncomingConnectionListener incomingListener = context.mock(ServerIncomingConnectionListener.class);
|
||||
|
||||
final States progress = context.states("progress").startsAs("sendFirst");
|
||||
context.checking(new Expectations() {{
|
||||
|
||||
oneOf(streamProvider).accept();will(returnValue(stream1));when(progress.is("sendFirst"));then(progress.is("sentFirst"));
|
||||
oneOf(incomingListener).onNewConnection(with(aConnectionAdapterFor(stream1)));
|
||||
when(progress.is("sentFirst"));then(progress.is("receivedFirst"));
|
||||
oneOf(streamProvider).accept();will(returnValue(stream2));when(progress.is("sendSecond"));then(progress.is("sentSecond"));
|
||||
oneOf(incomingListener).onNewConnection(with(aConnectionAdapterFor(stream2)));
|
||||
when(progress.is("sentSecond"));then(progress.is("receivedSecond"));
|
||||
}});
|
||||
|
||||
ServerIncomingStreamMonitor incomingMonitor = new ServerIncomingStreamMonitor(streamProvider, entryStore,
|
||||
incomingListener, adapterListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
incomingMonitor.start();
|
||||
|
||||
threadManager.getPeriodicThread(ServerIncomingStreamMonitor.class).run();
|
||||
assertThat(progress, hasState("receivedFirst"));
|
||||
progress.become("sendSecond");
|
||||
|
||||
threadManager.getPeriodicThread(ServerIncomingStreamMonitor.class).run();
|
||||
assertThat(progress, hasState("receivedSecond"));
|
||||
}
|
||||
|
||||
@Test public void testClose() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final ServerAdapterManager adapterListener = context.mock(ServerAdapterManager.class);
|
||||
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final NTThread thread = context.mock(NTThread.class);
|
||||
final ServerIncomingConnectionListener incomingListener = context.mock(ServerIncomingConnectionListener.class);
|
||||
|
||||
final States progress = context.states("progress").startsAs("creating monitor");
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Incoming Stream Monitor Thread"));will(returnValue(thread));
|
||||
when(progress.is("starting monitor"));then(progress.is("started monitor"));
|
||||
oneOf(thread).stop();when(progress.is("stopping monitor"));then(progress.is("stopped monitor"));
|
||||
}});
|
||||
|
||||
ServerIncomingStreamMonitor incomingMonitor = new ServerIncomingStreamMonitor(streamProvider, entryStore,
|
||||
incomingListener, adapterListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
progress.become("starting monitor");
|
||||
incomingMonitor.start();
|
||||
|
||||
assertThat(progress, hasState("started monitor"));
|
||||
|
||||
progress.become("stopping monitor");
|
||||
|
||||
incomingMonitor.stop();
|
||||
|
||||
assertThat(progress, hasState("stopped monitor"));
|
||||
}
|
||||
|
||||
@Test public void testStopWithoutStart() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final ServerAdapterManager adapterListener = context.mock(ServerAdapterManager.class);
|
||||
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final ServerIncomingConnectionListener incomingListener = context.mock(ServerIncomingConnectionListener.class);
|
||||
|
||||
ServerIncomingStreamMonitor incomingMonitor = new ServerIncomingStreamMonitor(streamProvider, entryStore,
|
||||
incomingListener, adapterListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
|
||||
incomingMonitor.stop();
|
||||
}
|
||||
|
||||
@Test public void testNullStream() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final ServerAdapterManager adapterListener = context.mock(ServerAdapterManager.class);
|
||||
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final TestThreadManager threadManager = new TestThreadManager();
|
||||
final ServerIncomingConnectionListener incomingListener = context.mock(ServerIncomingConnectionListener.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(streamProvider).accept();will(returnValue(null));
|
||||
}});
|
||||
|
||||
ServerIncomingStreamMonitor incomingMonitor = new ServerIncomingStreamMonitor(streamProvider, entryStore,
|
||||
incomingListener, adapterListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
incomingMonitor.start();
|
||||
|
||||
threadManager.getPeriodicThread(ServerIncomingStreamMonitor.class).run();
|
||||
}
|
||||
|
||||
@Test public void testStreamAcceptException() throws IOException {
|
||||
final ServerNetworkTableEntryStore entryStore = context.mock(ServerNetworkTableEntryStore.class);
|
||||
final ServerAdapterManager adapterListener = context.mock(ServerAdapterManager.class);
|
||||
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final TestThreadManager threadManager = new TestThreadManager();
|
||||
final ServerIncomingConnectionListener incomingListener = context.mock(ServerIncomingConnectionListener.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(streamProvider).accept();will(throwException(new IOException("Something bad happened")));
|
||||
}});
|
||||
|
||||
ServerIncomingStreamMonitor incomingMonitor = new ServerIncomingStreamMonitor(streamProvider, entryStore,
|
||||
incomingListener, adapterListener, new NetworkTableEntryTypeManager(), threadManager);
|
||||
incomingMonitor.start();
|
||||
|
||||
threadManager.getPeriodicThread(ServerIncomingStreamMonitor.class).run();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private Matcher<ServerConnectionAdapter> aConnectionAdapterFor(final IOStream stream) {
|
||||
return new TypeSafeMatcher<ServerConnectionAdapter>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText(" a server connection adapter for ").appendValue(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(ServerConnectionAdapter adapter) {
|
||||
return adapter.connection.stream==stream;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
private Matcher<States> hasState(final String state) {
|
||||
return new TypeSafeMatcher<States>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText(" has the state: ").appendValue(state);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(States stateMachine) {
|
||||
return stateMachine.is(state).isActive();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.server;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ServerTest {
|
||||
Mockery context = new JUnit4Mockery();
|
||||
|
||||
|
||||
@Test public void testClose() throws IOException {
|
||||
final IOStreamProvider streamProvider = context.mock(IOStreamProvider.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final NTThread thread1 = context.mock(NTThread.class, "thread 1");
|
||||
final NTThread thread2 = context.mock(NTThread.class, "thread 2");
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Write Manager Thread"));will(returnValue(thread1));
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Server Incoming Stream Monitor Thread"));will(returnValue(thread2));
|
||||
}});
|
||||
|
||||
NetworkTableServer server = new NetworkTableServer(streamProvider, new NetworkTableEntryTypeManager(), threadManager);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(thread1).stop();
|
||||
oneOf(thread2).stop();
|
||||
oneOf(streamProvider).close();
|
||||
}});
|
||||
server.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.server;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class ServerWriteManagerTest {
|
||||
Mockery context = new JUnit4Mockery(){{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test public void testSendTransaction() throws Exception {
|
||||
final TestThreadManager threadManager = new TestThreadManager();
|
||||
final ServerConnectionList connectionList = context.mock(ServerConnectionList.class);
|
||||
final NetworkTableEntry entry1 = context.mock(NetworkTableEntry.class, "entry1");
|
||||
final NetworkTableEntry entry2 = context.mock(NetworkTableEntry.class, "entry2");
|
||||
final NetworkTableEntry entry3 = context.mock(NetworkTableEntry.class, "entry3");
|
||||
final AbstractNetworkTableEntryStore entryStore = context.mock(AbstractNetworkTableEntryStore.class);
|
||||
|
||||
|
||||
WriteManager writeManager = new WriteManager(connectionList, threadManager, entryStore, Long.MAX_VALUE);
|
||||
writeManager.start();
|
||||
|
||||
writeManager.offerOutgoingAssignment(entry1);
|
||||
|
||||
final Sequence writeSequence1 = context.sequence("writeSequence1");
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectionList).offerOutgoingAssignment(entry1);inSequence(writeSequence1);
|
||||
oneOf(connectionList).flush();inSequence(writeSequence1);
|
||||
oneOf(entry1).makeClean();
|
||||
}});
|
||||
threadManager.getPeriodicThread(WriteManager.class).run();
|
||||
context.assertIsSatisfied();
|
||||
|
||||
|
||||
writeManager.offerOutgoingAssignment(entry2);
|
||||
writeManager.offerOutgoingAssignment(entry3);
|
||||
final Sequence writeSequence2 = context.sequence("writeSequence2");
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(connectionList).offerOutgoingAssignment(entry2);inSequence(writeSequence2);
|
||||
oneOf(connectionList).offerOutgoingAssignment(entry3);inSequence(writeSequence2);
|
||||
oneOf(connectionList).flush();inSequence(writeSequence2);
|
||||
oneOf(entry2).makeClean();
|
||||
oneOf(entry3).makeClean();
|
||||
}});
|
||||
threadManager.getPeriodicThread(WriteManager.class).run();
|
||||
}
|
||||
|
||||
@Test public void testClose() throws IOException {
|
||||
final ServerConnectionList connectionList = context.mock(ServerConnectionList.class);
|
||||
final NTThreadManager threadManager = context.mock(NTThreadManager.class);
|
||||
final NTThread thread = context.mock(NTThread.class);
|
||||
final AbstractNetworkTableEntryStore entryStore = context.mock(AbstractNetworkTableEntryStore.class);
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(threadManager).newBlockingPeriodicThread(with(any(PeriodicRunnable.class)), with("Write Manager Thread"));will(returnValue(thread));
|
||||
}});
|
||||
|
||||
WriteManager writeManager = new WriteManager(connectionList, threadManager, entryStore, Long.MAX_VALUE);
|
||||
|
||||
writeManager.start();
|
||||
context.assertIsSatisfied();
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(thread).stop();
|
||||
}});
|
||||
writeManager.stop();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
|
||||
@RunWith(JMock.class)
|
||||
public class SimpleIOStreamTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
|
||||
@Test
|
||||
public void testSingleSocketConnection() throws IOException {
|
||||
final InputStream is = context.mock(InputStream.class);
|
||||
final OutputStream os = context.mock(OutputStream.class);
|
||||
SimpleIOStream stream = new SimpleIOStream(is, os);
|
||||
assertSame(is, stream.getInputStream());
|
||||
assertSame(os, stream.getOutputStream());
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(is).close();
|
||||
oneOf(os).close();
|
||||
}});
|
||||
stream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionsOnISClose() throws IOException {
|
||||
final InputStream is = context.mock(InputStream.class);
|
||||
final OutputStream os = context.mock(OutputStream.class);
|
||||
SimpleIOStream stream = new SimpleIOStream(is, os);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(is).close();will(throwException(new IOException()));
|
||||
oneOf(os).close();
|
||||
}});
|
||||
stream.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionsOnOSClose() throws IOException {
|
||||
final InputStream is = context.mock(InputStream.class);
|
||||
final OutputStream os = context.mock(OutputStream.class);
|
||||
SimpleIOStream stream = new SimpleIOStream(is, os);
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(is).close();
|
||||
oneOf(os).close();will(throwException(new IOException()));
|
||||
}});
|
||||
stream.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.concurrent.*;
|
||||
import org.junit.*;
|
||||
|
||||
import test.util.*;
|
||||
|
||||
public class SocketTest {
|
||||
Mockery context = new JUnit4Mockery() {{
|
||||
setThreadingPolicy(new Synchroniser());
|
||||
}};
|
||||
|
||||
|
||||
@Test(timeout=1000)
|
||||
public void testSingleSocketConnection() throws Throwable {
|
||||
doSocketTest(1, 500, 1000, SocketStreams.newStreamProvider(10111), SocketStreams.newStreamFactory("localhost", 10111));
|
||||
}
|
||||
@Test(timeout=2500)
|
||||
public void testManySocketConnection() throws Throwable {
|
||||
doSocketTest(10, 500, 2000, SocketStreams.newStreamProvider(10112), SocketStreams.newStreamFactory("localhost", 10112));
|
||||
}
|
||||
|
||||
private void doSocketTest(final int count, long threadTimeout, long testTimeout, final IOStreamProvider streamProvider, final IOStreamFactory factory) throws Throwable {
|
||||
TestExecutor executor = new TestExecutor(count+1, threadTimeout);
|
||||
final AtomicInteger clientCount = new AtomicInteger(0);
|
||||
final AtomicInteger serverCount = new AtomicInteger(0);
|
||||
|
||||
for(int i = 0; i<count; ++i){
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
IOStream clientStream = factory.createStream();
|
||||
|
||||
PrintWriter output = new PrintWriter(clientStream.getOutputStream());
|
||||
output.println("FromClient");
|
||||
output.flush();
|
||||
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(clientStream.getInputStream()));
|
||||
assertEquals("FromServer", input.readLine());
|
||||
|
||||
clientStream.close();
|
||||
clientCount.incrementAndGet();
|
||||
} catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
while(serverCount.get()!=count){
|
||||
IOStream serverStream = streamProvider.accept();
|
||||
|
||||
BufferedReader input = new BufferedReader(new InputStreamReader(serverStream.getInputStream()));
|
||||
assertEquals("FromClient", input.readLine());
|
||||
|
||||
PrintWriter output = new PrintWriter(serverStream.getOutputStream());
|
||||
output.println("FromServer");
|
||||
output.flush();
|
||||
|
||||
serverStream.close();
|
||||
serverCount.incrementAndGet();
|
||||
}
|
||||
streamProvider.close();
|
||||
} catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
executor.await(testTimeout, TimeUnit.MILLISECONDS);
|
||||
assertEquals("server count", count, serverCount.get());
|
||||
assertEquals("client count", count, clientCount.get());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.system;
|
||||
|
||||
import edu.wpi.first.testing.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.client.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import org.junit.*;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
@RunWith(sUnitTestRunner.class)
|
||||
public class SystemTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleBidirectionalPut() throws Exception{
|
||||
sUnitTestRunner.server.waitMessage();//Server Up
|
||||
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory("10.1.90.2", 1735);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory);
|
||||
client.reconnect();
|
||||
Thread.sleep(500);
|
||||
sUnitTestRunner.server.sendMessage("client connected");
|
||||
|
||||
client.putString("ClientString1", "CValue1-1");
|
||||
client.putString("ClientString2", "CValue2-1");
|
||||
|
||||
sUnitTestRunner.server.waitMessage();//Server sent
|
||||
Thread.sleep(100);
|
||||
assertEquals("SValue1-1", client.getString("ServerString1"));
|
||||
assertEquals("SValue2-1", client.getString("ServerString2"));
|
||||
client.putString("ClientString1", "CValue1-2");
|
||||
client.putString("ClientString2", "CValue2-2");
|
||||
sUnitTestRunner.server.sendMessage("client sent");
|
||||
|
||||
sUnitTestRunner.server.waitMessage();//Server sent
|
||||
Thread.sleep(100);
|
||||
assertEquals("SValue1-2", client.getString("ServerString1"));
|
||||
assertEquals("SValue2-2", client.getString("ServerString2"));
|
||||
|
||||
client.stop();
|
||||
|
||||
sUnitTestRunner.server.sendMessage("test complete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRapidServerPutSingleKey() throws Exception{
|
||||
sUnitTestRunner.server.waitMessage();//Server Up
|
||||
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory("10.1.90.2", 1735);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory);
|
||||
client.reconnect();
|
||||
Thread.sleep(100);
|
||||
sUnitTestRunner.server.sendMessage("client connected");
|
||||
|
||||
sUnitTestRunner.server.waitMessage();//Server done
|
||||
assertEquals("SValue9999", client.getString("ServerKey"));
|
||||
client.stop();
|
||||
|
||||
|
||||
sUnitTestRunner.server.sendMessage("test complete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRapidServerPutMultiKey() throws Exception{
|
||||
sUnitTestRunner.server.waitMessage();//Server Up
|
||||
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory("10.1.90.2", 1735);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory);
|
||||
client.reconnect();
|
||||
Thread.sleep(100);
|
||||
sUnitTestRunner.server.sendMessage("client connected");
|
||||
|
||||
sUnitTestRunner.server.waitMessage();//Server done
|
||||
client.stop();
|
||||
|
||||
for(int i = 0; i<100; ++i)
|
||||
assertEquals("SValue999", client.getString("ServerKey"+i));
|
||||
|
||||
sUnitTestRunner.server.sendMessage("test complete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPeriodicServerPutMultiKey() throws Exception{
|
||||
sUnitTestRunner.server.waitMessage();//Server Up
|
||||
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory("10.1.90.2", 1735);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory);
|
||||
client.reconnect();
|
||||
Thread.sleep(100);
|
||||
sUnitTestRunner.server.sendMessage("client connected");
|
||||
|
||||
sUnitTestRunner.server.waitMessage();//Server done
|
||||
client.stop();
|
||||
|
||||
for(int i = 0; i<100; ++i)
|
||||
assertEquals("SValue99", client.getString("ServerKey"+i));
|
||||
|
||||
sUnitTestRunner.server.sendMessage("test complete");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBiDirectionalStress() throws Exception {
|
||||
sUnitTestRunner.server.waitMessage(); // Server up
|
||||
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory("10.1.90.2", 1735);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory);
|
||||
client.reconnect();
|
||||
Thread.sleep(100);
|
||||
sUnitTestRunner.server.sendMessage("Client connected");
|
||||
|
||||
Map<String, Double> valueRecord = new HashMap<String, Double>();
|
||||
|
||||
// Add and send 1 million values
|
||||
try {
|
||||
// Seed the RNG from a build property; otherwise, generate a random seed
|
||||
final String seedPropertyName = "edu.wpi.first.wpilibj.test.randomSeed";
|
||||
String seedStr = System.getProperty(seedPropertyName);
|
||||
boolean seedLoaded = false;
|
||||
|
||||
Random rand;
|
||||
long seed;
|
||||
if(seedStr != null) {
|
||||
seed = Long.parseLong(seedStr);
|
||||
System.out.println("Seed loaded from property '" + seedPropertyName + "'");
|
||||
seedLoaded = true;
|
||||
} else {
|
||||
System.out.println("Property '" + seedPropertyName + "' not set; generating random seed");
|
||||
Random seedRand = new Random();
|
||||
seed = seedRand.nextLong();
|
||||
}
|
||||
System.out.println("Using seed: "+ seed);
|
||||
rand = new Random(seed);
|
||||
|
||||
// Write values to the robot; try 10000 runs
|
||||
System.out.println("Writing values to the robot...");
|
||||
for(int i = 0; i < 10000; i++) {
|
||||
// Pick a random name out of ascii characters
|
||||
int nameLen = rand.nextInt(99) + 1;
|
||||
StringBuilder sb = new StringBuilder(nameLen);
|
||||
for(int j = 0; j < nameLen; j++) {
|
||||
|
||||
// Pick a random human-readable ascii character
|
||||
int c = rand.nextInt(94) + 32;
|
||||
sb.append((char) c);
|
||||
}
|
||||
|
||||
// Pick a value to send from the range of +/- Double.MAX_VALUE
|
||||
double value = rand.nextDouble() * Double.MAX_VALUE;
|
||||
if(!rand.nextBoolean())
|
||||
value *= -1;
|
||||
|
||||
// If a seed was specified (i.e. we are probably debugging),
|
||||
// print out the value sequence
|
||||
if(seedLoaded) {
|
||||
System.out.println(String.format("Setting %s to value %f", sb.toString(), value));
|
||||
}
|
||||
|
||||
valueRecord.put(sb.toString(), value);
|
||||
client.putDouble("/client/" + sb.toString(), value);
|
||||
|
||||
Thread.sleep(rand.nextInt(19) + 1);
|
||||
}
|
||||
|
||||
System.out.println("Waiting for 10 seconds...");
|
||||
Thread.sleep(10000);
|
||||
List<String> incorrectEntries = new LinkedList<String>();
|
||||
|
||||
// Compare the current value of every entry with the expected value
|
||||
for(Entry<String, Double> e : valueRecord.entrySet()) {
|
||||
try {
|
||||
Double d = client.getDouble("/server/" + e.getKey());
|
||||
|
||||
if(!e.getValue().equals(d))
|
||||
incorrectEntries.add(e.getKey());
|
||||
} catch (TableKeyNotDefinedException tknde) {
|
||||
incorrectEntries.add(e.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// Note any/all failures
|
||||
if(incorrectEntries.size() > 0) {
|
||||
for(String s : incorrectEntries) {
|
||||
try {
|
||||
Double d = client.getDouble("/server/" + s);
|
||||
|
||||
System.err.println(String.format("For key '%s' expected %f, got %f", s, valueRecord.get(s), d));
|
||||
} catch (TableKeyNotDefinedException tknde) {
|
||||
System.err.println(String.format("No key %s; expected %f", s, valueRecord.get(s)));
|
||||
}
|
||||
}
|
||||
|
||||
fail("Server namespace in network tables never became consistent with expected values");
|
||||
}
|
||||
sUnitTestRunner.server.sendMessage("Test complete");
|
||||
} catch(Exception e) {
|
||||
sUnitTestRunner.server.sendMessage("Test complete (exception occurred)");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.thread;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
public class DefaultThreadManagerTest {
|
||||
volatile Throwable exception = null;
|
||||
@Test(timeout=300)
|
||||
public void testConcurrentThreads() throws Throwable {
|
||||
final int numCounts = 10;
|
||||
final int numThreads = 10;
|
||||
final CyclicBarrier barrier = new CyclicBarrier(numThreads);
|
||||
final CountDownLatch ranNotification = new CountDownLatch(numThreads*numCounts);
|
||||
DefaultThreadManager threadManager = new DefaultThreadManager();
|
||||
|
||||
NTThread[] threads = new NTThread[numThreads];
|
||||
for(int i = 0; i<numThreads; ++i)
|
||||
threads[i] = threadManager.newBlockingPeriodicThread(new PeriodicRunnable(){
|
||||
@Override
|
||||
public void run() throws InterruptedException {
|
||||
try {
|
||||
barrier.await();
|
||||
} catch (BrokenBarrierException e) {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
ranNotification.countDown();
|
||||
}
|
||||
}, "Test thread "+i);
|
||||
|
||||
try {
|
||||
ranNotification.await();
|
||||
for(int i = 0; i<numThreads; ++i)
|
||||
threads[i].stop();
|
||||
Thread.sleep(100);//Wait for threads to terminate
|
||||
for(int i = 0; i<numThreads; ++i)
|
||||
assertFalse(threads[i].isRunning());
|
||||
} catch (InterruptedException e) {
|
||||
fail("interrupted while waiting");
|
||||
}
|
||||
if(exception!=null)
|
||||
throw exception;
|
||||
}
|
||||
|
||||
|
||||
volatile boolean threadInterrupted = false;
|
||||
@Test(timeout=300)
|
||||
public void testStopThread() throws IOException {
|
||||
DefaultThreadManager threadManager = new DefaultThreadManager();
|
||||
NTThread thread = threadManager.newBlockingPeriodicThread(new PeriodicRunnable(){
|
||||
@Override
|
||||
public void run() throws InterruptedException {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
}, "A Test Thread");
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
thread.stop();
|
||||
Thread.sleep(100);//wait for thread to stop
|
||||
assertFalse(thread.isRunning());
|
||||
} catch (InterruptedException e) {
|
||||
fail("interrupted while waiting");
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=2000)
|
||||
public void testPeriodicThread() throws IOException {
|
||||
final CountDownLatch countDown = new CountDownLatch(10);
|
||||
final AtomicInteger afterFinishCount = new AtomicInteger(0);
|
||||
DefaultThreadManager threadManager = new DefaultThreadManager();
|
||||
NTThread thread = threadManager.newBlockingPeriodicThread(new PeriodicRunnable(){
|
||||
@Override
|
||||
public void run() throws InterruptedException {
|
||||
Thread.sleep(50);
|
||||
if(countDown.getCount()==0)
|
||||
afterFinishCount.incrementAndGet();
|
||||
else
|
||||
countDown.countDown();
|
||||
}
|
||||
}, "A test thread");
|
||||
try {
|
||||
countDown.await();
|
||||
thread.stop();
|
||||
Thread.sleep(100);//wait for thread to stop
|
||||
assertFalse(thread.isRunning());
|
||||
assertTrue(afterFinishCount.get()<=1);//make sure the periodic calls stopped
|
||||
} catch (InterruptedException e) {
|
||||
fail("interrupted while waiting");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.TableKeyExistsWithDifferentTypeException;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.jmock.*;
|
||||
import org.jmock.integration.junit4.*;
|
||||
import org.jmock.lib.legacy.*;
|
||||
import org.junit.*;
|
||||
import org.junit.runner.*;
|
||||
|
||||
import test.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.client.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.server.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mitchell
|
||||
*/
|
||||
@RunWith(JMock.class)
|
||||
public class ArrayTypeTest {
|
||||
Mockery context = new JUnit4Mockery(){{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test
|
||||
public void testPutArrayValue() throws Exception{
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final ArrayEntryType arrayType = new ArrayEntryType((byte)10, type, ArrayData.class);
|
||||
final ArrayData data = new ArrayData(arrayType);
|
||||
data.setSize(9);
|
||||
final Object value1 = new Object();
|
||||
final Object value2 = new Object();
|
||||
data._set(0, value1);
|
||||
data._set(1, value2);
|
||||
|
||||
node.putValue("MyKey", data);
|
||||
Object[] internalValue = (Object[])node.getValue("MyKey");
|
||||
assertEquals(9, internalValue.length);
|
||||
assertSame(internalValue[0], value1);
|
||||
assertSame(internalValue[1], value2);
|
||||
for(int i = 2; i<9; ++i)
|
||||
assertNull(internalValue[i]);
|
||||
|
||||
|
||||
data._set(0, value2);
|
||||
data._set(1, value1);
|
||||
|
||||
Object[] internalValue2 = (Object[])node.getValue("MyKey");
|
||||
assertSame(internalValue, internalValue2);
|
||||
assertEquals(9, internalValue2.length);
|
||||
assertSame(internalValue2[0], value1);
|
||||
assertSame(internalValue2[1], value2);
|
||||
for(int i = 2; i<9; ++i)
|
||||
assertNull(internalValue2[i]);
|
||||
|
||||
node.putValue("MyKey", data);
|
||||
|
||||
Object[] internalValue3 = (Object[])node.getValue("MyKey");
|
||||
assertSame(internalValue2, internalValue3);
|
||||
assertEquals(9, internalValue3.length);
|
||||
assertSame(internalValue3[0], value2);
|
||||
assertSame(internalValue3[1], value1);
|
||||
for(int i = 2; i<9; ++i)
|
||||
assertNull(internalValue3[i]);
|
||||
|
||||
data.setSize(4);
|
||||
data._set(0, value1);
|
||||
data._set(1, value2);
|
||||
data._set(2, value2);
|
||||
data._set(3, value1);
|
||||
|
||||
Object[] internalValue4 = (Object[])node.getValue("MyKey");
|
||||
assertSame(internalValue3, internalValue4);
|
||||
assertEquals(9, internalValue4.length);
|
||||
assertSame(internalValue4[0], value2);
|
||||
assertSame(internalValue4[1], value1);
|
||||
for(int i = 2; i<9; ++i)
|
||||
assertNull(internalValue4[i]);
|
||||
|
||||
node.putValue("MyKey", data);
|
||||
|
||||
Object[] internalValue5 = (Object[])node.getValue("MyKey");
|
||||
assertNotSame(internalValue4, internalValue5);
|
||||
assertEquals(4, internalValue5.length);
|
||||
assertSame(internalValue5[0], value1);
|
||||
assertSame(internalValue5[1], value2);
|
||||
assertSame(internalValue5[2], value2);
|
||||
assertSame(internalValue5[3], value1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveArrayValue() throws Exception{
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final ArrayEntryType arrayType = new ArrayEntryType((byte)10, type, ArrayData.class);
|
||||
final ArrayData data = new ArrayData(arrayType);
|
||||
data.setSize(4);
|
||||
final Object value1 = new Object();
|
||||
final Object value2 = new Object();
|
||||
final Object value3 = new Object();
|
||||
final Object value4 = new Object();
|
||||
data._set(0, value1);
|
||||
data._set(1, value2);
|
||||
data._set(2, value3);
|
||||
data._set(3, value4);
|
||||
|
||||
node.putValue("MyKey", data);
|
||||
|
||||
final ArrayData targetData = new ArrayData(arrayType);
|
||||
node.retrieveValue("MyKey", targetData);
|
||||
assertEquals(4, targetData.size());
|
||||
assertSame(targetData.getAsObject(0), value1);
|
||||
assertSame(targetData.getAsObject(1), value2);
|
||||
assertSame(targetData.getAsObject(2), value3);
|
||||
assertSame(targetData.getAsObject(3), value4);
|
||||
|
||||
Object[] internalValue = (Object[])node.getValue("MyKey");
|
||||
assertNotSame(internalValue, targetData.getDataArray());
|
||||
|
||||
|
||||
targetData._set(0, value2);
|
||||
targetData._set(1, value1);
|
||||
|
||||
Object[] internalValue2 = (Object[])node.getValue("MyKey");
|
||||
assertSame(internalValue, internalValue2);
|
||||
assertEquals(4, internalValue2.length);
|
||||
assertSame(internalValue[0], value1);
|
||||
assertSame(internalValue[1], value2);
|
||||
assertSame(internalValue[2], value3);
|
||||
assertSame(internalValue[3], value4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithNonArrayExternal(){
|
||||
final NetworkTableEntryType elementType = context.mock(NetworkTableEntryType.class);
|
||||
try{
|
||||
new ArrayEntryType((byte)2, elementType, String.class);
|
||||
fail();
|
||||
} catch(Exception e){}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testInternalizeDifferentExternalType(){
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final ArrayEntryType arrayType = new ArrayEntryType((byte)10, type, BooleanArray.class);
|
||||
try{
|
||||
arrayType.internalizeValue("MyKey", new ArrayData(arrayType), new Object[0]);
|
||||
fail();
|
||||
}
|
||||
catch(TableKeyExistsWithDifferentTypeException e){
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExportDifferentExternalType(){
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final ArrayEntryType arrayType = new ArrayEntryType((byte)10, type, BooleanArray.class);
|
||||
try{
|
||||
arrayType.exportValue("MyKey", new Object[0], new ArrayData(arrayType));
|
||||
fail();
|
||||
}
|
||||
catch(TableKeyExistsWithDifferentTypeException e){
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testExportDifferentInternalType(){
|
||||
final NetworkTableEntryType type = context.mock(NetworkTableEntryType.class);
|
||||
final ArrayEntryType arrayType = new ArrayEntryType((byte)10, type, BooleanArray.class);
|
||||
try{
|
||||
arrayType.exportValue("MyKey", new boolean[0], new BooleanArray());
|
||||
fail();
|
||||
}
|
||||
catch(TableKeyExistsWithDifferentTypeException e){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Boolean
|
||||
*/
|
||||
@Test
|
||||
public void testSendBooleanArray(){
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BooleanArray.TYPE.sendValue(new Object[]{true, false, true, true}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{4, 1, 0, 1, 1}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BooleanArray.TYPE.sendValue(new Object[]{false, true, true, true, false, false, false, true}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{8, 0, 1, 1, 1, 0, 0, 0, 1}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BooleanArray.TYPE.sendValue(new Object[1000], new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
BooleanArray.TYPE.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadBooleanArray() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{4, 0, 1, 1, 0});
|
||||
assertArrayEquals(new Object[]{false, true, true, false}, (Object[])BooleanArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{9, 0, 1, 1, 1, 0, 0, 1, 1, 1});
|
||||
assertArrayEquals(new Object[]{false, true, true, true, false, false, true, true, true}, (Object[])BooleanArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWriteBooleanArray() throws Exception{
|
||||
StreamPipeProvider streamProvider = new StreamPipeProvider();
|
||||
NetworkTableServer server = new NetworkTableServer(streamProvider);
|
||||
NetworkTableClient client = new NetworkTableClient(streamProvider.getFactory());
|
||||
|
||||
final BooleanArray data = new BooleanArray();
|
||||
data.setSize(4);
|
||||
data.set(0, true);
|
||||
data.set(1, false);
|
||||
data.set(2, false);
|
||||
data.set(3, true);
|
||||
|
||||
server.putValue("MyKey", data);
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
final BooleanArray targetData = new BooleanArray();
|
||||
client.retrieveValue("MyKey", targetData);
|
||||
assertEquals(4, targetData.size());
|
||||
assertEquals(targetData.get(0), true);
|
||||
assertEquals(targetData.get(1), false);
|
||||
assertEquals(targetData.get(2), false);
|
||||
assertEquals(targetData.get(3), true);
|
||||
client.stop();
|
||||
server.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Double
|
||||
*/
|
||||
@Test
|
||||
public void testSendNumberArray(){
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
NumberArray.TYPE.sendValue(new Object[]{new Double(10), new Double(20), new Double(200.3), new Double(-1.3)}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{4, 64, 36, 0, 0, 0, 0, 0, 0, 64, 52, 0, 0, 0, 0, 0, 0, 64, 105, 9, -103, -103, -103, -103, -102, -65, -12, -52, -52, -52, -52, -52, -51}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
NumberArray.TYPE.sendValue(new Object[]{new Double(10), new Double(20), new Double(200.3), new Double(-1.3), new Double(11), new Double(-3.3), new Double(11), new Double(66.2)}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{8, 64, 36, 0, 0, 0, 0, 0, 0, 64, 52, 0, 0, 0, 0, 0, 0, 64, 105, 9, -103, -103, -103, -103, -102, -65, -12, -52, -52, -52, -52, -52, -51, 64, 38, 0, 0, 0, 0, 0, 0, -64, 10, 102, 102, 102, 102, 102, 102, 64, 38, 0, 0, 0, 0, 0, 0, 64, 80, -116, -52, -52, -52, -52, -51}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
NumberArray.TYPE.sendValue(new Object[1000], new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
NumberArray.TYPE.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadNumberArray() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{4, 64, 36, 0, 0, 0, 0, 0, 0, 64, 52, 0, 0, 0, 0, 0, 0, 64, 105, 9, -103, -103, -103, -103, -102, -65, -12, -52, -52, -52, -52, -52, -51});
|
||||
assertArrayEquals(new Object[]{new Double(10), new Double(20), new Double(200.3), new Double(-1.3)}, (Object[])NumberArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{8, 64, 36, 0, 0, 0, 0, 0, 0, 64, 52, 0, 0, 0, 0, 0, 0, 64, 105, 9, -103, -103, -103, -103, -102, -65, -12, -52, -52, -52, -52, -52, -51, 64, 38, 0, 0, 0, 0, 0, 0, -64, 10, 102, 102, 102, 102, 102, 102, 64, 38, 0, 0, 0, 0, 0, 0, 64, 80, -116, -52, -52, -52, -52, -51});
|
||||
assertArrayEquals(new Object[]{new Double(10), new Double(20), new Double(200.3), new Double(-1.3), new Double(11), new Double(-3.3), new Double(11), new Double(66.2)}, (Object[])NumberArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWriteNumberArray() throws Exception{
|
||||
StreamPipeProvider streamProvider = new StreamPipeProvider();
|
||||
NetworkTableServer server = new NetworkTableServer(streamProvider);
|
||||
NetworkTableClient client = new NetworkTableClient(streamProvider.getFactory());
|
||||
|
||||
final NumberArray data = new NumberArray();
|
||||
data.setSize(4);
|
||||
data.set(0, 10.4);
|
||||
data.set(1, 44.3);
|
||||
data.set(2, 33.4);
|
||||
data.set(3, 233);
|
||||
|
||||
server.putValue("MyKey", data);
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
final NumberArray targetData = new NumberArray();
|
||||
client.retrieveValue("MyKey", targetData);
|
||||
assertEquals(4, targetData.size());
|
||||
assertEquals(targetData.get(0), 10.4, 0);
|
||||
assertEquals(targetData.get(1), 44.3, 0);
|
||||
assertEquals(targetData.get(2), 33.4, 0);
|
||||
assertEquals(targetData.get(3), 233, 0);
|
||||
client.stop();
|
||||
server.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* String
|
||||
*/
|
||||
@Test
|
||||
public void testSendStringArray(){
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
StringArray.TYPE.sendValue(new Object[]{"HI", "", "HELlO", "--asdf"}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{4, 0, 2, 72, 73, 0, 0, 0, 5, 72, 69, 76, 108, 79, 0, 6, 45, 45, 97, 115, 100, 102}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
StringArray.TYPE.sendValue(new Object[]{"", "TEw4390", "00*&(&(*&*", "adsf", "asdfasdf", "asdfai888"}, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{6, 0, 0, 0, 7, 84, 69, 119, 52, 51, 57, 48, 0, 10, 48, 48, 42, 38, 40, 38, 40, 42, 38, 42, 0, 4, 97, 100, 115, 102, 0, 8, 97, 115, 100, 102, 97, 115, 100, 102, 0, 9, 97, 115, 100, 102, 97, 105, 56, 56, 56}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
StringArray.TYPE.sendValue(new Object[1000], new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
StringArray.TYPE.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadStringArray() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{4, 0, 2, 72, 73, 0, 0, 0, 5, 72, 69, 76, 108, 79, 0, 6, 45, 45, 97, 115, 100, 102});
|
||||
assertArrayEquals(new Object[]{"HI", "", "HELlO", "--asdf"}, (Object[])StringArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{6, 0, 0, 0, 7, 84, 69, 119, 52, 51, 57, 48, 0, 10, 48, 48, 42, 38, 40, 38, 40, 42, 38, 42, 0, 4, 97, 100, 115, 102, 0, 8, 97, 115, 100, 102, 97, 115, 100, 102, 0, 9, 97, 115, 100, 102, 97, 105, 56, 56, 56});
|
||||
assertArrayEquals(new Object[]{"", "TEw4390", "00*&(&(*&*", "adsf", "asdfasdf", "asdfai888"}, (Object[])StringArray.TYPE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadWriteStringArray() throws Exception{
|
||||
StreamPipeProvider streamProvider = new StreamPipeProvider();
|
||||
NetworkTableServer server = new NetworkTableServer(streamProvider);
|
||||
NetworkTableClient client = new NetworkTableClient(streamProvider.getFactory());
|
||||
|
||||
final StringArray data = new StringArray();
|
||||
data.setSize(5);
|
||||
data.set(0, "HI");
|
||||
data.set(1, "ehllos");
|
||||
data.set(2, "sdf-9889");
|
||||
data.set(3, "hi-----");
|
||||
data.set(4, "sfdasdfasdfasdfasf");
|
||||
|
||||
server.putValue("MyKey", data);
|
||||
|
||||
Thread.sleep(1500);
|
||||
|
||||
final StringArray targetData = new StringArray();
|
||||
client.retrieveValue("MyKey", targetData);
|
||||
assertEquals(5, targetData.size());
|
||||
assertEquals(targetData.get(0), "HI");
|
||||
assertEquals(targetData.get(1), "ehllos");
|
||||
assertEquals(targetData.get(2), "sdf-9889");
|
||||
assertEquals(targetData.get(3), "hi-----");
|
||||
assertEquals(targetData.get(4), "sfdasdfasdfasdfasf");
|
||||
client.stop();
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.TableKeyExistsWithDifferentTypeException;
|
||||
import edu.wpi.first.wpilibj.tables.TableKeyNotDefinedException;
|
||||
import org.jmock.Expectations;
|
||||
import org.jmock.Mockery;
|
||||
import org.jmock.integration.junit4.JMock;
|
||||
import org.jmock.integration.junit4.JUnit4Mockery;
|
||||
import org.jmock.lib.legacy.ClassImposteriser;
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import test.util.NetworkTableTestNode;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Mitchell
|
||||
*/
|
||||
@RunWith(JMock.class)
|
||||
public class ComplexTypeTest {
|
||||
Mockery context = new JUnit4Mockery(){{
|
||||
setImposteriser(ClassImposteriser.INSTANCE);
|
||||
}};
|
||||
|
||||
@Test
|
||||
public void testPutComplexValue() throws Exception{
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
|
||||
final ComplexEntryType dataType = context.mock(ComplexEntryType.class);
|
||||
final ComplexData data1 = context.mock(ComplexData.class, "data1");
|
||||
final Object value1 = new Object();
|
||||
final ComplexData data2 = context.mock(ComplexData.class, "data2");
|
||||
final Object value2 = new Object();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(data1).getType();will(returnValue(dataType));
|
||||
oneOf(dataType).internalizeValue("MyKey", data1, null);will(returnValue(value1));
|
||||
}});
|
||||
node.putValue("MyKey", data1);
|
||||
assertSame(value1, node.getValue("MyKey"));
|
||||
context.assertIsSatisfied();
|
||||
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
allowing(data2).getType();will(returnValue(dataType));
|
||||
oneOf(dataType).internalizeValue("MyKey", data2, value1);will(returnValue(value2));
|
||||
}});
|
||||
node.putValue("MyKey", data2);
|
||||
assertSame(value2, node.getValue("MyKey"));
|
||||
context.assertIsSatisfied();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveComplexValue() throws Exception{
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
|
||||
final ComplexEntryType dataType = context.mock(ComplexEntryType.class);
|
||||
final ComplexData data = context.mock(ComplexData.class, "data");
|
||||
final Object value = new Object();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(dataType).internalizeValue("MyKey", value, null);will(returnValue(value));
|
||||
}});
|
||||
node.putValue("MyKey", dataType, value);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
context.checking(new Expectations() {{
|
||||
oneOf(dataType).exportValue("MyKey", value, data);
|
||||
}});
|
||||
node.retrieveValue("MyKey", data);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveNonExistantValue(){
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
final ComplexData data = context.mock(ComplexData.class, "data");
|
||||
|
||||
try{
|
||||
node.retrieveValue("MyKey", data);
|
||||
fail();
|
||||
} catch(TableKeyNotDefinedException e){}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrieveNonComplexValue() throws Exception{
|
||||
NetworkTableTestNode node = new NetworkTableTestNode();
|
||||
final ComplexData data = context.mock(ComplexData.class, "data");
|
||||
|
||||
node.putString("MyKey", "SomeValue");
|
||||
try{
|
||||
node.retrieveValue("MyKey", data);
|
||||
fail();
|
||||
} catch(TableKeyExistsWithDifferentTypeException e){}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.type;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
public class EntryTypeTest {
|
||||
|
||||
@Test
|
||||
public void testIdToType() {
|
||||
assertSame(DefaultEntryTypes.BOOLEAN, new NetworkTableEntryTypeManager().getType((byte)0));
|
||||
assertSame(DefaultEntryTypes.DOUBLE, new NetworkTableEntryTypeManager().getType((byte)1));
|
||||
assertSame(DefaultEntryTypes.STRING, new NetworkTableEntryTypeManager().getType((byte)2));
|
||||
assertNull(new NetworkTableEntryTypeManager().getType((byte)3));
|
||||
assertNull(new NetworkTableEntryTypeManager().getType((byte)4));
|
||||
assertNull(new NetworkTableEntryTypeManager().getType((byte)5));
|
||||
assertNull(new NetworkTableEntryTypeManager().getType((byte)127));
|
||||
assertNull(new NetworkTableEntryTypeManager().getType((byte)-1));
|
||||
}
|
||||
@Test
|
||||
public void testTypeIds() {
|
||||
assertEquals(0, DefaultEntryTypes.BOOLEAN.id);
|
||||
assertEquals(1, DefaultEntryTypes.DOUBLE.id);
|
||||
assertEquals(2, DefaultEntryTypes.STRING.id);
|
||||
}
|
||||
@Test
|
||||
public void testTypeNames() {
|
||||
assertEquals("Boolean", DefaultEntryTypes.BOOLEAN.name);
|
||||
assertEquals("Double", DefaultEntryTypes.DOUBLE.name);
|
||||
assertEquals("String", DefaultEntryTypes.STRING.name);
|
||||
}
|
||||
@Test
|
||||
public void testTypeToString() {
|
||||
assertEquals("NetworkTable type: Boolean", DefaultEntryTypes.BOOLEAN.toString());
|
||||
assertEquals("NetworkTable type: Double", DefaultEntryTypes.DOUBLE.toString());
|
||||
assertEquals("NetworkTable type: String", DefaultEntryTypes.STRING.toString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBooleanRead() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{0});
|
||||
assertEquals(false, DefaultEntryTypes.BOOLEAN.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{1});
|
||||
assertEquals(true, DefaultEntryTypes.BOOLEAN.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[0]);
|
||||
assertEquals(false, DefaultEntryTypes.BOOLEAN.readValue(new DataInputStream(input)));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBooleanWrite() {
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.BOOLEAN.sendValue(false, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{0}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.BOOLEAN.sendValue(true, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{1}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.BOOLEAN.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testDoubleRead() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{64, 41, 0, 0, 0, 0, 0, 0});
|
||||
assertEquals(12.5, DefaultEntryTypes.DOUBLE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{64, 100, 0, 0, 0, 0, 0, 0});
|
||||
assertEquals(160.0, DefaultEntryTypes.DOUBLE.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[0]);
|
||||
assertEquals(false, DefaultEntryTypes.DOUBLE.readValue(new DataInputStream(input)));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleWrite() {
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.DOUBLE.sendValue(12.5, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{64, 41, 0, 0, 0, 0, 0, 0}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.DOUBLE.sendValue(160.0, new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{64, 100, 0, 0, 0, 0, 0, 0}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.DOUBLE.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testStringRead() {
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{0, 8, 77, 121, 32, 69, 110, 116, 114, 121});
|
||||
assertEquals("My Entry", DefaultEntryTypes.STRING.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[]{0, 5, 86, 97, 76, 117, 69});
|
||||
assertEquals("VaLuE", DefaultEntryTypes.STRING.readValue(new DataInputStream(input)));
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayInputStream input = new ByteArrayInputStream(new byte[0]);
|
||||
assertEquals(false, DefaultEntryTypes.STRING.readValue(new DataInputStream(input)));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringWrite() {
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.STRING.sendValue("My Entry", new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{0, 8, 77, 121, 32, 69, 110, 116, 114, 121}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.STRING.sendValue("VaLuE", new DataOutputStream(output));
|
||||
assertArrayEquals(new byte[]{0, 5, 86, 97, 76, 117, 69}, output.toByteArray());
|
||||
} catch (IOException e) {
|
||||
fail();
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
DefaultEntryTypes.STRING.sendValue(new Object(), new DataOutputStream(output));
|
||||
fail();
|
||||
} catch (IOException e) {}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.util;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.junit.*;
|
||||
|
||||
/**
|
||||
* @author mwills
|
||||
* @author Fred
|
||||
*/
|
||||
public class ListTest {
|
||||
|
||||
@Test
|
||||
public void testIsEmpty() {
|
||||
List list = new List();
|
||||
assertThat(list, isEmpty());
|
||||
list.add(new Integer(42));
|
||||
assertThat(list, not(isEmpty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSize() {
|
||||
List list = new List();
|
||||
assertThat(list, isEmpty());
|
||||
for (int i = 0; i < 42; i++) {
|
||||
list.add(new Integer(i));
|
||||
assertThat(list, hasSize(i+1));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSizeGrowth() {
|
||||
List list = new List(10);
|
||||
assertThat(list, isEmpty());
|
||||
for (int i = 0; i < 100; i++) {
|
||||
list.add(new Integer(i));
|
||||
}
|
||||
for (int i = 0; i < 100; i++) {
|
||||
assertThat(list, hasItem(i, equalTo(new Integer(i))));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContains() {
|
||||
List list = new List();
|
||||
Integer testInt1 = new Integer(42);
|
||||
Integer testInt2 = new Integer(43);
|
||||
assertThat(list, not(contains(testInt1)));
|
||||
list.add(testInt1);
|
||||
assertThat(list, contains(testInt1));
|
||||
assertThat(list, not(contains(testInt2)));
|
||||
list.add(testInt2);
|
||||
assertThat(list, contains(testInt2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveObject() {
|
||||
List list = new List();
|
||||
Integer testInt1 = new Integer(42);
|
||||
Integer testInt2 = new Integer(43);
|
||||
Integer testInt3 = new Integer(44);
|
||||
list.add(testInt1);
|
||||
list.add(testInt2);
|
||||
list.add(testInt3);
|
||||
assertThat(list, contains(testInt1));
|
||||
assertThat(list, contains(testInt2));
|
||||
assertThat(list, contains(testInt3));
|
||||
assertThat(list, hasSize(3));
|
||||
list.remove(testInt1);
|
||||
list.remove(testInt2);
|
||||
list.remove(testInt3);
|
||||
assertThat(list, not(contains(testInt1)));
|
||||
assertThat(list, not(contains(testInt2)));
|
||||
assertThat(list, not(contains(testInt3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddRemoveIndex() {
|
||||
List list = new List();
|
||||
Integer testInt1 = new Integer(42);
|
||||
Integer testInt2 = new Integer(43);
|
||||
Integer testInt3 = new Integer(44);
|
||||
list.add(testInt1);
|
||||
list.add(testInt2);
|
||||
list.add(testInt3);
|
||||
assertThat(list, hasItem(0, equalTo(testInt1)));
|
||||
assertThat(list, hasItem(1, equalTo(testInt2)));
|
||||
assertThat(list, hasItem(2, equalTo(testInt3)));
|
||||
assertThat(list, hasSize(3));
|
||||
list.remove(2);
|
||||
list.remove(1);
|
||||
list.remove(0);
|
||||
assertThat(list, isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
List list = new List();
|
||||
Integer testInt1 = new Integer(42);
|
||||
Integer testInt2 = new Integer(43);
|
||||
Integer testInt3 = new Integer(44);
|
||||
list.add(testInt1);
|
||||
list.add(testInt2);
|
||||
list.add(testInt3);
|
||||
assertThat(list, not(isEmpty()));
|
||||
list.clear();
|
||||
assertTrue(list.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOrdering(){
|
||||
Integer obj1 = new Integer(42);
|
||||
Boolean obj2 = new Boolean(false);
|
||||
Double obj3 = new Double(42.42);
|
||||
List list = new List();
|
||||
list.add(obj1);
|
||||
list.add(obj2);
|
||||
list.add(obj3);
|
||||
assertThat(list, hasItem(0, equalTo(obj1)));
|
||||
assertThat(list, hasItem(1, equalTo(obj2)));
|
||||
assertThat(list, hasItem(2, equalTo(obj3)));
|
||||
list.remove(obj2);
|
||||
assertThat(list, hasItem(0, equalTo(obj1)));
|
||||
assertThat(list, hasItem(1, equalTo(obj3)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSet(){
|
||||
Integer obj1 = new Integer(42);
|
||||
Boolean obj2 = new Boolean(false);
|
||||
Double obj3 = new Double(42.42);
|
||||
String obj4 = "MyString";
|
||||
String obj5 = "MyString2";
|
||||
String obj6 = "MyString3";
|
||||
List list = new List();
|
||||
list.add(obj1);
|
||||
list.add(obj2);
|
||||
list.add(obj3);
|
||||
assertThat(list, hasItem(0, equalTo(obj1)));
|
||||
assertThat(list, hasItem(1, equalTo(obj2)));
|
||||
assertThat(list, hasItem(2, equalTo(obj3)));
|
||||
list.set(1, obj4);
|
||||
assertThat(list, hasItem(0, equalTo(obj1)));
|
||||
assertThat(list, hasItem(1, equalTo(obj4)));
|
||||
assertThat(list, hasItem(2, equalTo(obj3)));
|
||||
assertThat(list, hasSize(3));
|
||||
list.set(2, obj5);
|
||||
assertThat(list, hasItem(0, equalTo(obj1)));
|
||||
assertThat(list, hasItem(1, equalTo(obj4)));
|
||||
assertThat(list, hasItem(2, equalTo(obj5)));
|
||||
assertThat(list, hasSize(3));
|
||||
list.set(0, obj6);
|
||||
assertThat(list, hasItem(0, equalTo(obj6)));
|
||||
assertThat(list, hasItem(1, equalTo(obj4)));
|
||||
assertThat(list, hasItem(2, equalTo(obj5)));
|
||||
assertThat(list, hasSize(3));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Matcher<List> contains(final Object object){
|
||||
return new TypeSafeMatcher<List>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("contains ").appendValue(object);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(List item) {
|
||||
return item.contains(object);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
public Matcher<List> isEmpty(){
|
||||
return new TypeSafeMatcher<List>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("is empty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(List item) {
|
||||
return item.isEmpty();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
public Matcher<List> hasSize(final int size){
|
||||
return new TypeSafeMatcher<List>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("has size ").appendValue(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(List item) {
|
||||
return item.size()==size;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
public Matcher<List> hasItem(final int index, final Matcher<?> matcher){
|
||||
return new TypeSafeMatcher<List>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("has ").appendDescriptionOf(matcher).appendText(" at index ").appendValue(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(List item) {
|
||||
return matcher.matches(item.get(index));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.util;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.hamcrest.*;
|
||||
import org.junit.*;
|
||||
|
||||
/**
|
||||
* @author mwills
|
||||
* @author Fred
|
||||
*/
|
||||
public class StackTest {
|
||||
|
||||
@Test
|
||||
public void pushTest(){
|
||||
Integer obj1 = new Integer(0);
|
||||
Stack stack = new Stack();
|
||||
assertThat(stack, isEmpty());
|
||||
stack.push(obj1);
|
||||
assertThat(stack, not(isEmpty()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void popTest(){
|
||||
Integer obj1 = new Integer(0);
|
||||
Object obj2;
|
||||
Stack stack = new Stack();
|
||||
assertThat(stack, isEmpty());
|
||||
obj2 = stack.pop();
|
||||
assertNull(obj2);
|
||||
stack.push(obj1);
|
||||
obj2 = stack.pop();
|
||||
assertSame(obj1, obj2);
|
||||
assertThat(stack, isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void orderingTest(){
|
||||
Integer obj1 = new Integer(42);
|
||||
Integer obj2 = new Integer(43);
|
||||
Integer obj3 = new Integer(44);
|
||||
Object obj4;
|
||||
Object obj5;
|
||||
Object obj6;
|
||||
Object obj7;
|
||||
Stack stack = new Stack();
|
||||
assertThat(stack, isEmpty());
|
||||
stack.push(obj1);
|
||||
assertThat(stack, hasSize(1));
|
||||
stack.push(obj2);
|
||||
stack.push(obj3);
|
||||
assertThat(stack, hasSize(3));
|
||||
obj4 = stack.pop();
|
||||
assertThat(stack, hasSize(2));
|
||||
obj5 = stack.pop();
|
||||
obj6 = stack.pop();
|
||||
assertSame(obj1, obj6);
|
||||
assertSame(obj2, obj5);
|
||||
assertSame(obj3, obj4);
|
||||
stack.push(obj1);
|
||||
stack.push(obj2);
|
||||
stack.push(obj3);
|
||||
stack.pop();
|
||||
stack.push(obj1);
|
||||
obj7 = stack.pop();
|
||||
assertSame(obj1, obj7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public Matcher<Stack> isEmpty(){
|
||||
return new TypeSafeMatcher<Stack>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("is empty");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(Stack item) {
|
||||
return item.isEmpty();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
public Matcher<Stack> hasSize(final int size){
|
||||
return new TypeSafeMatcher<Stack>(){
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("has size ").appendValue(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matchesSafely(Stack item) {
|
||||
return item.size()==size;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package edu.wpi.first.wpilibj.tables;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
public class TableKeyNotDefinedExceptionTest {
|
||||
|
||||
@Test
|
||||
public void throwExceptionTest(){
|
||||
try {
|
||||
throw new TableKeyNotDefinedException("Key 1");
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
assertEquals("Unkown Table Key: Key 1", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package test.util;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
|
||||
public class ByteArrayStream implements IOStream {
|
||||
|
||||
private final ByteArrayOutputStream os;
|
||||
private final ByteArrayInputStream is;
|
||||
|
||||
public ByteArrayStream() {
|
||||
this(new byte[0]);
|
||||
}
|
||||
public ByteArrayStream(final byte[] inputData) {
|
||||
this(new ByteArrayOutputStream(), new ByteArrayInputStream(inputData));
|
||||
}
|
||||
public ByteArrayStream(final ByteArrayOutputStream os, final byte[] inputData) {
|
||||
this(os, new ByteArrayInputStream(inputData));
|
||||
}
|
||||
public ByteArrayStream(final ByteArrayOutputStream os, final ByteArrayInputStream is) {
|
||||
this.is = is;
|
||||
this.os = os;
|
||||
}
|
||||
|
||||
public byte[] getOutput(){
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return is;
|
||||
}
|
||||
public OutputStream getOutputStream() {
|
||||
return os;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try{
|
||||
is.close();
|
||||
} catch(IOException e){}
|
||||
try {
|
||||
os.close();
|
||||
} catch (IOException e){}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package test.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
public class LoggingOutputStream extends OutputStream {
|
||||
|
||||
private final OutputStream backingStream;
|
||||
private final ByteArrayOutputStream buffer;
|
||||
|
||||
public LoggingOutputStream(OutputStream backingStream){
|
||||
this.backingStream = backingStream;
|
||||
buffer = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
backingStream.close();
|
||||
System.out.println("Closed "+backingStream+" with "+Arrays.toString(buffer.toByteArray()));
|
||||
buffer.reset();
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
backingStream.flush();
|
||||
System.out.println("Wrote "+Arrays.toString(buffer.toByteArray())+" to "+backingStream);
|
||||
buffer.reset();
|
||||
}
|
||||
|
||||
public void write(byte[] b) throws IOException {
|
||||
backingStream.write(b);
|
||||
buffer.write(b);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
backingStream.write(b, off, len);
|
||||
buffer.write(b, off, len);
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
backingStream.write(b);
|
||||
buffer.write(b);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package test.util;
|
||||
|
||||
import org.hamcrest.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
public class NetworkTableEntryUtil {
|
||||
public static NetworkTableEntry newBooleanEntry(final String name, final boolean value){
|
||||
return new NetworkTableEntry(name, DefaultEntryTypes.BOOLEAN, new Boolean(value));
|
||||
}
|
||||
public static NetworkTableEntry newBooleanEntry(char id, String name, char sequenceNumber, boolean value){
|
||||
return new NetworkTableEntry(id, name, sequenceNumber, DefaultEntryTypes.BOOLEAN, new Boolean(value));
|
||||
}
|
||||
|
||||
public static NetworkTableEntry newDoubleEntry(String name, double value){
|
||||
return new NetworkTableEntry(name, DefaultEntryTypes.DOUBLE, new Double(value));
|
||||
}
|
||||
public static NetworkTableEntry newDoubleEntry(char id, String name, char sequenceNumber, double value){
|
||||
return new NetworkTableEntry(id, name, sequenceNumber, DefaultEntryTypes.DOUBLE, new Double(value));
|
||||
}
|
||||
|
||||
public static NetworkTableEntry newStringEntry(String name, String value){
|
||||
return new NetworkTableEntry(name, DefaultEntryTypes.STRING, value);
|
||||
}
|
||||
public static NetworkTableEntry newStringEntry(char id, String name, char sequenceNumber, String value){
|
||||
return new NetworkTableEntry(id, name, sequenceNumber, DefaultEntryTypes.STRING, value);
|
||||
}
|
||||
|
||||
public static Matcher<NetworkTableEntry> aBooleanEntry(final int id, final String name, final int sequenceNumber, final boolean value){
|
||||
return aTableEntry((char)id, name, (char)sequenceNumber, DefaultEntryTypes.BOOLEAN, value);
|
||||
}
|
||||
public static Matcher<NetworkTableEntry> aDoubleEntry(final int id, final String name, final int sequenceNumber, final double value){
|
||||
return aTableEntry((char)id, name, (char)sequenceNumber, DefaultEntryTypes.DOUBLE, value);
|
||||
}
|
||||
public static Matcher<NetworkTableEntry> aStringEntry(final int id, final String name, final int sequenceNumber, final String value){
|
||||
return aTableEntry((char)id, name, (char)sequenceNumber, DefaultEntryTypes.STRING, value);
|
||||
}
|
||||
|
||||
public static Matcher<NetworkTableEntry> aTableEntry(final char id, final String name, final char sequenceNumber, final NetworkTableEntryType type, final Object value){
|
||||
return new TypeSafeMatcher<NetworkTableEntry>() {
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText(" a NetworkTableEntry with an id ").appendValue((int)id)
|
||||
.appendText(" and name ").appendValue(name)
|
||||
.appendText(" and sequence number ").appendValue((int)sequenceNumber)
|
||||
.appendText(" and type ").appendValue(type)
|
||||
.appendText(" and value ").appendValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean matchesSafely(NetworkTableEntry item) {
|
||||
if(item.getId()!=id)
|
||||
return false;
|
||||
if(!item.name.equals(name))
|
||||
return false;
|
||||
if(item.getSequenceNumber()!=sequenceNumber)
|
||||
return false;
|
||||
if(!item.getType().equals(type))
|
||||
return false;
|
||||
if(!item.getValue().equals(value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package test.util;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.client.*;
|
||||
|
||||
/**
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableTestNode extends NetworkTableNode{
|
||||
|
||||
public NetworkTableTestNode(){
|
||||
this(OutgoingEntryReceiver.NULL, OutgoingEntryReceiver.NULL);
|
||||
}
|
||||
public NetworkTableTestNode(OutgoingEntryReceiver incomingReceiver, OutgoingEntryReceiver outgoingReceiver){
|
||||
init(new ClientNetworkTableEntryStore(this));
|
||||
|
||||
getEntryStore().setOutgoingReceiver(outgoingReceiver);
|
||||
getEntryStore().setIncomingReceiver(incomingReceiver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package test.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
|
||||
public class StreamPipeProvider implements IOStreamProvider{
|
||||
private final StreamPipeFactory factory;
|
||||
private boolean hasAccepted = false;
|
||||
private final CountDownLatch closedLatch = new CountDownLatch(1);
|
||||
public StreamPipeProvider(){
|
||||
try {
|
||||
factory = new StreamPipeFactory();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public IOStream accept() throws IOException {
|
||||
if(!hasAccepted){
|
||||
hasAccepted = true;
|
||||
return factory.getServerStream();
|
||||
}
|
||||
try {
|
||||
closedLatch.await();
|
||||
|
||||
} catch (InterruptedException e) {}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
closedLatch.countDown();
|
||||
}
|
||||
|
||||
public StreamPipeFactory getFactory(){
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class StreamPipeFactory implements IOStreamFactory{
|
||||
private final PipedOutputStream serverOut;
|
||||
private final PipedInputStream serverIn;
|
||||
|
||||
private final PipedOutputStream clientOut;
|
||||
private final PipedInputStream clientIn;
|
||||
|
||||
private final IOStream serverStream;
|
||||
private final IOStream clientStream;
|
||||
|
||||
public StreamPipeFactory() throws IOException {
|
||||
clientIn = new PipedInputStream(serverOut = new PipedOutputStream());
|
||||
serverIn = new PipedInputStream(clientOut = new PipedOutputStream());
|
||||
|
||||
serverStream = new SimpleIOStream(serverIn, serverOut);
|
||||
clientStream = new SimpleIOStream(clientIn, clientOut);
|
||||
}
|
||||
|
||||
public IOStream getServerStream(){
|
||||
return serverStream;
|
||||
}
|
||||
|
||||
public IOStream getClientStream(){
|
||||
return clientStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOStream createStream() throws IOException {
|
||||
return getClientStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package test.util;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public class TestExecutor implements Executor, ThreadFactory{
|
||||
private ScheduledExecutorService executor;
|
||||
private long threadTimeout;
|
||||
private LinkedBlockingQueue<Throwable> exceptions = new LinkedBlockingQueue<Throwable>();
|
||||
|
||||
public TestExecutor(int numThreads, long threadTimeout) {
|
||||
this.threadTimeout = threadTimeout;
|
||||
executor = Executors.newScheduledThreadPool(numThreads, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
executor.schedule(command, threadTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread newThread(final Runnable r) {
|
||||
return new Thread(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
try{
|
||||
r.run();
|
||||
} catch(Throwable t){
|
||||
exceptions.offer(t);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
public void await(long timeout, TimeUnit unit) throws Throwable{
|
||||
executor.shutdown();
|
||||
executor.awaitTermination(timeout, unit);
|
||||
Throwable firstError = exceptions.poll();
|
||||
if(firstError!=null)
|
||||
throw firstError;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package test.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
|
||||
public class TestServerConnectionProvider implements IOStreamProvider{
|
||||
private final BlockingQueue<IOStream> connections = new LinkedBlockingQueue<IOStream>();
|
||||
|
||||
public void supply(IOStream stream){
|
||||
connections.offer(stream);
|
||||
}
|
||||
|
||||
public IOStream accept() {
|
||||
try {
|
||||
return connections.take();
|
||||
} catch (InterruptedException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package test.util;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
|
||||
public class TestThreadManager implements NTThreadManager {
|
||||
private final List<TestPeriodicThread> periodicThreads = new CopyOnWriteArrayList<TestPeriodicThread>();
|
||||
|
||||
|
||||
public class TestPeriodicThread implements NTThread{
|
||||
|
||||
private final PeriodicRunnable r;
|
||||
private final String name;
|
||||
public TestPeriodicThread(PeriodicRunnable r, String name){
|
||||
this.r = r;
|
||||
this.name = name;
|
||||
}
|
||||
public String toString(){
|
||||
return "Test Thread: "+name;
|
||||
}
|
||||
public String getName(){
|
||||
return r.getClass().getName();
|
||||
}
|
||||
public void run(){
|
||||
try {
|
||||
r.run();
|
||||
} catch (InterruptedException e) {}
|
||||
}
|
||||
@Override
|
||||
public void stop() {
|
||||
periodicThreads.remove(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return periodicThreads.contains(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public NTThread newBlockingPeriodicThread(PeriodicRunnable r, String name) {
|
||||
TestPeriodicThread thread = new TestPeriodicThread(r, name);
|
||||
periodicThreads.add(thread);
|
||||
return thread;
|
||||
}
|
||||
|
||||
public TestPeriodicThread getPeriodicThread(Class<?> type){
|
||||
TestPeriodicThread foundThread = null;
|
||||
for(TestPeriodicThread thread:periodicThreads){
|
||||
if(thread.getName().equals(type.getName())){
|
||||
if(foundThread!=null)
|
||||
throw new RuntimeException("There are more than one periodic threads of type: "+type);
|
||||
foundThread = thread;
|
||||
}
|
||||
}
|
||||
if(foundThread==null)
|
||||
throw new RuntimeException("There are no periodic threads of type: "+type);
|
||||
return foundThread;
|
||||
}
|
||||
public List<TestPeriodicThread> getAllPeriodicThread(Class<?> type){
|
||||
List<TestPeriodicThread> threads = new ArrayList<TestPeriodicThread>();
|
||||
for(TestPeriodicThread thread:periodicThreads){
|
||||
if(thread.getName().equals(type.getName()))
|
||||
threads.add(thread);
|
||||
}
|
||||
return threads;
|
||||
}
|
||||
public void runAllPeriodicThread(Class<?> type){
|
||||
for(TestPeriodicThread thread:periodicThreads){
|
||||
if(thread.getName().equals(type.getName()))
|
||||
thread.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
73
networktables/java/Azalea/pom.xml
Normal file
73
networktables/java/Azalea/pom.xml
Normal file
@@ -0,0 +1,73 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>edu.wpi.first.wpilib.templates.azalea</groupId>
|
||||
<artifactId>library-jar</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>WPILib Repository</id>
|
||||
<url>http://frcbuilder.wpi.edu:8348/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.sun.squawk</groupId>
|
||||
<artifactId>runtime</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<testExcludes>
|
||||
<exclude>edu/wpi/first/wpilibj/networktables2/system/SystemTest.java</exclude>
|
||||
</testExcludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>add-source</id>
|
||||
<phase>generate-sources</phase>
|
||||
<goals>
|
||||
<goal>add-source</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sources>
|
||||
<source>../src/main/java</source>
|
||||
</sources>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-source-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,40 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import javax.microedition.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* An object that will provide cRIO socket connections when a client connects to the server on the given port
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketConnectionServerStreamProvider implements IOStreamProvider{
|
||||
|
||||
private final ServerSocketConnection server;
|
||||
|
||||
/**
|
||||
* Create a new Stream provider that wraps a Socket Server on the given port
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public SocketConnectionServerStreamProvider(final int port) throws IOException{
|
||||
server = (ServerSocketConnection) Connector.open("socket://:" + port);
|
||||
}
|
||||
|
||||
public IOStream accept() throws IOException {
|
||||
SocketConnection socket = (SocketConnection) server.acceptAndOpen();
|
||||
if(socket!=null){
|
||||
socket.setSocketOption(SocketConnection.LINGER, 0);
|
||||
return new SocketConnectionStream(socket);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
server.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import javax.microedition.io.*;
|
||||
|
||||
/**
|
||||
* A socket connection on the cRIO
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketConnectionStream implements IOStream{
|
||||
|
||||
private final SocketConnection socket;
|
||||
private final InputStream is;
|
||||
private final OutputStream os;
|
||||
|
||||
/**
|
||||
* Create a new IOStream for a socket connection with the given host and port
|
||||
* @param host
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public SocketConnectionStream(final String host, final int port) throws IOException {
|
||||
this((SocketConnection) Connector.open("socket://"+host+":"+port));
|
||||
}
|
||||
/**
|
||||
* Create a new IOStream for a socket connection
|
||||
* @param socket
|
||||
* @throws IOException
|
||||
*/
|
||||
public SocketConnectionStream(final SocketConnection socket) throws IOException {
|
||||
this.socket = socket;
|
||||
is = socket.openInputStream();
|
||||
os = socket.openOutputStream();
|
||||
}
|
||||
|
||||
|
||||
public InputStream getInputStream() {
|
||||
return is;
|
||||
}
|
||||
public OutputStream getOutputStream() {
|
||||
return os;
|
||||
}
|
||||
public void close() {
|
||||
try{
|
||||
is.close();
|
||||
} catch(IOException e){
|
||||
//just ignore and close the rest of the stream
|
||||
}
|
||||
try{
|
||||
os.close();
|
||||
} catch(IOException e){
|
||||
//just ignore and close the rest of the stream
|
||||
}
|
||||
try{
|
||||
socket.close();
|
||||
} catch(IOException e){
|
||||
//just ignore and assume socket is now closed
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class SocketConnectionStreamFactory implements IOStreamFactory{
|
||||
|
||||
private final String host;
|
||||
private final int port;
|
||||
|
||||
/**
|
||||
* Create a new factory that will create socket connections with the given host and port
|
||||
* @param host
|
||||
* @param port
|
||||
* @throws IOException
|
||||
*/
|
||||
public SocketConnectionStreamFactory(final String host, final int port) throws IOException {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public IOStream createStream() throws IOException {
|
||||
return new SocketConnectionStream(host, port);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.stream;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* Static factory for socket stream factories and providers
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class SocketStreams {
|
||||
/**
|
||||
* Create a new IOStream factory
|
||||
* @param host
|
||||
* @param port
|
||||
* @return a IOStreamFactory that will create Socket Connections on the given host and port
|
||||
* @throws IOException
|
||||
*/
|
||||
public static IOStreamFactory newStreamFactory(final String host, final int port) throws IOException{
|
||||
return new SocketConnectionStreamFactory(host, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new IOStream provider
|
||||
* @param port
|
||||
* @return an IOStreamProvider for a socket server on the given port
|
||||
* @throws IOException
|
||||
*/
|
||||
public static IOStreamProvider newStreamProvider(final int port) throws IOException {
|
||||
return new SocketConnectionServerStreamProvider(port);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package java.io;
|
||||
|
||||
public class BufferedInputStream extends InputStream{
|
||||
private final InputStream source;
|
||||
private byte[] buffer;
|
||||
private int pos;//the next position to be read
|
||||
private int maxPos;//the maximum valid position in the buffer + 1
|
||||
|
||||
public BufferedInputStream(InputStream source){
|
||||
this(source, 8192);
|
||||
}
|
||||
public BufferedInputStream(InputStream source, int size){
|
||||
this.source = source;
|
||||
buffer = new byte[size];
|
||||
pos = 0;
|
||||
maxPos = 0;
|
||||
}
|
||||
|
||||
|
||||
private void fillBuffer() throws IOException {
|
||||
int numRemaining = maxPos-pos;
|
||||
System.arraycopy(buffer, pos, buffer, 0, numRemaining);
|
||||
pos = 0;
|
||||
maxPos = numRemaining;
|
||||
int numRead = source.read(buffer, numRemaining, buffer.length-numRemaining);
|
||||
maxPos += numRead;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
if(pos<maxPos)
|
||||
return buffer[pos++]&0xFF;//cast to make sure not to return -1 and instead just return lowest byte of int
|
||||
fillBuffer();
|
||||
if(pos<maxPos)
|
||||
return buffer[pos++]&0xFF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public int available() throws IOException{
|
||||
return maxPos-pos+source.available();
|
||||
}
|
||||
|
||||
public void close() throws IOException{
|
||||
source.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package java.io;
|
||||
|
||||
public class BufferedOutputStream extends OutputStream{
|
||||
|
||||
private final byte[] buffer;
|
||||
private int pos;
|
||||
private final OutputStream out;
|
||||
|
||||
public BufferedOutputStream(OutputStream out){
|
||||
this(out, 8192);
|
||||
}
|
||||
public BufferedOutputStream(OutputStream out, int size){
|
||||
this.out = out;
|
||||
buffer = new byte[size];
|
||||
pos = 0;
|
||||
}
|
||||
private void flushBuffer() throws IOException{
|
||||
if(pos>0){
|
||||
out.write(buffer, 0, pos);
|
||||
pos = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
buffer[pos++] = (byte)b;
|
||||
if(pos>=buffer.length)
|
||||
flushBuffer();
|
||||
}
|
||||
|
||||
public void write(byte b[], int off, int len) throws IOException {
|
||||
if(len>=buffer.length){
|
||||
flushBuffer();
|
||||
out.write(b, off, len);
|
||||
}
|
||||
else{
|
||||
if(len>=(buffer.length-pos))
|
||||
flushBuffer();
|
||||
|
||||
System.arraycopy(b, off, buffer, pos, len);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
|
||||
public void flush() throws IOException{
|
||||
flushBuffer();
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public void close() throws IOException{
|
||||
flushBuffer();
|
||||
out.close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.system;
|
||||
|
||||
import edu.wpi.first.testing.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.server.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.tables.ITable;
|
||||
import edu.wpi.first.wpilibj.tables.ITableListener;
|
||||
import java.io.*;
|
||||
|
||||
public class SystemTest extends TestClass {
|
||||
private static NetworkTableServer staticServer;
|
||||
static{
|
||||
try {
|
||||
staticServer = new NetworkTableServer(SocketStreams.newStreamProvider(1735));
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
NetworkTableServer server;
|
||||
public void before() throws IOException{
|
||||
server = staticServer;
|
||||
staticServer.getEntryStore().clearEntries();
|
||||
}
|
||||
public void after(){
|
||||
//server.close();
|
||||
}
|
||||
|
||||
public void testSimpleBidirectionalPut() throws Exception{
|
||||
sendMessage("server up");
|
||||
|
||||
waitMessage();//Client connected
|
||||
System.out.println("client sent");
|
||||
sleep(100);
|
||||
assertEquals("CValue1-1", server.getString("ClientString1"));
|
||||
assertEquals("CValue2-1", server.getString("ClientString2"));
|
||||
server.putString("ServerString1", "SValue1-1");
|
||||
server.putString("ServerString2", "SValue2-1");
|
||||
sendMessage("server sent");
|
||||
System.out.println("sent server");
|
||||
|
||||
waitMessage();//Client sent
|
||||
System.out.println("client sent");
|
||||
sleep(100);
|
||||
assertEquals("CValue1-2", server.getString("ClientString1"));
|
||||
assertEquals("CValue2-2", server.getString("ClientString2"));
|
||||
server.putString("ServerString1", "SValue1-2");
|
||||
server.putString("ServerString2", "SValue2-2");
|
||||
sendMessage("server sent");
|
||||
System.out.println("sent server");
|
||||
|
||||
waitMessage();//test complete
|
||||
}
|
||||
public void testRapidServerPutSingleKey() throws Exception{
|
||||
sendMessage("server up");
|
||||
|
||||
waitMessage();//Client connected
|
||||
|
||||
|
||||
for(int i = 0; i<10000; ++i)
|
||||
server.putString("ServerKey", "SValue"+i);
|
||||
|
||||
sleep(100);
|
||||
sendMessage("server done");
|
||||
|
||||
waitMessage();//test complete
|
||||
}
|
||||
public void testRapidServerPutMultiKey() throws Exception{
|
||||
sendMessage("server up");
|
||||
|
||||
waitMessage();//Client connected
|
||||
|
||||
|
||||
for(int i = 0; i<1000; ++i)
|
||||
for(int j = 0; j<100; ++j)
|
||||
server.putString("ServerKey"+j, "SValue"+i);
|
||||
|
||||
sleep(100);
|
||||
sendMessage("server done");
|
||||
|
||||
waitMessage();//test complete
|
||||
}
|
||||
public void testPeriodicServerPutMultiKey() throws Exception{
|
||||
sendMessage("server up");
|
||||
|
||||
waitMessage();//Client connected
|
||||
|
||||
|
||||
for(int i = 0; i<100; ++i){
|
||||
for(int j = 0; j<100; ++j)
|
||||
server.putString("ServerKey"+j, "SValue"+i);
|
||||
sleep(20);
|
||||
}
|
||||
sleep(100);
|
||||
|
||||
sendMessage("server done");
|
||||
|
||||
waitMessage();//test complete
|
||||
}
|
||||
public void testBiDirectionalStress() throws Exception{
|
||||
server.addTableListener(new ITableListener() {
|
||||
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew) {
|
||||
int prefixIndex = key.indexOf("/client/");
|
||||
if(prefixIndex == 0) {
|
||||
String name = key.substring("/client/".length());
|
||||
server.putDouble("/server/" + name, ((Double) value).doubleValue());
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
sendMessage("Server ready");
|
||||
waitMessage(); // Client connected
|
||||
|
||||
waitMessage(); // Client done
|
||||
}
|
||||
}
|
||||
BIN
networktables/java/NetworkTablesTransactionFlow.pdf
Normal file
BIN
networktables/java/NetworkTablesTransactionFlow.pdf
Normal file
Binary file not shown.
12
networktables/java/README.txt
Normal file
12
networktables/java/README.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
Network Tables 2.0 README
|
||||
|
||||
Important Classes:
|
||||
|
||||
Network Table Transaction - Handles reading/writing bytes to a connection
|
||||
Client Connection Adapter - Handles behavior specific to a client and interacts with the entry store
|
||||
Server Connection Adapter - Handles behavior specific to a connection to a server and interacts with the server's entry store
|
||||
Null Transaction Receiver - Returns a transaction and all entries inside of it to the transaction pool
|
||||
Write Manager - Buffers transaction and writes them out periodically on another thread
|
||||
Transaction Dirtier - Marks all entries mentioned in a transaction as dirty
|
||||
Entry Store - The local copy of entries, worries about applying transactions locally
|
||||
Connection List - Keeps a list of connections and forwards a transaction to all of them
|
||||
48
networktables/java/ant/crio.xml
Normal file
48
networktables/java/ant/crio.xml
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
<project name="Network_Tables_2.0 cRIO">
|
||||
|
||||
<!-- crio build properties -->
|
||||
<property name="crio.build.dir" value="${build.dir}/crio" />
|
||||
<property name="src.crio.build.dir" value="${build.dir}/crio-src" />
|
||||
<property name="crio.dist.suffix" value="-crio" />
|
||||
<property name="crio.dist.filename" value="${jar-base-name}${crio.dist.suffix}${jar-suffix}.jar" />
|
||||
<property name="crio.src.dist.filename" value="${jar-base-name}${crio.dist.suffix}${jar-suffix}.src.zip" />
|
||||
<path id="crio.source.path">
|
||||
<fileset dir="${crio.src.dir}"/>
|
||||
<fileset dir="${src.dir}"/>
|
||||
</path>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- crio build -->
|
||||
<target name="build-crio">
|
||||
<delete dir="${crio.build.dir}" />
|
||||
<mkdir dir="${src.crio.build.dir}" />
|
||||
<copy todir="${src.crio.build.dir}">
|
||||
<path refid="crio.source.path" />
|
||||
</copy>
|
||||
|
||||
|
||||
<mkdir dir="${build.dir}/crio-resources/META-INF"/>
|
||||
<manifest file="${build.dir}/crio-resources/META-INF/MANIFEST.MF">
|
||||
<attribute name="Build-Number" value="${BUILD_NUMBER}"/>
|
||||
<attribute name="Built-On" value="${BUILD_ID}"/>
|
||||
<attribute name="Built-From" value="SVN r${SVN_REVISION}"/>
|
||||
<attribute name="Build-Type" value="${BUILD_TYPE}"/>
|
||||
<attribute name="Build-Target" value="cRIO"/>
|
||||
</manifest>
|
||||
<ant antfile="${sunspot.home}/build.xml">
|
||||
<property name="src.dir" value="${src.crio.build.dir}"/>
|
||||
<property name="resources.dir" value="${build.dir}/crio-resources"/>
|
||||
<property name="build.dir" value="${crio.build.dir}"/>
|
||||
<property name="app.jar.file" value="${dist.dir}/lib/${crio.dist.filename}"/>
|
||||
<property name="app.src.zip.file" value="${dist.dir}/lib/${crio.src.dist.filename}"/>
|
||||
<property name="preverify.exclude.library.jars" value="true"/>
|
||||
<property name="alternate.networktables.archive" value=""/>
|
||||
<target name="jar"/>
|
||||
<target name="archive-source"/>
|
||||
</ant>
|
||||
</target>
|
||||
</project>
|
||||
51
networktables/java/ant/desktop.xml
Normal file
51
networktables/java/ant/desktop.xml
Normal file
@@ -0,0 +1,51 @@
|
||||
|
||||
<project name="Network_Tables_2.0 Desktop">
|
||||
|
||||
|
||||
<!-- desktop build properties -->
|
||||
<property name="desktop.build.dir" value="${build.dir}/desktop" />
|
||||
<property name="src.desktop.build.dir" value="${desktop.build.dir}/src" />
|
||||
<property name="classes.desktop.build.dir" value="${desktop.build.dir}/classes" />
|
||||
<property name="desktop.dist.suffix" value="-desktop" />
|
||||
<property name="desktop.dist.filename" value="${jar-base-name}${desktop.dist.suffix}${jar-suffix}.jar" />
|
||||
<property name="desktop.dist.jar.file" value="${dist.dir}/desktop-lib/${desktop.dist.filename}" />
|
||||
<property name="desktop.src.dist.filename" value="${jar-base-name}${desktop.dist.suffix}${jar-suffix}.src.zip" />
|
||||
<path id="desktop.source.path">
|
||||
<fileset dir="${desktop.src.dir}"/>
|
||||
<fileset dir="${src.dir}"/>
|
||||
</path>
|
||||
|
||||
|
||||
|
||||
<!-- desktop build -->
|
||||
<target name="build-desktop">
|
||||
<!-- copy source -->
|
||||
<mkdir dir="${src.desktop.build.dir}" />
|
||||
<copy todir="${src.desktop.build.dir}">
|
||||
<path refid="desktop.source.path" />
|
||||
</copy>
|
||||
<zip destfile="${dist.dir}/desktop-lib/${desktop.src.dist.filename}" basedir="${src.desktop.build.dir}"/>
|
||||
|
||||
|
||||
<!-- compile source -->
|
||||
<mkdir dir="${classes.desktop.build.dir}" />
|
||||
<javac target="1.6" source="1.6" srcdir="${src.desktop.build.dir}" destdir="${classes.desktop.build.dir}" includeAntRuntime="false" >
|
||||
<compilerarg value="-Xlint"/>
|
||||
<compilerarg line="-Xlint:-serial"/>
|
||||
<compilerarg line="-Xlint:-rawtypes"/>
|
||||
</javac>
|
||||
|
||||
|
||||
<!-- build desktop jar -->
|
||||
<jar destfile="${desktop.dist.jar.file}" basedir="${classes.desktop.build.dir}" >
|
||||
<manifest>
|
||||
<attribute name="Build-Number" value="${BUILD_NUMBER}"/>
|
||||
<attribute name="Built-On" value="${BUILD_ID}"/>
|
||||
<attribute name="Built-From" value="SVN r${SVN_REVISION}"/>
|
||||
<attribute name="Build-Type" value="${BUILD_TYPE}"/>
|
||||
<attribute name="Build-Target" value="Desktop"/>
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
18
networktables/java/ant/javadoc.xml
Normal file
18
networktables/java/ant/javadoc.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
|
||||
<project name="Network_Tables_2.0 Javadoc">
|
||||
|
||||
<!-- javadoc build properties -->
|
||||
<property name="javadoc.dir" value="${desktop.build.dir}/javadoc" />
|
||||
<target name="javadoc">
|
||||
<mkdir dir="${javadoc.dir}" />
|
||||
<javadoc sourcepath="${src.dir}" destdir="${javadoc.dir}" author="true" version="true" use="true" windowtitle="Network Tables 2.0">
|
||||
<doctitle>
|
||||
<![CDATA[
|
||||
<h1>Network Tables 2.0</h1>
|
||||
]]>
|
||||
</doctitle>
|
||||
</javadoc>
|
||||
<zip destfile="${dist.dir}/desktop-lib/networktables-desktop.javadoc.zip" basedir="${javadoc.dir}" />
|
||||
</target>
|
||||
</project>
|
||||
47
networktables/java/ant/test.xml
Normal file
47
networktables/java/ant/test.xml
Normal file
@@ -0,0 +1,47 @@
|
||||
<project name="Network_Tables_2.0 Test">
|
||||
|
||||
<!-- test build properties -->
|
||||
<property name="test.build.dir" value="${build.dir}/test" />
|
||||
<property name="classes.test.dir" value="${test.build.dir}/classes" />
|
||||
|
||||
|
||||
<!-- test build -->
|
||||
<target name="compile-test" depends="build-crio,build-desktop">
|
||||
<mkdir dir="${classes.test.dir}" />
|
||||
|
||||
<javac target="1.6" source="1.6" srcdir="" destdir="${classes.test.dir}" includeAntRuntime="false" debug="true" >
|
||||
<src path="${desktop.src.dir}"/>
|
||||
<src path="${src.dir}"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<target name="test" depends="compile-test">
|
||||
<path path="${classes.test.dir}" id="tested-desktop-classpath"/>
|
||||
<ant antfile="${sunspot.home}/test.xml">
|
||||
<property name="sunspot.home" value="${sunspot.home}" />
|
||||
<property name="crio.test.alternate.networktables.archive" value="${dist.dir}/lib/${crio.dist.filename}" />
|
||||
<property name="test.build.dir" value="${test.build.dir}" />
|
||||
<reference refid="tested-desktop-classpath"/>
|
||||
<target name="test"/>
|
||||
</ant>
|
||||
</target>
|
||||
|
||||
<target name="test-desktop" depends="compile-test">
|
||||
<path path="${classes.test.dir}" id="tested-desktop-classpath"/>
|
||||
<ant antfile="${sunspot.home}/test.xml">
|
||||
<property name="sunspot.home" value="${sunspot.home}" />
|
||||
<property name="test.build.dir" value="${test.build.dir}" />
|
||||
<reference refid="tested-desktop-classpath"/>
|
||||
<target name="test-desktop"/>
|
||||
</ant>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="dist-tests">
|
||||
<mkdir dir="${dist.dir}/tests" />
|
||||
<zip destfile="${dist.dir}/tests/networktables.tests.zip">
|
||||
<fileset dir="." includes="desktop-test/**"/>
|
||||
<fileset dir="." includes="crio-test/**"/>
|
||||
</zip>
|
||||
</target>
|
||||
</project>
|
||||
90
networktables/java/build.xml
Normal file
90
networktables/java/build.xml
Normal file
@@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
|
||||
<!--
|
||||
Network Tables 2.0 Build script
|
||||
|
||||
by Mitchell Wills
|
||||
mwills@wpi.edu
|
||||
|
||||
|
||||
clean: clean
|
||||
all: build everything
|
||||
dist: just build the desktop and crio jars
|
||||
desktop: build the desktop jar
|
||||
crio: build the crio jar
|
||||
javadoc: build the javadoc
|
||||
test: run the junit test and instrument them with emma
|
||||
|
||||
-->
|
||||
|
||||
<project basedir="." name="Network_Tables_2.0" default="all">
|
||||
<property file="${user.home}/.sunspotfrc.properties"/>
|
||||
|
||||
|
||||
<target name="all" depends="clean,dist,test,javadoc" />
|
||||
<target name="dist" depends="clean,build-desktop,build-crio,dist-tests" />
|
||||
|
||||
<!-- input folders -->
|
||||
<property name="src.dir" value="src/common" />
|
||||
<property name="crio.src.dir" value="src/crio" />
|
||||
<property name="desktop.src.dir" value="src/desktop" />
|
||||
<property name="test.dir" value="test" />
|
||||
<property name="lib.dir" value="lib" />
|
||||
|
||||
<!-- output folders -->
|
||||
<property name="build.dir" value="build" />
|
||||
<property name="dist.dir" value="dist" />
|
||||
|
||||
<property name="jar-base-name" value="networktables" />
|
||||
<property name="jar-suffix" value="" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<import file="ant/crio.xml"/>
|
||||
<import file="ant/desktop.xml"/>
|
||||
<import file="ant/test.xml"/>
|
||||
<import file="ant/javadoc.xml"/>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- Import enviornment properties and set defaults -->
|
||||
<property environment="env"/>
|
||||
<condition property="BUILD_NUMBER" value="${env.BUILD_NUMBER}" else="LOCAL">
|
||||
<isset property="env.BUILD_NUMBER"/>
|
||||
</condition>
|
||||
<tstamp>
|
||||
<format property="BUILD_START" pattern="yyyy-MM-dd_hh-mm-ss" locale="en,US"/>
|
||||
</tstamp>
|
||||
<condition property="BUILD_ID" value="${env.BUILD_ID}" else="${BUILD_START}">
|
||||
<isset property="env.BUILD_ID"/>
|
||||
</condition>
|
||||
<condition property="SVN_REVISION" value="${env.SVN_REVISION}" else="LOCAL">
|
||||
<isset property="env.SVN_REVISION"/>
|
||||
</condition>
|
||||
<condition property="BUILD_TYPE" value="${env.BUILD_TYPE}" else="CUSTOM">
|
||||
<isset property="env.BUILD_TYPE"/>
|
||||
</condition>
|
||||
|
||||
|
||||
|
||||
<echo>Building NetworkTables 2.0</echo>
|
||||
<echo>Build Number: ${BUILD_NUMBER}</echo>
|
||||
<echo>Build Time: ${BUILD_ID}</echo>
|
||||
<echo>SVN Revision: ${SVN_REVISION}</echo>
|
||||
<echo>Build Type: ${BUILD_TYPE}</echo>
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- build targets -->
|
||||
<target name="clean">
|
||||
<delete dir="${build.dir}" />
|
||||
<delete dir="${dist.dir}" />
|
||||
</target>
|
||||
|
||||
|
||||
</project>
|
||||
174
networktables/java/dist-old/pom.xml
Normal file
174
networktables/java/dist-old/pom.xml
Normal file
@@ -0,0 +1,174 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<!-- Generated dist files for the sunspotfrcsdk directory -->
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>dist-old</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>WPILib Repository</id>
|
||||
<url>http://frcbuilder.wpi.edu:8348/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.8</version>
|
||||
<executions>
|
||||
|
||||
<!-- Fetch the dependencies needed to build the cpp.zip file. -->
|
||||
<execution>
|
||||
<id>fetch-sunspotfrcsdk-dependencies</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>copy</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<destFileName>networktables-crio.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>javadoc</type>
|
||||
<destFileName>networktables-crio-javadoc.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<classifier>sources</classifier>
|
||||
<destFileName>networktables-crio-sources.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
<destFileName>networktables-desktop.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/desktop-lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>javadoc</type>
|
||||
<destFileName>networktables-desktop-javadoc.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/desktop-lib</outputDirectory>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<classifier>sources</classifier>
|
||||
<destFileName>networktables-desktop-sources.jar</destFileName>
|
||||
<outputDirectory>${project.build.directory}/dist/desktop-lib</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
<overWriteReleases>false</overWriteReleases>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.11</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmock</groupId>
|
||||
<artifactId>jmock-junit4</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jmock</groupId>
|
||||
<artifactId>jmock-legacy</artifactId>
|
||||
<version>2.6.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Add fake dependencies to inform Maven of the correct
|
||||
order it should build projects in during a multi-module build.
|
||||
|
||||
This list should match the list in the invocation of
|
||||
maven-dependency-plugin:copy above.
|
||||
|
||||
It may be possible to avoid this duplication by using the
|
||||
maven-assembly-plugin instead.-->
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>javadoc</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTablesAzalea</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<classifier>sources</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<type>javadoc</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>edu.wpi.first.wpilib.networktables.java</groupId>
|
||||
<artifactId>NetworkTables</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<classifier>sources</classifier>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<properties>
|
||||
<local-repository>C:/Users/wpilibj-buildmaster/maven-repository</local-repository>
|
||||
</properties>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jenkins</id>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>myrepository</id>
|
||||
<url>file:${local-repository}</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
23
networktables/java/eclipse_project/.classpath
Normal file
23
networktables/java/eclipse_project/.classpath
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="src" path="desktop"/>
|
||||
<classpathentry kind="src" path="desktop-test"/>
|
||||
<classpathentry kind="var" path="JRE_LIB" sourcepath="JRE_SRC"/>
|
||||
<classpathentry kind="lib" path="lib/junit-dep-4.10.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/bsh-core-2.0b4.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/cglib-nodep-2.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/cglib-src-2.2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/hamcrest-core-1.3.0RC1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/hamcrest-library-1.3.0RC1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/hamcrest-unit-test-1.3.0RC1.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/jmock-2.6.0-RC2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/jmock-junit3-2.6.0-RC2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/jmock-junit4-2.6.0-RC2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/jmock-legacy-2.6.0-RC2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/jmock-script-2.6.0-RC2.jar"/>
|
||||
<classpathentry kind="lib" path="lib/jmock/objenesis-1.0.jar"/>
|
||||
<classpathentry kind="lib" path="C:/Users/Mitchell/sunspotfrcsdk/lib/squawk.jar"/>
|
||||
<classpathentry kind="lib" path="C:/Users/Mitchell/sunspotfrcsdk-dev/desktop-test-lib/sunit-runner.jar"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
||||
59
networktables/java/eclipse_project/.project
Normal file
59
networktables/java/eclipse_project/.project
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Network_Tables_2.0</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
<linkedResources>
|
||||
<link>
|
||||
<name>build.xml</name>
|
||||
<type>1</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/build.xml</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>classes</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/build/desktop/classes</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>crio</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/src/crio</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>crio-test</name>
|
||||
<type>2</type>
|
||||
<location>D:/Projects/NetworkTables2.0/trunk/java/crio-test</location>
|
||||
</link>
|
||||
<link>
|
||||
<name>desktop</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/src/desktop</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>desktop-test</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/desktop-test</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>lib</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/lib</locationURI>
|
||||
</link>
|
||||
<link>
|
||||
<name>src</name>
|
||||
<type>2</type>
|
||||
<locationURI>$%7BPARENT-1-PROJECT_LOC%7D/src/common</locationURI>
|
||||
</link>
|
||||
</linkedResources>
|
||||
</projectDescription>
|
||||
BIN
networktables/java/lib/jacocoant.jar
Normal file
BIN
networktables/java/lib/jacocoant.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/bsh-core-2.0b4.jar
Normal file
BIN
networktables/java/lib/jmock/bsh-core-2.0b4.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/cglib-nodep-2.2.jar
Normal file
BIN
networktables/java/lib/jmock/cglib-nodep-2.2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/cglib-src-2.2.jar
Normal file
BIN
networktables/java/lib/jmock/cglib-src-2.2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/hamcrest-core-1.3.0RC1.jar
Normal file
BIN
networktables/java/lib/jmock/hamcrest-core-1.3.0RC1.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/hamcrest-library-1.3.0RC1.jar
Normal file
BIN
networktables/java/lib/jmock/hamcrest-library-1.3.0RC1.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/hamcrest-unit-test-1.3.0RC1.jar
Normal file
BIN
networktables/java/lib/jmock/hamcrest-unit-test-1.3.0RC1.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/jmock-2.6.0-RC2.jar
Normal file
BIN
networktables/java/lib/jmock/jmock-2.6.0-RC2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/jmock-junit3-2.6.0-RC2.jar
Normal file
BIN
networktables/java/lib/jmock/jmock-junit3-2.6.0-RC2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/jmock-junit4-2.6.0-RC2.jar
Normal file
BIN
networktables/java/lib/jmock/jmock-junit4-2.6.0-RC2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/jmock-legacy-2.6.0-RC2.jar
Normal file
BIN
networktables/java/lib/jmock/jmock-legacy-2.6.0-RC2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/jmock-script-2.6.0-RC2.jar
Normal file
BIN
networktables/java/lib/jmock/jmock-script-2.6.0-RC2.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/jmock/objenesis-1.0.jar
Normal file
BIN
networktables/java/lib/jmock/objenesis-1.0.jar
Normal file
Binary file not shown.
BIN
networktables/java/lib/junit-dep-4.10.jar
Normal file
BIN
networktables/java/lib/junit-dep-4.10.jar
Normal file
Binary file not shown.
141
networktables/java/nbproject/project.xml
Normal file
141
networktables/java/nbproject/project.xml
Normal file
@@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://www.netbeans.org/ns/project/1">
|
||||
<type>org.netbeans.modules.ant.freeform</type>
|
||||
<configuration>
|
||||
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
|
||||
<name>Network_Tables_2.0</name>
|
||||
</general-data>
|
||||
<general-data xmlns="http://www.netbeans.org/ns/freeform-project/2">
|
||||
<!-- Do not use Project Properties customizer when editing this file manually. -->
|
||||
<name>Network_Tables_2.0</name>
|
||||
<properties>
|
||||
<property-file>${user.home}/.sunspotfrc.properties</property-file>
|
||||
<property-file>build.properties</property-file>
|
||||
<property-file>${sunspot.home}/test-classpath.properties</property-file>
|
||||
<property-file>${sunspot.home}/default.properties</property-file>
|
||||
</properties>
|
||||
<folders>
|
||||
<source-folder>
|
||||
<label>src\desktop</label>
|
||||
<type>java</type>
|
||||
<location>src/desktop</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>crio-test</label>
|
||||
<type>java</type>
|
||||
<location>crio-test</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>desktop-test</label>
|
||||
<type>java</type>
|
||||
<location>desktop-test</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>src\crio</label>
|
||||
<type>java</type>
|
||||
<location>src/crio</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>src\common</label>
|
||||
<type>java</type>
|
||||
<location>src/common</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
<source-folder>
|
||||
<label>Network_Tables_2.0</label>
|
||||
<location>.</location>
|
||||
<encoding>windows-1252</encoding>
|
||||
</source-folder>
|
||||
</folders>
|
||||
<ide-actions>
|
||||
<action name="run">
|
||||
<target>all</target>
|
||||
</action>
|
||||
<action name="build">
|
||||
<target>dist</target>
|
||||
</action>
|
||||
<action name="clean">
|
||||
<target>clean</target>
|
||||
</action>
|
||||
<action name="test">
|
||||
<target>test-desktop</target>
|
||||
</action>
|
||||
<action name="rebuild">
|
||||
<target>clean</target>
|
||||
<target>dist</target>
|
||||
</action>
|
||||
</ide-actions>
|
||||
<view>
|
||||
<items>
|
||||
<source-folder style="packages">
|
||||
<label>src\desktop</label>
|
||||
<location>src/desktop</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>crio-test</label>
|
||||
<location>crio-test</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>desktop-test</label>
|
||||
<location>desktop-test</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>src\crio</label>
|
||||
<location>src/crio</location>
|
||||
</source-folder>
|
||||
<source-folder style="packages">
|
||||
<label>src\common</label>
|
||||
<location>src/common</location>
|
||||
</source-folder>
|
||||
<source-file>
|
||||
<location>build.xml</location>
|
||||
</source-file>
|
||||
</items>
|
||||
<context-menu>
|
||||
<ide-action name="build"/>
|
||||
<ide-action name="rebuild"/>
|
||||
<ide-action name="clean"/>
|
||||
<ide-action name="javadoc"/>
|
||||
<ide-action name="test"/>
|
||||
</context-menu>
|
||||
</view>
|
||||
<subprojects/>
|
||||
</general-data>
|
||||
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
|
||||
<compilation-unit>
|
||||
<package-root>src/desktop</package-root>
|
||||
<classpath mode="compile">src/common</classpath>
|
||||
<source-level>1.3</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>crio-test</package-root>
|
||||
<unit-tests/>
|
||||
<classpath mode="boot">${sunspot.home}/lib/squawk.jar</classpath>
|
||||
<classpath mode="compile">${sunit.server.jar};src/crio;src/common</classpath>
|
||||
<source-level>1.3</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>desktop-test</package-root>
|
||||
<unit-tests/>
|
||||
<classpath mode="compile">${jmock.classpath};${junit.classpath};${sunit.runner.jar};src/desktop;src/common</classpath>
|
||||
<built-to>build\test\junit</built-to>
|
||||
<source-level>1.5</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>src/crio</package-root>
|
||||
<classpath mode="boot">${sunspot.home}/lib/squawk.jar</classpath>
|
||||
<classpath mode="compile">src/common</classpath>
|
||||
<source-level>1.3</source-level>
|
||||
</compilation-unit>
|
||||
<compilation-unit>
|
||||
<package-root>src/common</package-root>
|
||||
<classpath mode="compile">src/desktop</classpath>
|
||||
<source-level>1.3</source-level>
|
||||
</compilation-unit>
|
||||
</java-data>
|
||||
</configuration>
|
||||
</project>
|
||||
52
networktables/java/pom.xml
Normal file
52
networktables/java/pom.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>edu.wpi.first.wpilib.networktables</groupId>
|
||||
<artifactId>java</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<local-repository>C:/Users/wpilibj-buildmaster/maven-repository</local-repository>
|
||||
</properties>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jenkins</id>
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>myrepository</id>
|
||||
<url>file:${local-repository}</url>
|
||||
</repository>
|
||||
</distributionManagement>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>desktop</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>Athena</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>athena</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>Athena</module>
|
||||
</modules>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>azalea</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<modules>
|
||||
<module>Azalea</module>
|
||||
<module>dist-old</module>
|
||||
</modules>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
@@ -0,0 +1,568 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.util.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.util.List;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Fredric
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
|
||||
public class NetworkTable implements ITable, IRemote {
|
||||
private static final NTThreadManager threadManager = new DefaultThreadManager();
|
||||
|
||||
/**
|
||||
* The path separator for sub-tables and keys
|
||||
*
|
||||
*/
|
||||
public static final char PATH_SEPARATOR = '/';
|
||||
/**
|
||||
* The default port that network tables operates on
|
||||
*/
|
||||
public static final int DEFAULT_PORT = 1735;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static NetworkTableProvider staticProvider = null;
|
||||
|
||||
private static NetworkTableMode mode = NetworkTableMode.Server;
|
||||
private static int port = DEFAULT_PORT;
|
||||
private static String ipAddress = null;
|
||||
|
||||
private synchronized static void checkInit(){
|
||||
if(staticProvider!=null)
|
||||
throw new IllegalStateException("Network tables has already been initialized");
|
||||
}
|
||||
/**
|
||||
* @throws IOException
|
||||
*/
|
||||
public synchronized static void initialize() throws IOException {
|
||||
checkInit();
|
||||
staticProvider = new NetworkTableProvider(mode.createNode(ipAddress, port, threadManager));
|
||||
}
|
||||
|
||||
/**
|
||||
* set the table provider for static network tables methods
|
||||
* This must be called before initalize or getTable
|
||||
*/
|
||||
public synchronized static void setTableProvider(NetworkTableProvider provider) {
|
||||
checkInit();
|
||||
staticProvider = provider;
|
||||
}
|
||||
/**
|
||||
* set that network tables should be a server
|
||||
* This must be called before initalize or getTable
|
||||
*/
|
||||
public synchronized static void setServerMode(){
|
||||
checkInit();
|
||||
mode = NetworkTableMode.Server;
|
||||
}
|
||||
/**
|
||||
* set that network tables should be a client
|
||||
* This must be called before initalize or getTable
|
||||
*/
|
||||
public synchronized static void setClientMode(){
|
||||
checkInit();
|
||||
mode = NetworkTableMode.Client;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the team the robot is configured for (this will set the ip address that network tables will connect to in client mode)
|
||||
* This must be called before initalize or getTable
|
||||
* @param team the team number
|
||||
*/
|
||||
public synchronized static void setTeam(int team){
|
||||
setIPAddress("10." + (team / 100) + "." + (team % 100) + ".2");
|
||||
}
|
||||
/**
|
||||
* @param address the adress that network tables will connect to in client mode
|
||||
*/
|
||||
public synchronized static void setIPAddress(final String address){
|
||||
checkInit();
|
||||
ipAddress = address;
|
||||
}
|
||||
/**
|
||||
* Gets the table with the specified key. If the table does not exist, a new table will be created.<br>
|
||||
* This will automatically initialize network tables if it has not been already
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the network table requested
|
||||
*/
|
||||
public synchronized static NetworkTable getTable(String key) {
|
||||
if(staticProvider==null)
|
||||
try {
|
||||
initialize();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("NetworkTable could not be initialized: "+e+": "+e.getMessage());
|
||||
}
|
||||
return (NetworkTable)staticProvider.getTable(PATH_SEPARATOR+key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private final String path;
|
||||
private final EntryCache entryCache;
|
||||
private final NetworkTableKeyCache absoluteKeyCache;
|
||||
private final NetworkTableProvider provider;
|
||||
private final NetworkTableNode node;
|
||||
|
||||
NetworkTable(String path, NetworkTableProvider provider) {
|
||||
this.path = path;
|
||||
entryCache = new EntryCache(path);
|
||||
absoluteKeyCache = new NetworkTableKeyCache(path);
|
||||
this.provider = provider;
|
||||
node = provider.getNode();
|
||||
}
|
||||
public String toString(){
|
||||
return "NetworkTable: "+path;
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return node.isConnected();
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return node.isServer();
|
||||
}
|
||||
|
||||
|
||||
static class NetworkTableKeyCache extends StringCache{
|
||||
private final String path;
|
||||
|
||||
public NetworkTableKeyCache(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public String calc(String key) {
|
||||
return path + PATH_SEPARATOR + key;
|
||||
}
|
||||
}
|
||||
class EntryCache {
|
||||
private final Hashtable cache = new Hashtable();
|
||||
private final String path;
|
||||
|
||||
public EntryCache(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
public NetworkTableEntry get(final String key){
|
||||
NetworkTableEntry cachedValue = (NetworkTableEntry)cache.get(key);
|
||||
if(cachedValue==null){
|
||||
cachedValue = node.getEntryStore().getEntry(absoluteKeyCache.get(key));
|
||||
if(cachedValue!=null)
|
||||
cache.put(key, cachedValue);
|
||||
}
|
||||
return cachedValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final Hashtable connectionListenerMap = new Hashtable();
|
||||
public void addConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify) {
|
||||
NetworkTableConnectionListenerAdapter adapter = (NetworkTableConnectionListenerAdapter)connectionListenerMap.get(listener);
|
||||
if(adapter!=null)
|
||||
throw new IllegalStateException("Cannot add the same listener twice");
|
||||
adapter = new NetworkTableConnectionListenerAdapter(this, listener);
|
||||
connectionListenerMap.put(listener, adapter);
|
||||
node.addConnectionListener(adapter, immediateNotify);
|
||||
}
|
||||
|
||||
public void removeConnectionListener(IRemoteConnectionListener listener) {
|
||||
NetworkTableConnectionListenerAdapter adapter = (NetworkTableConnectionListenerAdapter)connectionListenerMap.get(listener);
|
||||
if(adapter!=null)
|
||||
node.removeConnectionListener(adapter);
|
||||
}
|
||||
|
||||
|
||||
public void addTableListener(ITableListener listener) {
|
||||
addTableListener(listener, false);
|
||||
}
|
||||
|
||||
private final Hashtable listenerMap = new Hashtable();
|
||||
public void addTableListener(ITableListener listener, boolean immediateNotify) {
|
||||
List adapters = (List)listenerMap.get(listener);
|
||||
if(adapters==null){
|
||||
adapters = new List();
|
||||
listenerMap.put(listener, adapters);
|
||||
}
|
||||
NetworkTableListenerAdapter adapter = new NetworkTableListenerAdapter(path+PATH_SEPARATOR, this, listener);
|
||||
adapters.add(adapter);
|
||||
node.addTableListener(adapter, immediateNotify);
|
||||
}
|
||||
public void addTableListener(String key, ITableListener listener, boolean immediateNotify) {
|
||||
List adapters = (List)listenerMap.get(listener);
|
||||
if(adapters==null){
|
||||
adapters = new List();
|
||||
listenerMap.put(listener, adapters);
|
||||
}
|
||||
NetworkTableKeyListenerAdapter adapter = new NetworkTableKeyListenerAdapter(key, absoluteKeyCache.get(key), this, listener);
|
||||
adapters.add(adapter);
|
||||
node.addTableListener(adapter, immediateNotify);
|
||||
}
|
||||
public void addSubTableListener(final ITableListener listener) {
|
||||
List adapters = (List)listenerMap.get(listener);
|
||||
if(adapters==null){
|
||||
adapters = new List();
|
||||
listenerMap.put(listener, adapters);
|
||||
}
|
||||
NetworkTableSubListenerAdapter adapter = new NetworkTableSubListenerAdapter(path, this, listener);
|
||||
adapters.add(adapter);
|
||||
node.addTableListener(adapter, true);
|
||||
}
|
||||
|
||||
public void removeTableListener(ITableListener listener) {
|
||||
List adapters = (List)listenerMap.get(listener);
|
||||
if(adapters!=null){
|
||||
for(int i = 0; i<adapters.size(); ++i)
|
||||
node.removeTableListener((ITableListener) adapters.get(i));
|
||||
adapters.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized NetworkTableEntry getEntry(String key){
|
||||
return entryCache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table at the specified key. If there is no table at the
|
||||
* specified key, it will create a new table
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the networktable to be returned
|
||||
*/
|
||||
public synchronized ITable getSubTable(String key) {
|
||||
return (NetworkTable)provider.getTable(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the table and tells if it contains the specified key
|
||||
*
|
||||
* @param key
|
||||
* the key to be checked
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
return node.containsKey(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
public boolean containsSubTable(String key){
|
||||
String subtablePrefix = absoluteKeyCache.get(key)+PATH_SEPARATOR;
|
||||
List keys = node.getEntryStore().keys();
|
||||
for(int i = 0; i<keys.size(); ++i){
|
||||
if(((String)keys.get(i)).startsWith(subtablePrefix))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table. The key can
|
||||
* not be null. The value can be retrieved by calling the get method with a
|
||||
* key that is equal to the original key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value
|
||||
*/
|
||||
public void putNumber(String key, double value) {
|
||||
putValue(key, new Double(value));//TODO cache doubles
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to.
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the key
|
||||
* @throws TableKeyNotDefinedException
|
||||
* if the specified key is null
|
||||
*/
|
||||
public double getNumber(String key) throws TableKeyNotDefinedException {
|
||||
return node.getDouble(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to. If the key is null, it will return
|
||||
* the default value
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @param defaultValue
|
||||
* the default value if the key is null
|
||||
* @return the key
|
||||
*/
|
||||
public double getNumber(String key, double defaultValue) {
|
||||
try {
|
||||
return node.getDouble(absoluteKeyCache.get(key));
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table. The key can
|
||||
* not be null. The value can be retrieved by calling the get method with a
|
||||
* key that is equal to the original key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value
|
||||
*/
|
||||
public void putString(String key, String value) {
|
||||
putValue(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to.
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the key
|
||||
* @throws TableKeyNotDefinedException
|
||||
* if the specified key is null
|
||||
*/
|
||||
public String getString(String key) throws TableKeyNotDefinedException {
|
||||
return node.getString(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to. If the key is null, it will return
|
||||
* the default value
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @param defaultValue
|
||||
* the default value if the key is null
|
||||
* @return the key
|
||||
*/
|
||||
public String getString(String key, String defaultValue) {
|
||||
try {
|
||||
return node.getString(absoluteKeyCache.get(key));
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table. The key can
|
||||
* not be null. The value can be retrieved by calling the get method with a
|
||||
* key that is equal to the original key.
|
||||
*
|
||||
* @param key
|
||||
* the key
|
||||
* @param value
|
||||
* the value
|
||||
*/
|
||||
public void putBoolean(String key, boolean value) {
|
||||
putValue(key, value?Boolean.TRUE:Boolean.FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to.
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the key
|
||||
* @throws TableKeyNotDefinedException
|
||||
* if the specified key is null
|
||||
*/
|
||||
public boolean getBoolean(String key) throws TableKeyNotDefinedException {
|
||||
return node.getBoolean(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to. If the key is null, it will return
|
||||
* the default value
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @param defaultValue
|
||||
* the default value if the key is null
|
||||
* @return the key
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
try {
|
||||
return node.getBoolean(absoluteKeyCache.get(key));
|
||||
} catch (TableKeyNotDefinedException e) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void retrieveValue(String key, Object externalValue) {
|
||||
node.retrieveValue(absoluteKeyCache.get(key), externalValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the specified key to the specified value in this table. The key can
|
||||
* not be null. The value can be retrieved by calling the get method with a
|
||||
* key that is equal to the original key.
|
||||
*
|
||||
* @param key the key name
|
||||
* @param value the value to be put
|
||||
*/
|
||||
public void putValue(String key, Object value){
|
||||
NetworkTableEntry entry = entryCache.get(key);
|
||||
if(entry!=null)
|
||||
node.putValue(entry, value);
|
||||
else
|
||||
node.putValue(absoluteKeyCache.get(key), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to.
|
||||
* NOTE: If the value is a double, it will return a Double object,
|
||||
* not a primitive. To get the primitive, use getDouble
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @return the key
|
||||
* @throws TableKeyNotDefinedException
|
||||
* if the specified key is null
|
||||
*/
|
||||
public Object getValue(String key) throws TableKeyNotDefinedException {
|
||||
return node.getValue(absoluteKeyCache.get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that the name maps to. If the key is null, it will return
|
||||
* the default value
|
||||
* NOTE: If the value is a double, it will return a Double object,
|
||||
* not a primitive. To get the primitive, use getDouble
|
||||
*
|
||||
* @param key
|
||||
* the key name
|
||||
* @param defaultValue
|
||||
* the default value if the key is null
|
||||
* @return the key
|
||||
*/
|
||||
public Object getValue(String key, Object defaultValue) {
|
||||
try {
|
||||
return node.getValue(absoluteKeyCache.get(key));
|
||||
} catch(TableKeyNotDefinedException e){
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Depricated Methods
|
||||
*/
|
||||
/**
|
||||
* @deprecated
|
||||
* Maps the specified key to the specified value in this table.
|
||||
* The key can not be null.
|
||||
* The value can be retrieved by calling the get method with a key that is equal to the original key.
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws IllegalArgumentException if key is null
|
||||
*/
|
||||
public void putInt(String key, int value) {
|
||||
putNumber(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @return the value
|
||||
* @throws TableKeyNotDefinedException if there is no value mapped to by the key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not an int
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
*/
|
||||
public int getInt(String key) throws TableKeyNotDefinedException{
|
||||
return (int) getNumber(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @param defaultValue the value returned if the key is undefined
|
||||
* @return the value
|
||||
* @throws NetworkTableKeyNotDefined if there is no value mapped to by the key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not an int
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
*/
|
||||
public int getInt(String key, int defaultValue) throws TableKeyNotDefinedException{
|
||||
try {
|
||||
return (int) getNumber(key);
|
||||
} catch (NoSuchElementException ex) {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Maps the specified key to the specified value in this table.
|
||||
* The key can not be null.
|
||||
* The value can be retrieved by calling the get method with a key that is equal to the original key.
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @throws IllegalArgumentException if key is null
|
||||
*/
|
||||
public void putDouble(String key, double value) {
|
||||
putNumber(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @return the value
|
||||
* @throws NoSuchEleNetworkTableKeyNotDefinedmentException if there is no value mapped to by the key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not a double
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
*/
|
||||
public double getDouble(String key) throws TableKeyNotDefinedException{
|
||||
return getNumber(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Returns the value at the specified key.
|
||||
* @param key the key
|
||||
* @param defaultValue the value returned if the key is undefined
|
||||
* @return the value
|
||||
* @throws NoSuchEleNetworkTableKeyNotDefinedmentException if there is no value mapped to by the key
|
||||
* @throws IllegalArgumentException if the value mapped to by the key is not a double
|
||||
* @throws IllegalArgumentException if the key is null
|
||||
*/
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
return getNumber(key, defaultValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* An adapter that changes the source of a connection event
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableConnectionListenerAdapter implements IRemoteConnectionListener {
|
||||
|
||||
private final IRemoteConnectionListener targetListener;
|
||||
private final IRemote targetSource;
|
||||
|
||||
/**
|
||||
* @param targetSource the source where the event will appear to come from
|
||||
* @param targetListener the listener where events will be forwarded
|
||||
*/
|
||||
public NetworkTableConnectionListenerAdapter(IRemote targetSource, IRemoteConnectionListener targetListener){
|
||||
this.targetSource = targetSource;
|
||||
this.targetListener = targetListener;
|
||||
}
|
||||
|
||||
public void connected(IRemote remote) {
|
||||
targetListener.connected(targetSource);
|
||||
}
|
||||
|
||||
public void disconnected(IRemote remote) {
|
||||
targetListener.disconnected(targetSource);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* An adapter that is used to filter value change notifications for a specific key
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableKeyListenerAdapter implements ITableListener {
|
||||
|
||||
private final ITableListener targetListener;
|
||||
private final NetworkTable targetSource;
|
||||
private final String relativeKey;
|
||||
private final String fullKey;
|
||||
|
||||
/**
|
||||
* Create a new adapter
|
||||
* @param relativeKey the name of the key relative to the table (this is what the listener will receiver as the key)
|
||||
* @param fullKey the full name of the key in the {@link NetworkTableNode}
|
||||
* @param targetSource the source that events passed to the target listener will appear to come from
|
||||
* @param targetListener the listener where events are forwarded to
|
||||
*/
|
||||
public NetworkTableKeyListenerAdapter(String relativeKey, String fullKey, NetworkTable targetSource, ITableListener targetListener){
|
||||
this.relativeKey = relativeKey;
|
||||
this.fullKey = fullKey;
|
||||
this.targetSource = targetSource;
|
||||
this.targetListener = targetListener;
|
||||
}
|
||||
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew) {
|
||||
if(key.equals(fullKey)){
|
||||
targetListener.valueChanged(targetSource, relativeKey, value, isNew);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* An exception throw when the lookup a a key-value fails in a {@link NetworkTable}
|
||||
*
|
||||
* @deprecated to provide backwards compatability for new api
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableKeyNotDefined extends NoSuchElementException {
|
||||
|
||||
/**
|
||||
* @param key the key that was not defined in the table
|
||||
*/
|
||||
public NetworkTableKeyNotDefined(String key) {
|
||||
super("Unkown Table Key: "+key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* An adapter that is used to filter value change notifications and make the path relative to the NetworkTable
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableListenerAdapter implements ITableListener {
|
||||
|
||||
private final ITableListener targetListener;
|
||||
private final ITable targetSource;
|
||||
private final String prefix;
|
||||
|
||||
/**
|
||||
* Create a new adapter
|
||||
* @param prefix the prefix that will be filtered/removed from the beginning of the key
|
||||
* @param targetSource the source that events passed to the target listener will appear to come from
|
||||
* @param targetListener the listener where events are forwarded to
|
||||
*/
|
||||
public NetworkTableListenerAdapter(String prefix, ITable targetSource, ITableListener targetListener){
|
||||
this.prefix = prefix;
|
||||
this.targetSource = targetSource;
|
||||
this.targetListener = targetListener;
|
||||
}
|
||||
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew) {//TODO use string cache
|
||||
if(key.startsWith(prefix)){
|
||||
String relativeKey = key.substring(prefix.length());
|
||||
if(contains(relativeKey, NetworkTable.PATH_SEPARATOR))
|
||||
return;
|
||||
targetListener.valueChanged(targetSource, relativeKey, value, isNew);
|
||||
}
|
||||
}
|
||||
private static boolean contains(String source, char target){
|
||||
for(int i = 0; i<source.length(); ++i)
|
||||
if(source.charAt(i)==target)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.client.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.server.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* Represents a different modes that network tables can be configured in
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public abstract class NetworkTableMode {
|
||||
|
||||
/**
|
||||
* A mode where Network tables will be a server on the specified port
|
||||
*/
|
||||
public static final NetworkTableMode Server = new NetworkTableMode("Server"){
|
||||
public NetworkTableNode createNode(String ipAddress, int port, NTThreadManager threadManager) throws IOException {
|
||||
IOStreamProvider streamProvider = SocketStreams.newStreamProvider(port);
|
||||
return new NetworkTableServer(streamProvider, new NetworkTableEntryTypeManager(), threadManager);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* A mode where network tables will be a client which connects to the specified host and port
|
||||
*/
|
||||
public static final NetworkTableMode Client = new NetworkTableMode("Client"){
|
||||
public NetworkTableNode createNode(String ipAddress, int port, NTThreadManager threadManager) throws IOException {
|
||||
if(ipAddress==null)
|
||||
throw new IllegalArgumentException("IP address cannot be null when in client mode");
|
||||
IOStreamFactory streamFactory = SocketStreams.newStreamFactory(ipAddress, port);
|
||||
NetworkTableClient client = new NetworkTableClient(streamFactory, new NetworkTableEntryTypeManager(), threadManager);
|
||||
client.reconnect();
|
||||
return client;
|
||||
}
|
||||
};
|
||||
private String name;
|
||||
private NetworkTableMode(String name){
|
||||
this.name = name;
|
||||
}
|
||||
public String toString(){
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ipAddress the IP address configured by the user
|
||||
* @param port the port configured by the user
|
||||
* @param threadManager the thread manager that should be used for threads in the node
|
||||
* @return a new node that can back a network table
|
||||
* @throws IOException
|
||||
*/
|
||||
abstract NetworkTableNode createNode(String ipAddress, int port, NTThreadManager threadManager) throws IOException;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* Provides a {@link NetworkTable} for a given {@link NetworkTableNode}
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableProvider implements ITableProvider{
|
||||
private final NetworkTableNode node;
|
||||
private final Hashtable tables = new Hashtable();
|
||||
|
||||
/**
|
||||
* Create a new NetworkTableProvider for a given NetworkTableNode
|
||||
* @param node the node that handles the actual network table
|
||||
*/
|
||||
public NetworkTableProvider(NetworkTableNode node){
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
public ITable getRootTable(){
|
||||
return getTable("");
|
||||
}
|
||||
|
||||
public ITable getTable(String key) {
|
||||
if (tables.containsKey(key)) {
|
||||
return (NetworkTable) tables.get(key);
|
||||
} else {
|
||||
NetworkTable table = new NetworkTable(key, this);
|
||||
tables.put(key, table);
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the Network Table node that backs the Tables returned by this provider
|
||||
*/
|
||||
public NetworkTableNode getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* close the backing network table node
|
||||
*/
|
||||
public void close() {
|
||||
node.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package edu.wpi.first.wpilibj.networktables;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.util.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* An adapter that is used to filter sub table change notifications and make the path relative to the NetworkTable
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableSubListenerAdapter implements ITableListener {
|
||||
|
||||
private final ITableListener targetListener;
|
||||
private final NetworkTable targetSource;
|
||||
private final String prefix;
|
||||
|
||||
private final Set notifiedTables = new Set();
|
||||
|
||||
/**
|
||||
* Create a new adapter
|
||||
* @param prefix the prefix of the current table
|
||||
* @param targetSource the source that events passed to the target listener will appear to come from
|
||||
* @param targetListener the listener where events are forwarded to
|
||||
*/
|
||||
public NetworkTableSubListenerAdapter(String prefix, NetworkTable targetSource, ITableListener targetListener){
|
||||
this.prefix = prefix;
|
||||
this.targetSource = targetSource;
|
||||
this.targetListener = targetListener;
|
||||
}
|
||||
|
||||
public void valueChanged(ITable source, String key, Object value, boolean isNew) {//TODO use string cache
|
||||
if(key.startsWith(prefix)){
|
||||
String relativeKey = key.substring(prefix.length()+1);
|
||||
int endSubTable = -1;//TODO implement sub table listening better
|
||||
for(int i = 0; i<relativeKey.length(); ++i){
|
||||
if(relativeKey.charAt(i)==NetworkTable.PATH_SEPARATOR){//is sub table
|
||||
endSubTable = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(endSubTable!=-1){
|
||||
String subTableKey = relativeKey.substring(0, endSubTable);
|
||||
if(!notifiedTables.contains(subTableKey)){
|
||||
notifiedTables.add(subTableKey);
|
||||
targetListener.valueChanged(targetSource, subTableKey, targetSource.getSubTable(subTableKey), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.util.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
|
||||
/**
|
||||
* An entry store that handles storing entries and applying transactions
|
||||
*
|
||||
* @author mwills
|
||||
* @author Fredric
|
||||
*
|
||||
*/
|
||||
|
||||
public abstract class AbstractNetworkTableEntryStore implements IncomingEntryReceiver{
|
||||
protected final CharacterArrayMap idEntries = new CharacterArrayMap();
|
||||
protected final Hashtable namedEntries = new Hashtable();
|
||||
|
||||
protected final TableListenerManager listenerManager;
|
||||
|
||||
protected AbstractNetworkTableEntryStore(TableListenerManager listenerManager){
|
||||
this.listenerManager = listenerManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an entry based on it's id
|
||||
* @param entryId the id f the entry to look for
|
||||
* @return the entry or null if the entry does not exist
|
||||
*/
|
||||
public NetworkTableEntry getEntry(final char entryId){
|
||||
synchronized(this){
|
||||
return (NetworkTableEntry) idEntries.get(entryId);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get an entry based on it's name
|
||||
* @param name the name of the entry to look for
|
||||
* @return the entry or null if the entry does not exist
|
||||
*/
|
||||
public NetworkTableEntry getEntry(String name){
|
||||
synchronized(this){
|
||||
return (NetworkTableEntry) namedEntries.get(name);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get an entry based on it's name
|
||||
* @param name the name of the entry to look for
|
||||
* @return the entry or null if the entry does not exist
|
||||
*/
|
||||
public List keys(){
|
||||
synchronized(this){
|
||||
List entryKeys = new List();
|
||||
Enumeration e = namedEntries.keys();
|
||||
while(e.hasMoreElements())
|
||||
entryKeys.add(e.nextElement());
|
||||
return entryKeys;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all entries
|
||||
* NOTE: This method should not be used with applications which cache entries which would lead to unknown results
|
||||
* This method is for use in testing only
|
||||
*/
|
||||
public void clearEntries() {
|
||||
synchronized (this) {
|
||||
idEntries.clear();
|
||||
namedEntries.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clear the id's of all entries
|
||||
*/
|
||||
public void clearIds() {
|
||||
synchronized(this){
|
||||
idEntries.clear();
|
||||
Enumeration e = namedEntries.elements();
|
||||
while(e.hasMoreElements())
|
||||
((NetworkTableEntry)e.nextElement()).clearId();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected OutgoingEntryReceiver outgoingReceiver;
|
||||
protected OutgoingEntryReceiver incomingReceiver;
|
||||
public void setOutgoingReceiver(final OutgoingEntryReceiver receiver){
|
||||
outgoingReceiver = receiver;
|
||||
}
|
||||
public void setIncomingReceiver(OutgoingEntryReceiver receiver){
|
||||
incomingReceiver = receiver;
|
||||
}
|
||||
|
||||
protected abstract boolean addEntry(NetworkTableEntry entry);
|
||||
protected abstract boolean updateEntry(NetworkTableEntry entry, char sequenceNumber, Object value);
|
||||
|
||||
/**
|
||||
* Check if two objects are equal doing a deep equals of arrays
|
||||
* This method assumes that o1 and o2 are of the same type (if one is an object array the other one is also)
|
||||
* @param o1
|
||||
* @param o2
|
||||
*/
|
||||
private static boolean valuesEqual(Object o1, Object o2){
|
||||
if(o1 instanceof Object[]){
|
||||
Object[] a1 = (Object[])o1;
|
||||
Object[] a2 = (Object[])o2;
|
||||
if(a1.length!=a2.length)
|
||||
return false;
|
||||
for(int i = 0; i<a1.length; ++i)
|
||||
if(!valuesEqual(a1[i], a2[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
return o1!=null?o1.equals(o2):o2==null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the given value under the given name and queues it for
|
||||
* transmission to the server.
|
||||
*
|
||||
* @param name The name under which to store the given value.
|
||||
* @param type The type of the given value.
|
||||
* @param value The value to store.
|
||||
* @throws TableKeyExistsWithDifferentTypeException Thrown if an
|
||||
* entry already exists with the given name and is of a different type.
|
||||
*/
|
||||
public void putOutgoing(String name, NetworkTableEntryType type, Object value) throws TableKeyExistsWithDifferentTypeException{
|
||||
synchronized(this){
|
||||
NetworkTableEntry tableEntry = (NetworkTableEntry)namedEntries.get(name);
|
||||
if(tableEntry==null){
|
||||
//TODO validate type
|
||||
tableEntry = new NetworkTableEntry(name, type, value);
|
||||
if(addEntry(tableEntry)){
|
||||
tableEntry.fireListener(listenerManager);
|
||||
outgoingReceiver.offerOutgoingAssignment(tableEntry);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(tableEntry.getType().id != type.id)
|
||||
throw new edu.wpi.first.wpilibj.networktables2.TableKeyExistsWithDifferentTypeException(name, tableEntry.getType());
|
||||
if(!valuesEqual(value, tableEntry.getValue())){
|
||||
if(updateEntry(tableEntry, (char)(tableEntry.getSequenceNumber()+1), value)){
|
||||
outgoingReceiver.offerOutgoingUpdate(tableEntry);
|
||||
}
|
||||
tableEntry.fireListener(listenerManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void putOutgoing(NetworkTableEntry tableEntry, Object value){
|
||||
synchronized(this){
|
||||
//TODO Validate type
|
||||
if(!valuesEqual(value, tableEntry.getValue())){
|
||||
if(updateEntry(tableEntry, (char)(tableEntry.getSequenceNumber()+1), value)){
|
||||
outgoingReceiver.offerOutgoingUpdate(tableEntry);
|
||||
}
|
||||
tableEntry.fireListener(listenerManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void offerIncomingAssignment(NetworkTableEntry entry) {
|
||||
synchronized(this){
|
||||
NetworkTableEntry tableEntry = (NetworkTableEntry)namedEntries.get(entry.name);
|
||||
if(addEntry(entry)){
|
||||
if(tableEntry==null)
|
||||
tableEntry = entry;
|
||||
tableEntry.fireListener(listenerManager);
|
||||
incomingReceiver.offerOutgoingAssignment(tableEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void offerIncomingUpdate(NetworkTableEntry entry, char sequenceNumber, Object value) {
|
||||
synchronized(this){
|
||||
if(updateEntry(entry, sequenceNumber, value)){
|
||||
entry.fireListener(listenerManager);
|
||||
incomingReceiver.offerOutgoingUpdate(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called to say that a listener should notify the listener manager of all of the entries
|
||||
* @param listener
|
||||
* @param table
|
||||
*/
|
||||
public void notifyEntries(final ITable table, final ITableListener listener) {
|
||||
synchronized(this){
|
||||
Enumeration entryIterator = namedEntries.elements();
|
||||
while(entryIterator.hasMoreElements()){
|
||||
NetworkTableEntry entry = (NetworkTableEntry) entryIterator.nextElement();
|
||||
listener.valueChanged(table, entry.name, entry.getValue(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* An object that handles firing Table Listeners
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public interface TableListenerManager {
|
||||
/**
|
||||
* Called when the object should fire it's listeners
|
||||
* @param key
|
||||
* @param value
|
||||
* @param isNew
|
||||
*/
|
||||
void fireTableListeners(String key, Object value, boolean isNew);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
|
||||
|
||||
public interface FlushableOutgoingEntryReceiver extends OutgoingEntryReceiver{
|
||||
public void flush();
|
||||
|
||||
public void ensureAlive();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
|
||||
|
||||
public interface IncomingEntryReceiver {
|
||||
IncomingEntryReceiver NULL = new IncomingEntryReceiver() {
|
||||
public void offerIncomingUpdate(NetworkTableEntry entry, char entrySequenceNumber, Object value) {
|
||||
}
|
||||
public void offerIncomingAssignment(NetworkTableEntry entry) {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
public void offerIncomingAssignment(NetworkTableEntry entry);
|
||||
public void offerIncomingUpdate(NetworkTableEntry entry, char entrySequenceNumber, Object value);
|
||||
}
|
||||
@@ -0,0 +1,171 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.AbstractNetworkTableEntryStore.TableListenerManager;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/**
|
||||
* An entry in a network table
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public class NetworkTableEntry {
|
||||
/**
|
||||
* the id that represents that an id is unknown for an entry
|
||||
*/
|
||||
public static final char UNKNOWN_ID = (char)0xFFFF;
|
||||
|
||||
private char id;
|
||||
private char sequenceNumber;
|
||||
/**
|
||||
* the name of the entry
|
||||
*/
|
||||
public final String name;
|
||||
/**
|
||||
* the type of the entry
|
||||
*/
|
||||
private NetworkTableEntryType type;
|
||||
private Object value;
|
||||
private volatile boolean isNew = true;
|
||||
private volatile boolean isDirty = false;
|
||||
|
||||
/**
|
||||
* Create a new entry with the given name, type, value, an unknown id and a sequence number of 0
|
||||
* @param name
|
||||
* @param type
|
||||
* @param value
|
||||
*/
|
||||
public NetworkTableEntry(final String name, final NetworkTableEntryType type, final Object value){
|
||||
this(UNKNOWN_ID, name, (char)0, type, value);
|
||||
}
|
||||
/**
|
||||
* Create a new entry with the given id, name, sequence number, type and value
|
||||
* @param id
|
||||
* @param name
|
||||
* @param sequenceNumber
|
||||
* @param type
|
||||
* @param value
|
||||
*/
|
||||
public NetworkTableEntry(final char id, final String name, final char sequenceNumber, final NetworkTableEntryType type, final Object value){
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.sequenceNumber = sequenceNumber;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id of the entry
|
||||
*/
|
||||
public char getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @return the current value of the entry
|
||||
*/
|
||||
public Object getValue(){
|
||||
return value;
|
||||
}
|
||||
/**
|
||||
* @return the type of the entry
|
||||
*/
|
||||
public NetworkTableEntryType getType(){
|
||||
return type;
|
||||
}
|
||||
private static final char HALF_OF_CHAR = 32768;
|
||||
/**
|
||||
* set the value of the entry if the given sequence number is greater that the current sequence number
|
||||
* @param newSequenceNumber the sequence number of the incoming entry
|
||||
* @param newValue the new value
|
||||
* @return true if the value was set
|
||||
*/
|
||||
public boolean putValue(final char newSequenceNumber, final Object newValue) {
|
||||
if( (sequenceNumber < newSequenceNumber && newSequenceNumber - sequenceNumber < HALF_OF_CHAR)
|
||||
|| (sequenceNumber > newSequenceNumber && sequenceNumber - newSequenceNumber > HALF_OF_CHAR) ){
|
||||
value = newValue;
|
||||
sequenceNumber = newSequenceNumber;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* force a value and new sequence number upon an entry
|
||||
* @param newSequenceNumber
|
||||
* @param newValue
|
||||
*/
|
||||
public void forcePut(final char newSequenceNumber, final Object newValue) {
|
||||
value = newValue;
|
||||
sequenceNumber = newSequenceNumber;
|
||||
}
|
||||
/**
|
||||
* force a value and new sequence number upon an entry, Will also set the type of the entry
|
||||
* @param newSequenceNumber
|
||||
* @param type
|
||||
* @param newValue
|
||||
*/
|
||||
public void forcePut(final char newSequenceNumber, final NetworkTableEntryType type, final Object newValue) {
|
||||
this.type = type;
|
||||
forcePut(newSequenceNumber, newValue);
|
||||
}
|
||||
|
||||
|
||||
public void makeDirty() {
|
||||
isDirty = true;
|
||||
}
|
||||
public void makeClean() {
|
||||
isDirty = false;
|
||||
}
|
||||
public boolean isDirty(){
|
||||
return isDirty;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the value of the entry over the output stream
|
||||
* @param os
|
||||
* @throws IOException
|
||||
*/
|
||||
public void sendValue(final DataOutputStream os) throws IOException{
|
||||
type.sendValue(value, os);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current sequence number of the entry
|
||||
*/
|
||||
public char getSequenceNumber() {
|
||||
return sequenceNumber;
|
||||
}
|
||||
/**
|
||||
* Sets the id of the entry
|
||||
* @param id the id of the entry
|
||||
* @throws IllegalStateException if the entry already has a known id
|
||||
*/
|
||||
public void setId(final char id) throws IllegalStateException{
|
||||
if(this.id!=UNKNOWN_ID)
|
||||
throw new IllegalStateException("Cannot set the Id of a table entry that already has a valid id");
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* clear the id of the entry to unknown
|
||||
*/
|
||||
public void clearId() {
|
||||
id = UNKNOWN_ID;
|
||||
}
|
||||
|
||||
public void send(NetworkTableConnection connection) throws IOException {
|
||||
connection.sendEntryAssignment(this);
|
||||
}
|
||||
public void fireListener(TableListenerManager listenerManager) {//TODO determine best way to handle complex data
|
||||
listenerManager.fireTableListeners(name, value, isNew);
|
||||
isNew = false;
|
||||
}
|
||||
|
||||
public String toString(){
|
||||
return "Network Table "+type.name+" entry: "+name+": "+(int)getId()+" - "+(int)getSequenceNumber()+" - "+getValue();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
/**
|
||||
* The definitions of all of the protocol message types
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public interface NetworkTableMessageType {
|
||||
/**
|
||||
* A keep alive message that the client sends
|
||||
*/
|
||||
int KEEP_ALIVE = 0x00;
|
||||
/**
|
||||
* a client hello message that a client sends
|
||||
*/
|
||||
int CLIENT_HELLO = 0x01;
|
||||
/**
|
||||
* a protocol version unsupported message that the server sends to a client
|
||||
*/
|
||||
int PROTOCOL_VERSION_UNSUPPORTED = 0x02;
|
||||
int SERVER_HELLO_COMPLETE = 0x03;
|
||||
/**
|
||||
* an entry assignment message
|
||||
*/
|
||||
int ENTRY_ASSIGNMENT = 0x10;
|
||||
/**
|
||||
* a field update message
|
||||
*/
|
||||
int FIELD_UPDATE = 0x11;
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.AbstractNetworkTableEntryStore.TableListenerManager;
|
||||
import edu.wpi.first.wpilibj.networktables2.client.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.util.*;
|
||||
import edu.wpi.first.wpilibj.tables.*;
|
||||
|
||||
/**
|
||||
* represents a node (either a client or a server) in a network tables 2.0
|
||||
* <br>
|
||||
* implementers of the class must ensure that they call {@link #init(NetworkTableTransactionPool, AbstractNetworkTableEntryStore)} before calling any other methods on this class
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public abstract class NetworkTableNode implements TableListenerManager, ClientConnectionListenerManager, IRemote{
|
||||
|
||||
protected AbstractNetworkTableEntryStore entryStore;
|
||||
|
||||
|
||||
protected final void init(AbstractNetworkTableEntryStore entryStore) {
|
||||
this.entryStore = entryStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the entry store used by this node
|
||||
*/
|
||||
public AbstractNetworkTableEntryStore getEntryStore(){
|
||||
return entryStore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void putBoolean(String name, boolean value){
|
||||
putValue(name, DefaultEntryTypes.BOOLEAN, value?Boolean.TRUE:Boolean.FALSE);
|
||||
}
|
||||
public boolean getBoolean(String name) throws TableKeyNotDefinedException{
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry==null)
|
||||
throw new TableKeyNotDefinedException(name);
|
||||
return ((Boolean)entry.getValue()).booleanValue();
|
||||
}
|
||||
|
||||
public void putDouble(String name, double value){
|
||||
putValue(name, DefaultEntryTypes.DOUBLE, new Double(value));//TODO don't make a new double every time
|
||||
}
|
||||
public double getDouble(String name) throws TableKeyNotDefinedException{
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry==null)
|
||||
throw new TableKeyNotDefinedException(name);
|
||||
return ((Double)entry.getValue()).doubleValue();
|
||||
}
|
||||
|
||||
public void putString(String name, String value){
|
||||
putValue(name, DefaultEntryTypes.STRING, value);
|
||||
}
|
||||
public String getString(String name) throws TableKeyNotDefinedException{
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry==null)
|
||||
throw new TableKeyNotDefinedException(name);
|
||||
return ((String)entry.getValue());
|
||||
}
|
||||
|
||||
public void putComplex(String name, ComplexData value){
|
||||
putValue(name, value.getType(), value);
|
||||
}
|
||||
|
||||
public void retrieveValue(String name, Object externalData) throws TableKeyNotDefinedException{
|
||||
synchronized(entryStore){
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry==null)
|
||||
throw new TableKeyNotDefinedException(name);
|
||||
NetworkTableEntryType entryType = entry.getType();
|
||||
if(!(entryType instanceof ComplexEntryType))
|
||||
throw new TableKeyExistsWithDifferentTypeException(name, entryType, "Is not a complex data type");
|
||||
ComplexEntryType complexType = (ComplexEntryType)entryType;
|
||||
complexType.exportValue(name, entry.getValue(), externalData);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void putValue(String name, Object value) throws IllegalArgumentException{
|
||||
if(value instanceof Double){
|
||||
putValue(name, DefaultEntryTypes.DOUBLE, value);
|
||||
} else if (value instanceof String){
|
||||
putValue(name, DefaultEntryTypes.STRING, value);
|
||||
} else if(value instanceof Boolean){
|
||||
putValue(name, DefaultEntryTypes.BOOLEAN, value);
|
||||
} else if(value instanceof ComplexData){
|
||||
putValue(name, ((ComplexData)value).getType(), value);
|
||||
} else if(value==null) {
|
||||
throw new NullPointerException("Cannot put a null value into networktables");
|
||||
} else {
|
||||
throw new IllegalArgumentException("Invalid Type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put a value with a specific network table type
|
||||
* @param name the name of the entry to associate with the given value
|
||||
* @param type the type of the entry
|
||||
* @param value the actual value of the entry
|
||||
*/
|
||||
public void putValue(String name, NetworkTableEntryType type, Object value){
|
||||
if(type instanceof ComplexEntryType){
|
||||
synchronized(entryStore){//must sync because use get
|
||||
ComplexEntryType entryType = (ComplexEntryType)type;
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry!=null)
|
||||
entryStore.putOutgoing(entry, entryType.internalizeValue(entry.name, value, entry.getValue()));
|
||||
else
|
||||
entryStore.putOutgoing(name, type, entryType.internalizeValue(name, value, null));
|
||||
}
|
||||
}
|
||||
else
|
||||
entryStore.putOutgoing(name, type, value);
|
||||
}
|
||||
|
||||
public void putValue(NetworkTableEntry entry, Object value){
|
||||
if(entry.getType() instanceof ComplexEntryType){
|
||||
synchronized(entryStore){//must sync because use get
|
||||
ComplexEntryType entryType = (ComplexEntryType)entry.getType();
|
||||
entryStore.putOutgoing(entry, entryType.internalizeValue(entry.name, value, entry.getValue()));
|
||||
}
|
||||
}
|
||||
else
|
||||
entryStore.putOutgoing(entry, value);
|
||||
}
|
||||
|
||||
public Object getValue(String name) throws TableKeyNotDefinedException{//TODO don't allow get of complex types
|
||||
synchronized(entryStore){
|
||||
NetworkTableEntry entry = entryStore.getEntry(name);
|
||||
if(entry == null)
|
||||
throw new TableKeyNotDefinedException(name);
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param key the key to check for existence
|
||||
* @return true if the table has the given key
|
||||
*/
|
||||
public boolean containsKey(final String key){
|
||||
return entryStore.getEntry(key)!=null;
|
||||
}
|
||||
|
||||
/**
|
||||
* close all networking activity related to this node
|
||||
*/
|
||||
public abstract void close();
|
||||
|
||||
private final List remoteListeners = new List();
|
||||
public void addConnectionListener(IRemoteConnectionListener listener, boolean immediateNotify) {
|
||||
remoteListeners.add(listener);
|
||||
if(isConnected())
|
||||
listener.connected(this);
|
||||
else
|
||||
listener.disconnected(this);
|
||||
}
|
||||
public void removeConnectionListener(IRemoteConnectionListener listener) {
|
||||
remoteListeners.remove(listener);
|
||||
}
|
||||
public void fireConnectedEvent(){
|
||||
for(int i = 0; i<remoteListeners.size(); ++i)
|
||||
((IRemoteConnectionListener)remoteListeners.get(i)).connected(this);
|
||||
}
|
||||
public void fireDisconnectedEvent(){
|
||||
for(int i = 0; i<remoteListeners.size(); ++i)
|
||||
((IRemoteConnectionListener)remoteListeners.get(i)).disconnected(this);
|
||||
}
|
||||
|
||||
|
||||
private final List tableListeners = new List();
|
||||
public void addTableListener(ITableListener listener, boolean immediateNotify) {
|
||||
tableListeners.add(listener);
|
||||
if(immediateNotify)
|
||||
entryStore.notifyEntries(null, listener);
|
||||
}
|
||||
public void removeTableListener(ITableListener listener) {
|
||||
tableListeners.remove(listener);
|
||||
}
|
||||
public void fireTableListeners(String key, Object value, boolean isNew){
|
||||
for(int i = 0; i<tableListeners.size(); ++i)
|
||||
((ITableListener)tableListeners.get(i)).valueChanged(null, key, value, isNew);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
|
||||
|
||||
public interface OutgoingEntryReceiver {
|
||||
OutgoingEntryReceiver NULL = new OutgoingEntryReceiver() {
|
||||
public void offerOutgoingUpdate(NetworkTableEntry entry) {
|
||||
}
|
||||
public void offerOutgoingAssignment(NetworkTableEntry entry) {
|
||||
}
|
||||
};
|
||||
|
||||
public void offerOutgoingAssignment(NetworkTableEntry entry);
|
||||
public void offerOutgoingUpdate(NetworkTableEntry entry);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.type.NetworkTableEntryType;
|
||||
|
||||
/**
|
||||
* Throw to indicate that an attempt to put data to a table is illegal because
|
||||
* the specified key exists with a different data type than the put data type.
|
||||
*
|
||||
* @author Paul Malmsten <pmalmsten@gmail.com>
|
||||
*/
|
||||
public class TableKeyExistsWithDifferentTypeException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Creates a new TableKeyExistsWithDifferentTypeException
|
||||
*
|
||||
* @param existingKey The name of the key which exists.
|
||||
* @param existingType The type of the key which exists.
|
||||
*/
|
||||
public TableKeyExistsWithDifferentTypeException(String existingKey, NetworkTableEntryType existingType) {
|
||||
this(existingKey, existingType, "");
|
||||
}
|
||||
|
||||
public TableKeyExistsWithDifferentTypeException(String existingKey, NetworkTableEntryType existingType, String message) {
|
||||
super("Illegal put - key '" + existingKey + "' exists with type '" + existingType + "'. "+message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
|
||||
/**
|
||||
* A transaction receiver that marks all Table entries as dirty in the entry store. Entries will not be passed to the continuing receiver if they are already dirty
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class TransactionDirtier implements OutgoingEntryReceiver {
|
||||
private final OutgoingEntryReceiver continuingReceiver;
|
||||
|
||||
public TransactionDirtier(final OutgoingEntryReceiver continuingReceiver) {
|
||||
this.continuingReceiver = continuingReceiver;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void offerOutgoingAssignment(NetworkTableEntry entry) {
|
||||
if(entry.isDirty())
|
||||
return;
|
||||
entry.makeDirty();
|
||||
continuingReceiver.offerOutgoingAssignment(entry);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public void offerOutgoingUpdate(NetworkTableEntry entry) {
|
||||
if(entry.isDirty())
|
||||
return;
|
||||
entry.makeDirty();
|
||||
continuingReceiver.offerOutgoingUpdate(entry);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
|
||||
package edu.wpi.first.wpilibj.networktables2;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.util.*;
|
||||
|
||||
/**
|
||||
* A write manager is a {@link IncomingEntryReceiver} that buffers transactions and then and then dispatches them to a flushable transaction receiver that is periodically offered all queued transaction and then flushed
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class WriteManager implements OutgoingEntryReceiver, PeriodicRunnable{
|
||||
private final int SLEEP_TIME = 100;
|
||||
|
||||
private final int queueSize = 500;
|
||||
|
||||
private Object transactionsLock = new Object();
|
||||
private NTThread thread;
|
||||
private NTThreadManager threadManager;
|
||||
private final AbstractNetworkTableEntryStore entryStore;
|
||||
|
||||
private volatile HalfQueue incomingAssignmentQueue;
|
||||
private volatile HalfQueue incomingUpdateQueue;
|
||||
private volatile HalfQueue outgoingAssignmentQueue;
|
||||
private volatile HalfQueue outgoingUpdateQueue;
|
||||
|
||||
private FlushableOutgoingEntryReceiver receiver;
|
||||
private long lastWrite;
|
||||
|
||||
private final long keepAliveDelay;
|
||||
|
||||
/**
|
||||
* Create a new Write manager
|
||||
* @param receiver
|
||||
* @param threadManager
|
||||
* @param transactionPool
|
||||
* @param entryStore
|
||||
*/
|
||||
public WriteManager(final FlushableOutgoingEntryReceiver receiver, final NTThreadManager threadManager, final AbstractNetworkTableEntryStore entryStore, long keepAliveDelay) {
|
||||
this.receiver = receiver;
|
||||
this.threadManager = threadManager;
|
||||
this.entryStore = entryStore;
|
||||
|
||||
incomingAssignmentQueue = new HalfQueue(queueSize);
|
||||
incomingUpdateQueue = new HalfQueue(queueSize);
|
||||
outgoingAssignmentQueue = new HalfQueue(queueSize);
|
||||
outgoingUpdateQueue = new HalfQueue(queueSize);
|
||||
|
||||
this.keepAliveDelay = keepAliveDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* start the write thread
|
||||
*/
|
||||
public void start(){
|
||||
if(thread!=null)
|
||||
stop();
|
||||
lastWrite = System.currentTimeMillis();
|
||||
thread = threadManager.newBlockingPeriodicThread(this, "Write Manager Thread");
|
||||
}
|
||||
/**
|
||||
* stop the write thread
|
||||
*/
|
||||
public void stop(){
|
||||
if(thread!=null)
|
||||
thread.stop();
|
||||
}
|
||||
|
||||
|
||||
public void offerOutgoingAssignment(NetworkTableEntry entry) {
|
||||
synchronized(transactionsLock){
|
||||
incomingAssignmentQueue.queue(entry);
|
||||
if(incomingAssignmentQueue.isFull()){
|
||||
try {
|
||||
run();
|
||||
} catch (InterruptedException e) {}
|
||||
System.err.println("assignment queue overflowed. decrease the rate at which you create new entries or increase the write buffer size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void offerOutgoingUpdate(NetworkTableEntry entry) {
|
||||
synchronized(transactionsLock){
|
||||
incomingUpdateQueue.queue(entry);
|
||||
if(incomingUpdateQueue.isFull()){
|
||||
try {
|
||||
run();
|
||||
} catch (InterruptedException e) {}
|
||||
System.err.println("update queue overflowed. decrease the rate at which you update entries or increase the write buffer size");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* the periodic method that sends all buffered transactions
|
||||
*/
|
||||
public void run() throws InterruptedException {
|
||||
synchronized(transactionsLock){
|
||||
//swap the assignment and update queue
|
||||
HalfQueue tmp = incomingAssignmentQueue;
|
||||
incomingAssignmentQueue = outgoingAssignmentQueue;
|
||||
outgoingAssignmentQueue = tmp;
|
||||
|
||||
tmp = incomingUpdateQueue;
|
||||
incomingUpdateQueue = outgoingUpdateQueue;
|
||||
outgoingUpdateQueue = tmp;
|
||||
}
|
||||
|
||||
boolean wrote = false;
|
||||
NetworkTableEntry entry;
|
||||
int i;
|
||||
int size = outgoingAssignmentQueue.size();
|
||||
Object[] array = outgoingAssignmentQueue.array;
|
||||
for(i = 0; i<size; ++i){
|
||||
entry = (NetworkTableEntry)array[i];
|
||||
synchronized(entryStore){
|
||||
entry.makeClean();
|
||||
}
|
||||
wrote = true;
|
||||
receiver.offerOutgoingAssignment(entry);
|
||||
}
|
||||
outgoingAssignmentQueue.clear();
|
||||
|
||||
|
||||
size = outgoingUpdateQueue.size();
|
||||
array = outgoingUpdateQueue.array;
|
||||
for(i = 0; i<size; ++i){
|
||||
entry = (NetworkTableEntry)array[i];
|
||||
synchronized(entryStore){
|
||||
entry.makeClean();
|
||||
}
|
||||
wrote = true;
|
||||
receiver.offerOutgoingUpdate(entry);
|
||||
}
|
||||
outgoingUpdateQueue.clear();
|
||||
|
||||
|
||||
if(wrote){
|
||||
receiver.flush();
|
||||
lastWrite = System.currentTimeMillis();
|
||||
}
|
||||
else if(System.currentTimeMillis()-lastWrite>keepAliveDelay)
|
||||
receiver.ensureAlive();
|
||||
|
||||
Thread.sleep(SLEEP_TIME);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.BadMessageException;
|
||||
import java.io.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
/**
|
||||
* Object that adapts messages from a server
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class ClientConnectionAdapter implements ConnectionAdapter, IncomingEntryReceiver, FlushableOutgoingEntryReceiver{
|
||||
|
||||
private final ClientNetworkTableEntryStore entryStore;
|
||||
private final IOStreamFactory streamFactory;
|
||||
private final NTThreadManager threadManager;
|
||||
|
||||
private NetworkTableConnection connection;
|
||||
private NTThread readThread;
|
||||
private ClientConnectionState connectionState = ClientConnectionState.DISCONNECTED_FROM_SERVER;
|
||||
private final ClientConnectionListenerManager connectionListenerManager;
|
||||
private final Object connectionLock = new Object();
|
||||
private final NetworkTableEntryTypeManager typeManager;
|
||||
|
||||
private void gotoState(ClientConnectionState newState){
|
||||
synchronized(connectionLock){
|
||||
if(connectionState!=newState){
|
||||
System.out.println(this+" entered connection state: "+newState);
|
||||
if(newState==ClientConnectionState.IN_SYNC_WITH_SERVER)
|
||||
connectionListenerManager.fireConnectedEvent();
|
||||
if(connectionState==ClientConnectionState.IN_SYNC_WITH_SERVER)
|
||||
connectionListenerManager.fireDisconnectedEvent();
|
||||
connectionState = newState;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return the state of the connection
|
||||
*/
|
||||
public ClientConnectionState getConnectionState(){
|
||||
return connectionState;
|
||||
}
|
||||
/**
|
||||
* @return if the client is connected to the server
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
return getConnectionState()==ClientConnectionState.IN_SYNC_WITH_SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new ClientConnectionAdapter
|
||||
* @param entryStore
|
||||
* @param threadManager
|
||||
* @param streamFactory
|
||||
* @param transactionPool
|
||||
* @param connectionListenerManager
|
||||
*/
|
||||
public ClientConnectionAdapter(final ClientNetworkTableEntryStore entryStore, final NTThreadManager threadManager, final IOStreamFactory streamFactory, final ClientConnectionListenerManager connectionListenerManager, final NetworkTableEntryTypeManager typeManager) {
|
||||
this.entryStore = entryStore;
|
||||
this.streamFactory = streamFactory;
|
||||
this.threadManager = threadManager;
|
||||
this.connectionListenerManager = connectionListenerManager;
|
||||
this.typeManager = typeManager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Connection management
|
||||
*/
|
||||
/**
|
||||
* Reconnect the client to the server (even if the client is not currently connected)
|
||||
*/
|
||||
public void reconnect() {
|
||||
synchronized(connectionLock){
|
||||
close();//close the existing stream and monitor thread if needed
|
||||
try{
|
||||
IOStream stream = streamFactory.createStream();
|
||||
if(stream==null)
|
||||
return;
|
||||
connection = new NetworkTableConnection(stream, typeManager);
|
||||
readThread = threadManager.newBlockingPeriodicThread(new ConnectionMonitorThread(this, connection), "Client Connection Reader Thread");
|
||||
connection.sendClientHello();
|
||||
gotoState(ClientConnectionState.CONNECTED_TO_SERVER);
|
||||
} catch(Exception e){
|
||||
close();//make sure to clean everything up if we fail to connect
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the client connection
|
||||
*/
|
||||
public void close() {
|
||||
close(ClientConnectionState.DISCONNECTED_FROM_SERVER);
|
||||
}
|
||||
/**
|
||||
* Close the connection to the server and enter the given state
|
||||
* @param newState
|
||||
*/
|
||||
public void close(final ClientConnectionState newState) {
|
||||
synchronized(connectionLock){
|
||||
gotoState(newState);
|
||||
if(readThread!=null){
|
||||
readThread.stop();
|
||||
readThread = null;
|
||||
}
|
||||
if(connection!=null){
|
||||
connection.close();
|
||||
connection = null;
|
||||
}
|
||||
entryStore.clearIds();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void badMessage(BadMessageException e) {
|
||||
close(new ClientConnectionState.Error(e));
|
||||
}
|
||||
|
||||
public void ioException(IOException e) {
|
||||
if(connectionState!=ClientConnectionState.DISCONNECTED_FROM_SERVER)//will get io exception when on read thread connection is closed
|
||||
reconnect();
|
||||
//gotoState(new ClientConnectionState.Error(e));
|
||||
}
|
||||
|
||||
public NetworkTableEntry getEntry(char id) {
|
||||
return entryStore.getEntry(id);
|
||||
}
|
||||
|
||||
|
||||
public void keepAlive() throws IOException {
|
||||
}
|
||||
|
||||
public void clientHello(char protocolRevision) throws IOException {
|
||||
throw new BadMessageException("A client should not receive a client hello message");
|
||||
}
|
||||
|
||||
public void protocolVersionUnsupported(char protocolRevision) {
|
||||
close();
|
||||
gotoState(new ClientConnectionState.ProtocolUnsuppotedByServer(protocolRevision));
|
||||
}
|
||||
|
||||
public void serverHelloComplete() throws IOException {
|
||||
if (connectionState==ClientConnectionState.CONNECTED_TO_SERVER) {
|
||||
try {
|
||||
gotoState(ClientConnectionState.IN_SYNC_WITH_SERVER);
|
||||
entryStore.sendUnknownEntries(connection);
|
||||
} catch (IOException e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new BadMessageException("A client should only receive a server hello complete once and only after it has connected to the server");
|
||||
}
|
||||
|
||||
|
||||
public void offerIncomingAssignment(NetworkTableEntry entry) {
|
||||
entryStore.offerIncomingAssignment(entry);
|
||||
}
|
||||
public void offerIncomingUpdate(NetworkTableEntry entry, char sequenceNumber, Object value) {
|
||||
entryStore.offerIncomingUpdate(entry, sequenceNumber, value);
|
||||
}
|
||||
|
||||
public void offerOutgoingAssignment(NetworkTableEntry entry) {
|
||||
try {
|
||||
synchronized(connectionLock){
|
||||
if(connection!=null && connectionState==ClientConnectionState.IN_SYNC_WITH_SERVER)
|
||||
connection.sendEntryAssignment(entry);
|
||||
}
|
||||
} catch(IOException e){
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void offerOutgoingUpdate(NetworkTableEntry entry) {
|
||||
try {
|
||||
synchronized(connectionLock){
|
||||
if(connection!=null && connectionState==ClientConnectionState.IN_SYNC_WITH_SERVER)
|
||||
connection.sendEntryUpdate(entry);
|
||||
}
|
||||
} catch(IOException e){
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
public void flush() {
|
||||
synchronized(connectionLock){
|
||||
if(connection!=null) {
|
||||
try {
|
||||
connection.flush();
|
||||
} catch (IOException e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ensureAlive() {
|
||||
synchronized(connectionLock){
|
||||
if(connection!=null) {
|
||||
try {
|
||||
connection.sendKeepAlive();
|
||||
} catch (IOException e) {
|
||||
ioException(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
reconnect();//try to reconnect if not connected
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
/**
|
||||
* An object that manages connection listeners and fires events for other listeners
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public interface ClientConnectionListenerManager {
|
||||
/**
|
||||
* called when something is connected
|
||||
*/
|
||||
void fireConnectedEvent();
|
||||
/**
|
||||
* called when something is disconnected
|
||||
*/
|
||||
void fireDisconnectedEvent();
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
/**
|
||||
* Represents a state that the client is in
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class ClientConnectionState {
|
||||
/**
|
||||
* indicates that the client is disconnected from the server
|
||||
*/
|
||||
public static final ClientConnectionState DISCONNECTED_FROM_SERVER = new ClientConnectionState("DISCONNECTED_FROM_SERVER");
|
||||
/**
|
||||
* indicates that the client is connected to the server but has not yet begun communication
|
||||
*/
|
||||
public static final ClientConnectionState CONNECTED_TO_SERVER = new ClientConnectionState("CONNECTED_TO_SERVER");
|
||||
/**
|
||||
* represents that the client has sent the hello to the server and is waiting for a response
|
||||
*/
|
||||
public static final ClientConnectionState SENT_HELLO_TO_SERVER = new ClientConnectionState("SENT_HELLO_TO_SERVER");
|
||||
/**
|
||||
* represents that the client is now in sync with the server
|
||||
*/
|
||||
public static final ClientConnectionState IN_SYNC_WITH_SERVER = new ClientConnectionState("IN_SYNC_WITH_SERVER");
|
||||
|
||||
/**
|
||||
* Represents that a client received a message from the server indicating that the client's protocol revision is not supported by the server
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public static class ProtocolUnsuppotedByServer extends ClientConnectionState{
|
||||
private final char serverVersion;
|
||||
/**
|
||||
* Create a new protocol unsupported state
|
||||
* @param serverVersion
|
||||
*/
|
||||
public ProtocolUnsuppotedByServer(final char serverVersion){
|
||||
super("PROTOCOL_UNSUPPORTED_BY_SERVER");
|
||||
this.serverVersion = serverVersion;
|
||||
}
|
||||
/**
|
||||
* @return the protocol version that the server reported it supports
|
||||
*/
|
||||
public char getServerVersion(){
|
||||
return serverVersion;
|
||||
}
|
||||
public String toString(){
|
||||
return "PROTOCOL_UNSUPPORTED_BY_SERVER: Server Version: 0x"+Integer.toHexString(serverVersion);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Represents that the client is in an error state
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public static class Error extends ClientConnectionState{
|
||||
private final Exception e;
|
||||
/**
|
||||
* Create a new error state
|
||||
* @param e
|
||||
*/
|
||||
public Error(final Exception e){
|
||||
super("CLIENT_ERROR");
|
||||
this.e = e;
|
||||
}
|
||||
/**
|
||||
* @return the exception that caused the client to enter an error state
|
||||
*/
|
||||
public Exception getException(){
|
||||
return e;
|
||||
}
|
||||
public String toString(){
|
||||
return "CLIENT_ERROR: "+e.getClass()+": "+e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private String name;
|
||||
protected ClientConnectionState(String name){
|
||||
this.name = name;
|
||||
}
|
||||
public String toString(){
|
||||
return name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.connection.*;
|
||||
|
||||
/**
|
||||
* The entry store for a {@link NetworkTableClient}
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class ClientNetworkTableEntryStore extends AbstractNetworkTableEntryStore{
|
||||
|
||||
/**
|
||||
* Create a new ClientNetworkTableEntryStore
|
||||
* @param transactionPool
|
||||
* @param listenerManager
|
||||
*/
|
||||
public ClientNetworkTableEntryStore(final TableListenerManager listenerManager) {
|
||||
super(listenerManager);
|
||||
}
|
||||
|
||||
|
||||
protected boolean addEntry(NetworkTableEntry newEntry){
|
||||
synchronized(this){
|
||||
NetworkTableEntry entry = (NetworkTableEntry)namedEntries.get(newEntry.name);
|
||||
|
||||
if(entry!=null){
|
||||
if(entry.getId()!=newEntry.getId()){
|
||||
idEntries.remove(entry.getId());
|
||||
if(newEntry.getId()!=NetworkTableEntry.UNKNOWN_ID){
|
||||
entry.setId(newEntry.getId());
|
||||
idEntries.put(newEntry.getId(), entry);
|
||||
}
|
||||
}
|
||||
|
||||
entry.forcePut(newEntry.getSequenceNumber(), newEntry.getType(), newEntry.getValue());
|
||||
}
|
||||
else{
|
||||
if(newEntry.getId()!=NetworkTableEntry.UNKNOWN_ID)
|
||||
idEntries.put(newEntry.getId(), newEntry);
|
||||
namedEntries.put(newEntry.name, newEntry);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean updateEntry(NetworkTableEntry entry, char sequenceNumber, Object value) {
|
||||
synchronized(this){
|
||||
entry.forcePut(sequenceNumber, value);
|
||||
if(entry.getId()==NetworkTableEntry.UNKNOWN_ID){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send all unknown entries in the entry store to the given connection
|
||||
* @param connection
|
||||
* @throws IOException
|
||||
*/
|
||||
void sendUnknownEntries(final NetworkTableConnection connection) throws IOException {
|
||||
synchronized(this){
|
||||
Enumeration e = namedEntries.elements();
|
||||
while(e.hasMoreElements()){
|
||||
NetworkTableEntry entry = (NetworkTableEntry) e.nextElement();
|
||||
if(entry.getId()==NetworkTableEntry.UNKNOWN_ID)
|
||||
connection.sendEntryAssignment(entry);
|
||||
}
|
||||
connection.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.client;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.stream.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.thread.*;
|
||||
import edu.wpi.first.wpilibj.networktables2.type.*;
|
||||
|
||||
/**
|
||||
* A client node in NetworkTables 2.0
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class NetworkTableClient extends NetworkTableNode{
|
||||
private final ClientConnectionAdapter adapter;
|
||||
private final WriteManager writeManager;
|
||||
|
||||
/**
|
||||
* Create a new NetworkTable Client
|
||||
* @param streamFactory
|
||||
* @param threadManager
|
||||
* @param transactionPool
|
||||
*/
|
||||
public NetworkTableClient(final IOStreamFactory streamFactory, final NetworkTableEntryTypeManager typeManager, final NTThreadManager threadManager){
|
||||
ClientNetworkTableEntryStore entryStore;
|
||||
init(entryStore = new ClientNetworkTableEntryStore(this));
|
||||
adapter = new ClientConnectionAdapter(entryStore, threadManager, streamFactory, this, typeManager);
|
||||
writeManager = new WriteManager(adapter, threadManager, getEntryStore(), 1000);
|
||||
|
||||
getEntryStore().setOutgoingReceiver(new TransactionDirtier(writeManager));
|
||||
getEntryStore().setIncomingReceiver(OutgoingEntryReceiver.NULL);
|
||||
writeManager.start();
|
||||
}
|
||||
/**
|
||||
* Create a new NetworkTable Client
|
||||
* @param streamFactory
|
||||
*/
|
||||
public NetworkTableClient(final IOStreamFactory streamFactory){
|
||||
this(streamFactory, new NetworkTableEntryTypeManager(), new DefaultThreadManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* force the client to disconnect and reconnect to the server again. Will connect if the client is currently disconnected
|
||||
*/
|
||||
public void reconnect() {
|
||||
adapter.reconnect();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
adapter.close();
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
writeManager.stop();
|
||||
close();
|
||||
}
|
||||
|
||||
public boolean isConnected() {
|
||||
return adapter.isConnected();
|
||||
}
|
||||
|
||||
public boolean isServer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
/**
|
||||
* An exception throw when a NetworkTableNode receives a bad message
|
||||
*
|
||||
* @author Mitchell
|
||||
*
|
||||
*/
|
||||
public class BadMessageException extends IOException {
|
||||
/**
|
||||
* Create a new exception
|
||||
* @param message a message
|
||||
*/
|
||||
public BadMessageException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package edu.wpi.first.wpilibj.networktables2.connection;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import edu.wpi.first.wpilibj.networktables2.*;
|
||||
|
||||
/**
|
||||
* Handles logic specific to the type of a node
|
||||
*
|
||||
* @author mwills
|
||||
*
|
||||
*/
|
||||
public interface ConnectionAdapter extends IncomingEntryReceiver{
|
||||
/**
|
||||
* Called when the connection receives a keep alive message
|
||||
* @throws IOException
|
||||
*/
|
||||
public void keepAlive() throws IOException;
|
||||
|
||||
/**
|
||||
* Called when the connection receives a client hello message
|
||||
* @param protocolRevision
|
||||
* @throws IOException
|
||||
*/
|
||||
public void clientHello(char protocolRevision) throws IOException;
|
||||
|
||||
/**
|
||||
* Called when the connection receives a protocol unsupported message
|
||||
* @param protocolRevision the protocol version the server reported it supports
|
||||
* @throws IOException
|
||||
*/
|
||||
public void protocolVersionUnsupported(char protocolRevision) throws IOException;
|
||||
|
||||
public void serverHelloComplete() throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* get an entry (used by a connection when filling an update entry
|
||||
* @param id
|
||||
* @return the entry or null if the entry does not exist
|
||||
*/
|
||||
public NetworkTableEntry getEntry(char id);
|
||||
|
||||
/**
|
||||
* called if a bad message exception is thrown
|
||||
* @param e
|
||||
*/
|
||||
public void badMessage(BadMessageException e);
|
||||
|
||||
/**
|
||||
* called if an io exception is thrown
|
||||
* @param e
|
||||
*/
|
||||
public void ioException(IOException e);
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user