/src/tool/TOOL/Net/DataSerializer.java

https://github.com/nterman/nbites · Java · 466 lines · 271 code · 90 blank · 105 comment · 63 complexity · ab2f5c201572c5fc0b5dd46654b77e48 MD5 · raw file

  1. // This file is part of TOOL, a robotics interaction and development
  2. // package created by the Northern Bites RoboCup team of Bowdoin College
  3. // in Brunswick, Maine.
  4. //
  5. // TOOL is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. //
  10. // TOOL is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with TOOL. If not, see <http://www.gnu.org/licenses/>.
  17. package TOOL.Net;
  18. import java.net.InetAddress;
  19. import java.net.Socket;
  20. import java.net.UnknownHostException;
  21. import java.io.BufferedInputStream;
  22. import java.io.BufferedOutputStream;
  23. import java.io.DataInputStream;
  24. import java.io.DataOutputStream;
  25. import java.io.IOException;
  26. import java.io.StreamCorruptedException;
  27. import TOOL.TOOL;
  28. public class DataSerializer {
  29. public static final int UDP_PORT = 4000;
  30. public static final int TCP_PORT = 4001;
  31. public static final int BUF_SIZE = 1048576; // 1 MB - seems large, but one
  32. // Nao image is 614400
  33. public static final int SIZEOF_INT = 4;
  34. public static final int SIZEOF_BYTE = 1;
  35. public static final int SIZEOF_FLOAT = SIZEOF_INT;
  36. public static final int SIZEOF_LONG = 8;
  37. public static final int SIZEOF_DOUBLE = SIZEOF_LONG;
  38. public static final byte TYPE_INT = 0;
  39. public static final byte TYPE_BYTE = 1;
  40. public static final byte TYPE_FLOAT = 2;
  41. public static final byte TYPE_LONG = 3;
  42. public static final byte TYPE_DOUBLE = 4; // this is so cool
  43. public static final byte TYPE_INT_ARRAY = 5;
  44. public static final byte TYPE_BYTE_ARRAY = 6;
  45. public static final byte TYPE_FLOAT_ARRAY = 7;
  46. public static final byte TYPE_LONG_ARRAY = 8;
  47. public static final byte TYPE_DOUBLE_ARRAY = 9;
  48. //
  49. // Default Error messages
  50. //
  51. public static final String ERROR_NO_INPUT = "Input unavailable on socket.";
  52. public static final String ERROR_NO_OUTPUT =
  53. "Output unavailable on socket.";
  54. public static final String ERROR_DATATYPE = "Unexpected data type read " +
  55. "from socket connection.";
  56. public static final String ERROR_DATASIZE = "Unexpected amount of data " +
  57. "read in array transfer from socket connection.";
  58. private InetAddress host;
  59. private Socket sock;
  60. private DataInputStream input;
  61. private DataOutputStream output;
  62. private boolean flushing;
  63. public DataSerializer(InetAddress remoteHost) {
  64. host = remoteHost;
  65. flushing = false;
  66. }
  67. public void connect() throws IOException {
  68. sock = new Socket(host, TCP_PORT);
  69. input = new DataInputStream(
  70. new BufferedInputStream(sock.getInputStream(), BUF_SIZE));
  71. output = new DataOutputStream(
  72. new BufferedOutputStream(sock.getOutputStream(), BUF_SIZE));
  73. }
  74. public void close() {
  75. try {
  76. if (sock != null)
  77. sock.close();
  78. }catch (IOException e) {
  79. TOOL.CONSOLE.error("An error occured on disconnect from " + host);
  80. }
  81. }
  82. public void setFlushing(boolean toFlush) {
  83. flushing = toFlush;
  84. }
  85. public void flush() throws IOException {
  86. output.flush();
  87. }
  88. //
  89. // Stream writing methods
  90. //
  91. /**
  92. * Helper method to automate writing the correct header information for a
  93. * serialized array, of any type.
  94. */
  95. private void writeArrayHeader(byte type, int length) throws IOException {
  96. if (output == null)
  97. throw new IOException(ERROR_NO_OUTPUT);
  98. output.write(type);
  99. output.writeInt(length);
  100. }
  101. /**
  102. *
  103. */
  104. public synchronized void writeInt(int value) throws IOException {
  105. if (output == null)
  106. throw new IOException(ERROR_NO_OUTPUT);
  107. output.write(TYPE_INT);
  108. output.writeInt(value);
  109. if (flushing)
  110. output.flush();
  111. }
  112. /**
  113. *
  114. */
  115. public synchronized void writeByte(byte value) throws IOException {
  116. if (output == null)
  117. throw new IOException(ERROR_NO_OUTPUT);
  118. output.write(TYPE_BYTE);
  119. output.write(value);
  120. if (flushing)
  121. output.flush();
  122. }
  123. public synchronized void writeByte(boolean value) throws IOException {
  124. if (value)
  125. writeByte((byte)1);
  126. else
  127. writeByte((byte)0);
  128. }
  129. public synchronized void writeFloat(float value) throws IOException {
  130. if (output == null)
  131. throw new IOException(ERROR_NO_OUTPUT);
  132. output.write(TYPE_FLOAT);
  133. output.writeFloat(value);
  134. if (flushing)
  135. output.flush();
  136. }
  137. /**
  138. * Serialize and write an integer array to the output stream. Prepends the
  139. * message with the standard array header giving the data type and length.
  140. */
  141. public synchronized void writeInts(int[] data) throws IOException {
  142. writeArrayHeader(TYPE_INT_ARRAY, data.length * SIZEOF_INT);
  143. for (int i = 0; i < data.length; i++)
  144. output.writeInt(data[i]);
  145. if (flushing)
  146. output.flush();
  147. }
  148. /**
  149. * Serialize and write a two dimensional integer array to the output
  150. * stream. Prepends the message with the standard array header giving the
  151. * data type and length.
  152. */
  153. public synchronized void writeInts(int[][] data) throws IOException {
  154. writeArrayHeader(TYPE_INT_ARRAY,
  155. data.length * data[0].length * SIZEOF_INT);
  156. for (int i = 0; i < data.length; i++)
  157. for (int j = 0; j < data[0].length; j++)
  158. output.writeInt(data[i][j]);
  159. if (flushing)
  160. output.flush();
  161. }
  162. /**
  163. * Serialize and write a float array to the output stream. Prepends the
  164. * message with the standard array header giving the data type and length.
  165. */
  166. public synchronized void writeFloats(float[] data) throws IOException {
  167. writeArrayHeader(TYPE_FLOAT_ARRAY, data.length * SIZEOF_FLOAT);
  168. for (int i = 0; i < data.length; i++)
  169. output.writeFloat(data[i]);
  170. if (flushing)
  171. output.flush();
  172. }
  173. /**
  174. * Serialize and write a double array to the output stream. Prepends the
  175. * message with the standard array header giving the data type and length.
  176. */
  177. public synchronized void writeDoubles(double[] data) throws IOException {
  178. writeArrayHeader(TYPE_DOUBLE_ARRAY, data.length * SIZEOF_DOUBLE);
  179. for (int i = 0; i < data.length; i++)
  180. output.writeDouble(data[i]);
  181. if (flushing)
  182. output.flush();
  183. }
  184. /**
  185. * Serialize and write a two dimensional double array to the output
  186. * stream. Prepends the message with the standard array header giving the
  187. * data type and length.
  188. */
  189. public synchronized void writeDoubles(double[][] data) throws IOException {
  190. writeArrayHeader(TYPE_DOUBLE_ARRAY,
  191. data.length * data[0].length * SIZEOF_DOUBLE);
  192. for (int i = 0; i < data.length; i++)
  193. for (int j = 0; j < data[0].length; j++)
  194. output.writeDouble(data[i][j]);
  195. if (flushing)
  196. output.flush();
  197. }
  198. /**
  199. *
  200. */
  201. public synchronized void writeBytes(byte[] data) throws IOException {
  202. writeArrayHeader(TYPE_BYTE_ARRAY, data.length);
  203. output.write(data);
  204. if (flushing)
  205. output.flush();
  206. }
  207. public synchronized void writeBytes(boolean[] data) throws IOException {
  208. writeArrayHeader(TYPE_BYTE_ARRAY, data.length);
  209. for (int i = 0; i < data.length; i++)
  210. output.writeBoolean(data[i]);
  211. if (flushing)
  212. output.flush();
  213. }
  214. /**
  215. *
  216. */
  217. public synchronized void writeBytes(byte[][] data) throws IOException {
  218. writeArrayHeader(TYPE_BYTE_ARRAY, data.length * data[0].length);
  219. for (int i = 0; i < data.length; i++)
  220. output.write(data[i]);
  221. if (flushing)
  222. output.flush();
  223. }
  224. //
  225. // Stream reading methods
  226. //
  227. /**
  228. * Helper method to automate reading the expected header information for
  229. * a serialized array, of any type.
  230. */
  231. private void readArrayHeader(byte type, int length) throws IOException {
  232. if (input == null)
  233. throw new IOException(ERROR_NO_INPUT);
  234. byte actualType = input.readByte();
  235. if (actualType != type)
  236. errorDataType(type, actualType);
  237. int actualLength = input.readInt();
  238. if (actualLength != length)
  239. errorDataSize(length, actualLength);
  240. }
  241. private int readArrayHeader(byte type, int length, boolean variableLength)
  242. throws IOException {
  243. if (input == null)
  244. throw new IOException(ERROR_NO_INPUT);
  245. byte actualType = input.readByte();
  246. if (actualType != type)
  247. errorDataType(type, actualType);
  248. int actualLength = input.readInt();
  249. if (variableLength && actualLength > length ||
  250. !variableLength && actualLength != length)
  251. errorDataSize(length, actualLength);
  252. return actualLength;
  253. }
  254. /**
  255. *
  256. */
  257. public synchronized int readInt() throws IOException {
  258. if (input == null)
  259. throw new IOException(ERROR_NO_INPUT);
  260. byte actualType = input.readByte();
  261. if (actualType != TYPE_INT)
  262. errorDataType(TYPE_INT, actualType);
  263. return input.readInt();
  264. }
  265. /**
  266. *
  267. */
  268. public synchronized byte readByte() throws IOException {
  269. if (input == null)
  270. throw new IOException(ERROR_NO_INPUT);
  271. byte actualType = input.readByte();
  272. if (actualType != TYPE_BYTE)
  273. errorDataType(TYPE_BYTE, actualType);
  274. return input.readByte();
  275. }
  276. /**
  277. * Read a serialized integer array from the input stream. Expects the
  278. * message to be prepended with the standard array header giving the
  279. * correct data type and length.
  280. */
  281. public synchronized void readInts(int[] data) throws IOException {
  282. readArrayHeader(TYPE_INT_ARRAY, data.length * SIZEOF_INT);
  283. for (int i = 0; i < data.length; i++)
  284. data[i] = input.readInt();
  285. }
  286. public synchronized int readInts(int[] data, boolean variableLength)
  287. throws IOException {
  288. int length = readArrayHeader(TYPE_INT_ARRAY, data.length * SIZEOF_INT,
  289. variableLength) / SIZEOF_INT;
  290. for (int i = 0; i < length; i++)
  291. data[i] = input.readInt();
  292. return length;
  293. }
  294. /**
  295. * Read a serialized two dimensional integer array from the output stream.
  296. * Expects the message to be prepended with the standard array header
  297. * giving the correct data type and length.
  298. */
  299. public synchronized void readInts(int[][] data) throws IOException {
  300. readArrayHeader(TYPE_INT_ARRAY,
  301. data.length * data[0].length * SIZEOF_INT);
  302. for (int i = 0; i < data.length; i++)
  303. for (int j = 0; j < data[0].length; j++)
  304. data[i][j] = input.readInt();
  305. }
  306. /**
  307. * Read a serialized double array from the input stream. Expects the
  308. * message to be prepended with the standard array header giving the
  309. * correct data type and length.
  310. */
  311. public synchronized void readFloats(float[] data) throws IOException {
  312. readArrayHeader(TYPE_FLOAT_ARRAY, data.length * SIZEOF_FLOAT);
  313. for (int i = 0; i < data.length; i++)
  314. data[i] = input.readFloat();
  315. }
  316. public synchronized int readFloats(float[] data, boolean variableLength)
  317. throws IOException {
  318. int length = readArrayHeader(TYPE_FLOAT_ARRAY, data.length * SIZEOF_FLOAT,
  319. variableLength) / SIZEOF_FLOAT;
  320. for (int i = 0; i < length; i++)
  321. data[i] = input.readFloat();
  322. return length;
  323. }
  324. /**
  325. * Read a serialized double array from the input stream. Expects the
  326. * message to be prepended with the standard array header giving the
  327. * correct data type and length.
  328. */
  329. public synchronized void readDoubles(double[] data) throws IOException {
  330. readArrayHeader(TYPE_DOUBLE_ARRAY, data.length * SIZEOF_DOUBLE);
  331. for (int i = 0; i < data.length; i++)
  332. data[i] = input.readDouble();
  333. }
  334. /**
  335. * Read a serialized two dimensional double array from the output stream.
  336. * Expects the message to be prepended with the standard array header
  337. * giving the correct data type and length.
  338. */
  339. public synchronized void readDoubles(double[][] data) throws IOException {
  340. readArrayHeader(TYPE_DOUBLE_ARRAY,
  341. data.length * data[0].length * SIZEOF_DOUBLE);
  342. for (int i = 0; i < data.length; i++)
  343. for (int j = 0; j < data[0].length; j++)
  344. data[i][j] = input.readDouble();
  345. }
  346. /**
  347. *
  348. */
  349. public synchronized void readBytes(byte[] data) throws IOException {
  350. readArrayHeader(TYPE_BYTE_ARRAY, data.length);
  351. input.readFully(data);
  352. }
  353. public synchronized int readBytes(byte[] data, boolean variableLength)
  354. throws IOException {
  355. int length = readArrayHeader(TYPE_BYTE_ARRAY, data.length,
  356. variableLength);
  357. input.readFully(data, 0, length);
  358. return length;
  359. }
  360. /**
  361. *
  362. */
  363. public synchronized void readBytes(byte[][] data) throws IOException {
  364. readArrayHeader(TYPE_BYTE_ARRAY, data.length * data[0].length);
  365. for (int i = 0; i < data.length; i++)
  366. input.readFully(data[i]);
  367. }
  368. private void errorDataSize(int expected, int received) throws IOException {
  369. throw new IOException(ERROR_DATASIZE + "\n Expected=" + expected +
  370. ", received=" + received);
  371. }
  372. private void errorDataType(int expected, int received) throws IOException {
  373. throw new StreamCorruptedException(ERROR_DATATYPE + "\n Expected=" +
  374. expected + ", received=" + received);
  375. }
  376. }