1 package org.sim0mq.message;
2
3 import java.nio.charset.Charset;
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import org.djunits.unit.MoneyPerAreaUnit;
8 import org.djunits.unit.MoneyPerDurationUnit;
9 import org.djunits.unit.MoneyPerEnergyUnit;
10 import org.djunits.unit.MoneyPerLengthUnit;
11 import org.djunits.unit.MoneyPerMassUnit;
12 import org.djunits.unit.MoneyPerVolumeUnit;
13 import org.djunits.unit.MoneyUnit;
14 import org.djunits.unit.Unit;
15 import org.djunits.value.StorageType;
16 import org.djunits.value.ValueException;
17 import org.djunits.value.vdouble.matrix.AbstractDoubleMatrix;
18 import org.djunits.value.vdouble.matrix.DoubleMatrixUtil;
19 import org.djunits.value.vdouble.scalar.AbstractDoubleScalar;
20 import org.djunits.value.vdouble.scalar.DoubleScalarUtil;
21 import org.djunits.value.vdouble.scalar.Money;
22 import org.djunits.value.vdouble.scalar.MoneyPerArea;
23 import org.djunits.value.vdouble.scalar.MoneyPerDuration;
24 import org.djunits.value.vdouble.scalar.MoneyPerEnergy;
25 import org.djunits.value.vdouble.scalar.MoneyPerLength;
26 import org.djunits.value.vdouble.scalar.MoneyPerMass;
27 import org.djunits.value.vdouble.scalar.MoneyPerVolume;
28 import org.djunits.value.vdouble.vector.AbstractDoubleVector;
29 import org.djunits.value.vdouble.vector.DoubleVectorUtil;
30 import org.djunits.value.vfloat.matrix.AbstractFloatMatrix;
31 import org.djunits.value.vfloat.matrix.FloatMatrixUtil;
32 import org.djunits.value.vfloat.scalar.AbstractFloatScalar;
33 import org.djunits.value.vfloat.scalar.FloatMoney;
34 import org.djunits.value.vfloat.scalar.FloatMoneyPerArea;
35 import org.djunits.value.vfloat.scalar.FloatMoneyPerDuration;
36 import org.djunits.value.vfloat.scalar.FloatMoneyPerEnergy;
37 import org.djunits.value.vfloat.scalar.FloatMoneyPerLength;
38 import org.djunits.value.vfloat.scalar.FloatMoneyPerMass;
39 import org.djunits.value.vfloat.scalar.FloatMoneyPerVolume;
40 import org.djunits.value.vfloat.scalar.FloatScalarUtil;
41 import org.djunits.value.vfloat.vector.AbstractFloatVector;
42 import org.djunits.value.vfloat.vector.FloatVectorUtil;
43 import org.sim0mq.Sim0MQException;
44 import org.sim0mq.message.types.Sim0MQDisplayType;
45 import org.sim0mq.message.types.Sim0MQTypes;
46 import org.sim0mq.message.types.Sim0MQUnitType;
47 import org.sim0mq.message.util.EndianUtil;
48
49 import nl.tudelft.simulation.language.Throw;
50
51
52
53
54
55
56
57
58
59
60
61 public final class TypedMessage
62 {
63
64 protected static final String VERSION = "SIM01";
65
66
67 protected static final int BYTE_HC = Byte.class.hashCode();
68
69
70 protected static final int SHORT_HC = Short.class.hashCode();
71
72
73 protected static final int INTEGER_HC = Integer.class.hashCode();
74
75
76 protected static final int LONG_HC = Long.class.hashCode();
77
78
79 protected static final int FLOAT_HC = Float.class.hashCode();
80
81
82 protected static final int DOUBLE_HC = Double.class.hashCode();
83
84
85 protected static final int BOOLEAN_HC = Boolean.class.hashCode();
86
87
88 protected static final int CHAR_HC = Character.class.hashCode();
89
90
91 protected static final int STRING_HC = String.class.hashCode();
92
93
94 protected static final int BYTE_ARRAY_HC = byte[].class.hashCode();
95
96
97 protected static final int SHORT_ARRAY_HC = short[].class.hashCode();
98
99
100 protected static final int INT_ARRAY_HC = int[].class.hashCode();
101
102
103 protected static final int LONG_ARRAY_HC = long[].class.hashCode();
104
105
106 protected static final int FLOAT_ARRAY_HC = float[].class.hashCode();
107
108
109 protected static final int DOUBLE_ARRAY_HC = double[].class.hashCode();
110
111
112 protected static final int BOOLEAN_ARRAY_HC = boolean[].class.hashCode();
113
114
115 protected static final int BYTE_MATRIX_HC = byte[][].class.hashCode();
116
117
118 protected static final int SHORT_MATRIX_HC = short[][].class.hashCode();
119
120
121 protected static final int INT_MATRIX_HC = int[][].class.hashCode();
122
123
124 protected static final int LONG_MATRIX_HC = long[][].class.hashCode();
125
126
127 protected static final int FLOAT_MATRIX_HC = float[][].class.hashCode();
128
129
130 protected static final int DOUBLE_MATRIX_HC = double[][].class.hashCode();
131
132
133 protected static final int BOOLEAN_MATRIX_HC = boolean[][].class.hashCode();
134
135
136 protected static final Charset UTF8 = Charset.forName("UTF-8");
137
138
139 protected static final Charset UTF16 = Charset.forName("UTF-16BE");
140
141
142
143
144 private TypedMessage()
145 {
146
147 }
148
149
150
151
152
153
154
155 public static byte[] encodeUTF8(final Object... content) throws Sim0MQException
156 {
157 return encode(true, false, content);
158 }
159
160
161
162
163
164
165
166 public static byte[] encodeUTF16(final Object... content) throws Sim0MQException
167 {
168 return encode(false, false, content);
169 }
170
171
172
173
174
175
176
177
178 public static byte[] encode0MQMessageUTF8(final Object... content) throws Sim0MQException
179 {
180 Throw.when(content.length == 0, Sim0MQException.class, "empty array to encode");
181 Throw.when(!(content[1] instanceof String), Sim0MQException.class, "first field in array is not a String");
182 return encode(true, false, content);
183 }
184
185
186
187
188
189
190
191
192 public static byte[] encode0MQMessageUTF16(final Object... content) throws Sim0MQException
193 {
194 Throw.when(content.length == 0, Sim0MQException.class, "empty array to encode");
195 Throw.when(!(content[1] instanceof String), Sim0MQException.class, "first field in array is not a String");
196 return encode(false, false, content);
197 }
198
199
200
201
202
203
204
205
206
207 @SuppressWarnings({ "checkstyle:methodlength", "checkstyle:needbraces" })
208 private static byte[] encode(final boolean utf8, final boolean firstUtf8, final Object... content) throws Sim0MQException
209 {
210 int size = 0;
211 for (int i = 0; i < content.length; i++)
212 {
213 size++;
214 int hc = content[i].getClass().hashCode();
215 if (hc == BYTE_HC)
216 size += 1;
217 else if (hc == SHORT_HC)
218 size += 2;
219 else if (hc == INTEGER_HC)
220 size += 4;
221 else if (hc == LONG_HC)
222 size += 8;
223 else if (hc == FLOAT_HC)
224 size += 4;
225 else if (hc == DOUBLE_HC)
226 size += 8;
227 else if (hc == BOOLEAN_HC)
228 size += 1;
229 else if (hc == CHAR_HC && utf8)
230 size += 1;
231 else if (hc == CHAR_HC && !utf8)
232 size += 2;
233 else if (hc == STRING_HC)
234 {
235 if (utf8 || (i == 0 && firstUtf8))
236 size += ((String) content[i]).length() + 4;
237 else
238 size += 2 * ((String) content[i]).length() + 4;
239 }
240 else if (hc == BYTE_ARRAY_HC)
241 size += ((byte[]) content[i]).length + 4;
242 else if (hc == SHORT_ARRAY_HC)
243 size += 2 * ((short[]) content[i]).length + 4;
244 else if (hc == INT_ARRAY_HC)
245 size += 4 * ((int[]) content[i]).length + 4;
246 else if (hc == LONG_ARRAY_HC)
247 size += 8 * ((long[]) content[i]).length + 4;
248 else if (hc == FLOAT_ARRAY_HC)
249 size += 4 * ((float[]) content[i]).length + 4;
250 else if (hc == DOUBLE_ARRAY_HC)
251 size += 8 * ((double[]) content[i]).length + 4;
252 else if (hc == BOOLEAN_ARRAY_HC)
253 size += ((boolean[]) content[i]).length + 4;
254 else if (hc == BYTE_MATRIX_HC)
255 size += ((byte[][]) content[i]).length * ((byte[][]) content[i])[0].length + 8;
256 else if (hc == SHORT_MATRIX_HC)
257 size += 2 * ((short[][]) content[i]).length * ((short[][]) content[i])[0].length + 8;
258 else if (hc == INT_MATRIX_HC)
259 size += 4 * ((int[][]) content[i]).length * ((int[][]) content[i])[0].length + 8;
260 else if (hc == LONG_MATRIX_HC)
261 size += 8 * ((long[][]) content[i]).length * ((long[][]) content[i])[0].length + 8;
262 else if (hc == FLOAT_MATRIX_HC)
263 size += 4 * ((float[][]) content[i]).length * ((float[][]) content[i])[0].length + 8;
264 else if (hc == DOUBLE_MATRIX_HC)
265 size += 8 * ((double[][]) content[i]).length * ((double[][]) content[i])[0].length + 8;
266 else if (hc == BOOLEAN_MATRIX_HC)
267 size += ((boolean[][]) content[i]).length * ((boolean[][]) content[i])[0].length + 8;
268 else if (content[i] instanceof AbstractFloatScalar)
269 size += 6 + extraBytesMoney(content[i]);
270 else if (content[i] instanceof AbstractDoubleScalar)
271 size += 10 + extraBytesMoney(content[i]);
272 else if (content[i] instanceof AbstractFloatVector)
273 {
274 AbstractFloatVector<?, ?> afv = (AbstractFloatVector<?, ?>) content[i];
275 try
276 {
277 size += 4 + 2 + extraBytesMoney(afv.get(0)) + 4 * afv.size();
278 }
279 catch (ValueException exception)
280 {
281 throw new Sim0MQException(exception);
282 }
283 }
284 else if (content[i] instanceof AbstractDoubleVector)
285 {
286 AbstractDoubleVector<?, ?> adv = (AbstractDoubleVector<?, ?>) content[i];
287 try
288 {
289 size += 4 + 2 + extraBytesMoney(adv.get(0)) + 8 * adv.size();
290 }
291 catch (ValueException exception)
292 {
293 throw new Sim0MQException(exception);
294 }
295 }
296 else if (content[i] instanceof AbstractFloatMatrix)
297 {
298 AbstractFloatMatrix<?, ?> afm = (AbstractFloatMatrix<?, ?>) content[i];
299 try
300 {
301 size += 4 + 4 + 2 + extraBytesMoney(afm.get(0, 0)) + 4 * afm.rows() * afm.columns();
302 }
303 catch (ValueException exception)
304 {
305 throw new Sim0MQException(exception);
306 }
307 }
308 else if (content[i] instanceof AbstractDoubleMatrix)
309 {
310 AbstractDoubleMatrix<?, ?> adm = (AbstractDoubleMatrix<?, ?>) content[i];
311 try
312 {
313 size += 4 + 4 + 2 + extraBytesMoney(adm.get(0, 0)) + 8 * adm.rows() * adm.columns();
314 }
315 catch (ValueException exception)
316 {
317 throw new Sim0MQException(exception);
318 }
319 }
320 else if (content[i] instanceof AbstractFloatVector[])
321 {
322 AbstractFloatVector<?, ?>[] afvArray = (AbstractFloatVector<?, ?>[]) content[i];
323 try
324 {
325 size += 4 + 4;
326 for (int j = 0; j < afvArray.length; j++)
327 {
328 size += 2 + extraBytesMoney(afvArray[j].get(0)) + 4 * afvArray[j].size();
329 }
330 }
331 catch (ValueException exception)
332 {
333 throw new Sim0MQException(exception);
334 }
335 }
336 else if (content[i] instanceof AbstractDoubleVector[])
337 {
338 AbstractDoubleVector<?, ?>[] afvArray = (AbstractDoubleVector<?, ?>[]) content[i];
339 try
340 {
341 size += 4 + 4;
342 for (int j = 0; j < afvArray.length; j++)
343 {
344 size += 2 + extraBytesMoney(afvArray[j].get(0)) + 8 * afvArray[j].size();
345 }
346 }
347 catch (ValueException exception)
348 {
349 throw new Sim0MQException(exception);
350 }
351 }
352 else
353 throw new Sim0MQException("Unknown data type " + content[i].getClass() + " for encoding the ZeroMQ message");
354 }
355
356 byte[] message = new byte[size];
357 int pointer = 0;
358
359 for (int i = 0; i < content.length; i++)
360 {
361 Object field = content[i];
362 int hc = field.getClass().hashCode();
363
364 if (hc == BYTE_HC)
365 {
366 message[pointer++] = Sim0MQTypes.BYTE_8;
367 message[pointer++] = (byte) field;
368 }
369
370 else if (hc == SHORT_HC)
371 {
372 message[pointer++] = Sim0MQTypes.SHORT_16;
373 short v = (short) field;
374 pointer = EndianUtil.encodeShort(v, message, pointer);
375 }
376
377 else if (hc == INTEGER_HC)
378 {
379 message[pointer++] = Sim0MQTypes.INT_32;
380 int v = (int) field;
381 pointer = EndianUtil.encodeInt(v, message, pointer);
382 }
383
384 else if (hc == LONG_HC)
385 {
386 message[pointer++] = Sim0MQTypes.LONG_64;
387 long v = (long) field;
388 pointer = EndianUtil.encodeLong(v, message, pointer);
389 }
390
391 else if (hc == FLOAT_HC)
392 {
393 message[pointer++] = Sim0MQTypes.FLOAT_32;
394 float v = (float) field;
395 pointer = EndianUtil.encodeFloat(v, message, pointer);
396 }
397
398 else if (hc == DOUBLE_HC)
399 {
400 message[pointer++] = Sim0MQTypes.DOUBLE_64;
401 double v = (double) field;
402 pointer = EndianUtil.encodeDouble(v, message, pointer);
403 }
404
405 else if (hc == BOOLEAN_HC)
406 {
407 message[pointer++] = Sim0MQTypes.BOOLEAN_8;
408 message[pointer++] = (byte) ((boolean) field ? 1 : 0);
409 }
410
411 else if (hc == CHAR_HC && utf8)
412 {
413 message[pointer++] = Sim0MQTypes.CHAR_8;
414 char v = (char) field;
415 message[pointer++] = (byte) (v & 0xFF);
416 }
417
418 else if (hc == CHAR_HC && !utf8)
419 {
420 message[pointer++] = Sim0MQTypes.CHAR_16;
421 char v = (char) field;
422 pointer = EndianUtil.encodeChar(v, message, pointer);
423 }
424
425 else if (hc == STRING_HC && utf8)
426 {
427 message[pointer++] = Sim0MQTypes.STRING_8;
428 int len = ((String) field).length();
429 pointer = EndianUtil.encodeInt(len, message, pointer);
430 byte[] s = ((String) field).getBytes(UTF8);
431 for (byte b : s)
432 {
433 message[pointer++] = b;
434 }
435 }
436
437 else if (hc == STRING_HC && !utf8)
438 {
439 message[pointer++] = Sim0MQTypes.STRING_16;
440 int len = ((String) field).length();
441 pointer = EndianUtil.encodeInt(len, message, pointer);
442 byte[] s = ((String) field).getBytes(UTF16);
443 for (byte b : s)
444 {
445 message[pointer++] = b;
446 }
447 }
448
449 else if (hc == BYTE_ARRAY_HC)
450 {
451 message[pointer++] = Sim0MQTypes.BYTE_8_ARRAY;
452 int len = ((byte[]) field).length;
453 pointer = EndianUtil.encodeInt(len, message, pointer);
454 for (byte v : (byte[]) field)
455 {
456 message[pointer++] = v;
457 }
458 }
459
460 else if (hc == SHORT_ARRAY_HC)
461 {
462 message[pointer++] = Sim0MQTypes.SHORT_16_ARRAY;
463 int len = ((short[]) field).length;
464 pointer = EndianUtil.encodeInt(len, message, pointer);
465 for (short v : (short[]) field)
466 {
467 pointer = EndianUtil.encodeShort(v, message, pointer);
468 }
469 }
470
471 else if (hc == INT_ARRAY_HC)
472 {
473 message[pointer++] = Sim0MQTypes.INT_32_ARRAY;
474 int len = ((int[]) field).length;
475 pointer = EndianUtil.encodeInt(len, message, pointer);
476 for (int v : (int[]) field)
477 {
478 pointer = EndianUtil.encodeInt(v, message, pointer);
479 }
480 }
481
482 else if (hc == LONG_ARRAY_HC)
483 {
484 message[pointer++] = Sim0MQTypes.LONG_64_ARRAY;
485 int len = ((long[]) field).length;
486 pointer = EndianUtil.encodeInt(len, message, pointer);
487 for (long v : (long[]) field)
488 {
489 pointer = EndianUtil.encodeLong(v, message, pointer);
490 }
491 }
492
493 else if (hc == FLOAT_ARRAY_HC)
494 {
495 message[pointer++] = Sim0MQTypes.FLOAT_32_ARRAY;
496 int len = ((float[]) field).length;
497 pointer = EndianUtil.encodeInt(len, message, pointer);
498 for (float v : (float[]) field)
499 {
500 pointer = EndianUtil.encodeFloat(v, message, pointer);
501 }
502 }
503
504 else if (hc == DOUBLE_ARRAY_HC)
505 {
506 message[pointer++] = Sim0MQTypes.DOUBLE_64_ARRAY;
507 int len = ((double[]) field).length;
508 pointer = EndianUtil.encodeInt(len, message, pointer);
509 for (double v : (double[]) field)
510 {
511 pointer = EndianUtil.encodeDouble(v, message, pointer);
512 }
513 }
514
515 else if (hc == BOOLEAN_ARRAY_HC)
516 {
517 message[pointer++] = Sim0MQTypes.BOOLEAN_8_ARRAY;
518 int len = ((boolean[]) field).length;
519 pointer = EndianUtil.encodeInt(len, message, pointer);
520 for (boolean v : (boolean[]) field)
521 {
522 message[pointer++] = (byte) (v ? 1 : 0);
523 }
524 }
525
526 else if (hc == BYTE_MATRIX_HC)
527 {
528 message[pointer++] = Sim0MQTypes.BYTE_8_MATRIX;
529 byte[][] matrix = (byte[][]) field;
530 int rows = matrix.length;
531 pointer = EndianUtil.encodeInt(rows, message, pointer);
532 int cols = matrix[0].length;
533 pointer = EndianUtil.encodeInt(cols, message, pointer);
534 for (int row = 0; row < rows; row++)
535 {
536 byte[] vRow = matrix[row];
537 for (byte v : vRow)
538 {
539 message[pointer++] = v;
540 }
541 }
542 }
543
544 else if (hc == SHORT_MATRIX_HC)
545 {
546 message[pointer++] = Sim0MQTypes.SHORT_16_MATRIX;
547 short[][] matrix = (short[][]) field;
548 int rows = matrix.length;
549 pointer = EndianUtil.encodeInt(rows, message, pointer);
550 int cols = matrix[0].length;
551 pointer = EndianUtil.encodeInt(cols, message, pointer);
552 for (int row = 0; row < rows; row++)
553 {
554 short[] vRow = matrix[row];
555 for (short v : vRow)
556 {
557 pointer = EndianUtil.encodeShort(v, message, pointer);
558 }
559 }
560 }
561
562 else if (hc == INT_MATRIX_HC)
563 {
564 message[pointer++] = Sim0MQTypes.INT_32_MATRIX;
565 int[][] matrix = (int[][]) field;
566 int rows = matrix.length;
567 pointer = EndianUtil.encodeInt(rows, message, pointer);
568 int cols = matrix[0].length;
569 pointer = EndianUtil.encodeInt(cols, message, pointer);
570 for (int row = 0; row < rows; row++)
571 {
572 int[] vRow = matrix[row];
573 for (int v : vRow)
574 {
575 pointer = EndianUtil.encodeInt(v, message, pointer);
576 }
577 }
578 }
579
580 else if (hc == LONG_MATRIX_HC)
581 {
582 message[pointer++] = Sim0MQTypes.LONG_64_MATRIX;
583 long[][] matrix = (long[][]) field;
584 int rows = matrix.length;
585 pointer = EndianUtil.encodeInt(rows, message, pointer);
586 int cols = matrix[0].length;
587 pointer = EndianUtil.encodeInt(cols, message, pointer);
588 for (int row = 0; row < rows; row++)
589 {
590 long[] vRow = matrix[row];
591 for (long v : vRow)
592 {
593 pointer = EndianUtil.encodeLong(v, message, pointer);
594 }
595 }
596 }
597
598 else if (hc == FLOAT_MATRIX_HC)
599 {
600 message[pointer++] = Sim0MQTypes.FLOAT_32_MATRIX;
601 float[][] matrix = (float[][]) field;
602 int rows = matrix.length;
603 pointer = EndianUtil.encodeInt(rows, message, pointer);
604 int cols = matrix[0].length;
605 pointer = EndianUtil.encodeInt(cols, message, pointer);
606 for (int row = 0; row < rows; row++)
607 {
608 float[] vRow = matrix[row];
609 for (float v : vRow)
610 {
611 pointer = EndianUtil.encodeFloat(v, message, pointer);
612 }
613 }
614 }
615
616 else if (hc == DOUBLE_MATRIX_HC)
617 {
618 message[pointer++] = Sim0MQTypes.DOUBLE_64_MATRIX;
619 double[][] matrix = (double[][]) field;
620 int rows = matrix.length;
621 pointer = EndianUtil.encodeInt(rows, message, pointer);
622 int cols = matrix[0].length;
623 pointer = EndianUtil.encodeInt(cols, message, pointer);
624 for (int row = 0; row < rows; row++)
625 {
626 double[] vRow = matrix[row];
627 for (double v : vRow)
628 {
629 pointer = EndianUtil.encodeDouble(v, message, pointer);
630 }
631 }
632 }
633
634 else if (hc == BOOLEAN_MATRIX_HC)
635 {
636 message[pointer++] = Sim0MQTypes.BOOLEAN_8_MATRIX;
637 boolean[][] matrix = (boolean[][]) field;
638 int rows = matrix.length;
639 pointer = EndianUtil.encodeInt(rows, message, pointer);
640 int cols = matrix[0].length;
641 pointer = EndianUtil.encodeInt(cols, message, pointer);
642 for (int row = 0; row < rows; row++)
643 {
644 boolean[] vRow = matrix[row];
645 for (boolean v : vRow)
646 {
647 message[pointer++] = (byte) (v ? 1 : 0);
648 }
649 }
650 }
651
652 else if (field instanceof AbstractFloatScalar)
653 {
654 message[pointer++] = Sim0MQTypes.FLOAT_32_UNIT;
655 pointer = encodeUnit(((AbstractFloatScalar<?, ?>) field).getUnit(), message, pointer);
656 float v = ((AbstractFloatScalar<?, ?>) field).si;
657 pointer = EndianUtil.encodeFloat(v, message, pointer);
658 }
659
660 else if (content[i] instanceof AbstractDoubleScalar)
661 {
662 message[pointer++] = Sim0MQTypes.DOUBLE_64_UNIT;
663 pointer = encodeUnit(((AbstractDoubleScalar<?, ?>) field).getUnit(), message, pointer);
664 double v = ((AbstractDoubleScalar<?, ?>) field).si;
665 pointer = EndianUtil.encodeDouble(v, message, pointer);
666 }
667
668 else if (content[i] instanceof AbstractFloatVector)
669 {
670 message[pointer++] = Sim0MQTypes.FLOAT_32_UNIT_ARRAY;
671 AbstractFloatVector<?, ?> afv = (AbstractFloatVector<?, ?>) content[i];
672 pointer = EndianUtil.encodeInt(afv.size(), message, pointer);
673 pointer = encodeUnit(afv.getUnit(), message, pointer);
674 try
675 {
676 for (int j = 0; j < afv.size(); j++)
677 {
678 pointer = EndianUtil.encodeFloat(afv.getSI(j), message, pointer);
679 }
680 }
681 catch (ValueException exception)
682 {
683 throw new Sim0MQException(exception);
684 }
685 }
686
687 else if (content[i] instanceof AbstractDoubleVector)
688 {
689 message[pointer++] = Sim0MQTypes.DOUBLE_64_UNIT_ARRAY;
690 AbstractDoubleVector<?, ?> adv = (AbstractDoubleVector<?, ?>) content[i];
691 pointer = EndianUtil.encodeInt(adv.size(), message, pointer);
692 pointer = encodeUnit(adv.getUnit(), message, pointer);
693 try
694 {
695 for (int j = 0; j < adv.size(); j++)
696 {
697 pointer = EndianUtil.encodeDouble(adv.getSI(j), message, pointer);
698 }
699 }
700 catch (ValueException exception)
701 {
702 throw new Sim0MQException(exception);
703 }
704 }
705
706 else if (content[i] instanceof AbstractFloatMatrix)
707 {
708 message[pointer++] = Sim0MQTypes.FLOAT_32_UNIT_MATRIX;
709 AbstractFloatMatrix<?, ?> afm = (AbstractFloatMatrix<?, ?>) content[i];
710 pointer = EndianUtil.encodeInt(afm.rows(), message, pointer);
711 pointer = EndianUtil.encodeInt(afm.columns(), message, pointer);
712 pointer = encodeUnit(afm.getUnit(), message, pointer);
713 try
714 {
715 for (int row = 0; row < afm.rows(); row++)
716 {
717 for (int col = 0; col < afm.columns(); col++)
718 {
719 pointer = EndianUtil.encodeFloat(afm.getSI(row, col), message, pointer);
720 }
721 }
722 }
723 catch (ValueException exception)
724 {
725 throw new Sim0MQException(exception);
726 }
727 }
728
729 else if (content[i] instanceof AbstractDoubleMatrix)
730 {
731 message[pointer++] = Sim0MQTypes.DOUBLE_64_UNIT_MATRIX;
732 AbstractDoubleMatrix<?, ?> adm = (AbstractDoubleMatrix<?, ?>) content[i];
733 pointer = EndianUtil.encodeInt(adm.rows(), message, pointer);
734 pointer = EndianUtil.encodeInt(adm.columns(), message, pointer);
735 pointer = encodeUnit(adm.getUnit(), message, pointer);
736 try
737 {
738 for (int row = 0; row < adm.rows(); row++)
739 {
740 for (int col = 0; col < adm.columns(); col++)
741 {
742 pointer = EndianUtil.encodeDouble(adm.getSI(row, col), message, pointer);
743 }
744 }
745 }
746 catch (ValueException exception)
747 {
748 throw new Sim0MQException(exception);
749 }
750 }
751
752 else if (content[i] instanceof AbstractFloatVector[])
753 {
754 message[pointer++] = Sim0MQTypes.FLOAT_32_UNIT_COLUMN_ARRAY;
755 AbstractFloatVector<?, ?>[] afvArray = (AbstractFloatVector<?, ?>[]) content[i];
756 pointer = EndianUtil.encodeInt(afvArray[0].size(), message, pointer);
757 pointer = EndianUtil.encodeInt(afvArray.length, message, pointer);
758 for (int col = 0; col < afvArray.length; col++)
759 {
760 pointer = encodeUnit(afvArray[col].getUnit(), message, pointer);
761 }
762 try
763 {
764 for (int row = 0; row < afvArray[0].size(); row++)
765 {
766 for (int col = 0; col < afvArray.length; col++)
767 {
768 pointer = EndianUtil.encodeFloat(afvArray[col].getSI(row), message, pointer);
769 }
770 }
771 }
772 catch (ValueException exception)
773 {
774 throw new Sim0MQException(exception);
775 }
776 }
777
778 else if (content[i] instanceof AbstractDoubleVector[])
779 {
780 message[pointer++] = Sim0MQTypes.DOUBLE_64_UNIT_COLUMN_ARRAY;
781 AbstractDoubleVector<?, ?>[] advArray = (AbstractDoubleVector<?, ?>[]) content[i];
782 pointer = EndianUtil.encodeInt(advArray[0].size(), message, pointer);
783 pointer = EndianUtil.encodeInt(advArray.length, message, pointer);
784 for (int col = 0; col < advArray.length; col++)
785 {
786 pointer = encodeUnit(advArray[col].getUnit(), message, pointer);
787 }
788 try
789 {
790 for (int row = 0; row < advArray[0].size(); row++)
791 {
792 for (int col = 0; col < advArray.length; col++)
793 {
794 pointer = EndianUtil.encodeDouble(advArray[col].getSI(row), message, pointer);
795 }
796 }
797 }
798 catch (ValueException exception)
799 {
800 throw new Sim0MQException(exception);
801 }
802 }
803
804 else
805 throw new Sim0MQException("Unknown data type " + content[i].getClass() + " for encoding the ZeroMQ message");
806
807 }
808
809 return message;
810 }
811
812
813
814
815
816
817
818
819 @SuppressWarnings("rawtypes")
820 private static int encodeUnit(final Unit unit, final byte[] message, final int pointer)
821 {
822 int p = pointer;
823 @SuppressWarnings("unchecked")
824 Sim0MQUnitType unitType = Sim0MQUnitType.getUnitType(unit);
825 message[p++] = unitType.getCode();
826 if (unit instanceof MoneyUnit)
827 {
828 @SuppressWarnings("unchecked")
829 Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(unit);
830 p = EndianUtil.encodeShort((short) displayType.getIntCode(), message, p);
831 }
832 else if (unit instanceof MoneyPerAreaUnit)
833 {
834 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerAreaUnit) unit).getMoneyUnit());
835 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
836 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerAreaUnit) unit).getAreaUnit());
837 message[p++] = perType.getByteCode();
838 }
839 else if (unit instanceof MoneyPerEnergyUnit)
840 {
841 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerEnergyUnit) unit).getMoneyUnit());
842 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
843 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerEnergyUnit) unit).getEnergyUnit());
844 message[p++] = perType.getByteCode();
845 }
846 else if (unit instanceof MoneyPerLengthUnit)
847 {
848 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerLengthUnit) unit).getMoneyUnit());
849 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
850 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerLengthUnit) unit).getLengthUnit());
851 message[p++] = perType.getByteCode();
852 }
853 else if (unit instanceof MoneyPerMassUnit)
854 {
855 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerMassUnit) unit).getMoneyUnit());
856 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
857 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerMassUnit) unit).getMassUnit());
858 message[p++] = perType.getByteCode();
859 }
860 else if (unit instanceof MoneyPerDurationUnit)
861 {
862 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerDurationUnit) unit).getMoneyUnit());
863 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
864 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerDurationUnit) unit).getDurationUnit());
865 message[p++] = perType.getByteCode();
866 }
867 else if (unit instanceof MoneyPerVolumeUnit)
868 {
869 Sim0MQDisplayType moneyType = Sim0MQDisplayType.getDisplayType(((MoneyPerVolumeUnit) unit).getMoneyUnit());
870 p = EndianUtil.encodeShort((short) moneyType.getIntCode(), message, p);
871 Sim0MQDisplayType perType = Sim0MQDisplayType.getDisplayType(((MoneyPerVolumeUnit) unit).getVolumeUnit());
872 message[p++] = perType.getByteCode();
873 }
874 else
875 {
876 @SuppressWarnings("unchecked")
877 Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(unit);
878 message[p++] = displayType.getByteCode();
879 }
880 return p;
881 }
882
883
884
885
886
887
888
889 @SuppressWarnings({ "checkstyle:methodlength", "checkstyle:needbraces" })
890 public static Object[] decodeSim0MQMessage(final byte[] message) throws Sim0MQException
891 {
892 Throw.when(message.length < 10, Sim0MQException.class, "Message length < 10");
893 Object[] array = decode(message);
894
895
896 byte char0 = message[0];
897 Throw.when(char0 != 9, Sim0MQException.class, "Message does not start with an UTF8 string");
898 int magicLen = EndianUtil.decodeInt(message, 1);
899 Throw.when(magicLen < 0, Sim0MQException.class, "Length of magic number < 0");
900 Throw.when(Double.isNaN(magicLen), Sim0MQException.class, "Length of magic number = NaN");
901 Throw.when(Double.isInfinite(magicLen), Sim0MQException.class, "Length of magic number = Infinite");
902 Throw.when(magicLen > 10, Sim0MQException.class, "Length of magic number > 10");
903 String magicNumber = EndianUtil.decodeUTF8String(message, 1);
904 Throw.when(!magicNumber.startsWith("SIM"), Sim0MQException.class,
905 "Magic number does not start with SIM but with " + magicNumber);
906 Throw.when(!magicNumber.equals(VERSION), Sim0MQException.class,
907 "Message version " + magicNumber + " not compatible with this software version " + VERSION);
908
909 return array;
910 }
911
912
913
914
915
916
917
918 @SuppressWarnings({ "checkstyle:methodlength", "checkstyle:needbraces" })
919 public static Object[] decode(final byte[] message) throws Sim0MQException
920 {
921 List<Object> list = new ArrayList<>();
922 MessageBuffer mb = new MessageBuffer(message);
923 while (mb.hasMore())
924 {
925 byte type = mb.getByte();
926
927 if (type == Sim0MQTypes.BYTE_8)
928 {
929 list.add(mb.getByte());
930 }
931
932 else if (type == Sim0MQTypes.SHORT_16)
933 {
934 list.add(mb.getShort());
935 }
936
937 else if (type == Sim0MQTypes.INT_32)
938 {
939 list.add(mb.getInt());
940 }
941
942 else if (type == Sim0MQTypes.LONG_64)
943 {
944 list.add(mb.getLong());
945 }
946
947 else if (type == Sim0MQTypes.FLOAT_32)
948 {
949 list.add(mb.getFloat());
950 }
951
952 else if (type == Sim0MQTypes.DOUBLE_64)
953 {
954 list.add(mb.getDouble());
955 }
956
957 else if (type == Sim0MQTypes.BOOLEAN_8)
958 {
959 list.add(mb.getBoolean());
960 }
961
962 else if (type == Sim0MQTypes.CHAR_8)
963 {
964 list.add(mb.getCharUTF8());
965 }
966
967 else if (type == Sim0MQTypes.CHAR_16)
968 {
969 list.add(mb.getCharUTF16());
970 }
971
972 else if (type == Sim0MQTypes.STRING_8)
973 {
974 list.add(mb.getStringUTF8());
975 }
976
977 else if (type == Sim0MQTypes.STRING_16)
978 {
979 list.add(mb.getStringUTF16());
980 }
981
982 else if (type == Sim0MQTypes.BYTE_8_ARRAY)
983 {
984 int size = mb.getInt();
985 byte[] value = new byte[size];
986 for (int i = 0; i < size; i++)
987 value[i] = mb.getByte();
988 list.add(value);
989 }
990
991 else if (type == Sim0MQTypes.SHORT_16_ARRAY)
992 {
993 int size = mb.getInt();
994 short[] value = new short[size];
995 for (int i = 0; i < size; i++)
996 value[i] = mb.getShort();
997 list.add(value);
998 }
999
1000 else if (type == Sim0MQTypes.INT_32_ARRAY)
1001 {
1002 int size = mb.getInt();
1003 int[] value = new int[size];
1004 for (int i = 0; i < size; i++)
1005 value[i] = mb.getInt();
1006 list.add(value);
1007 }
1008
1009 else if (type == Sim0MQTypes.LONG_64_ARRAY)
1010 {
1011 int size = mb.getInt();
1012 long[] value = new long[size];
1013 for (int i = 0; i < size; i++)
1014 value[i] = mb.getLong();
1015 list.add(value);
1016 }
1017
1018 else if (type == Sim0MQTypes.FLOAT_32_ARRAY)
1019 {
1020 int size = mb.getInt();
1021 float[] value = new float[size];
1022 for (int i = 0; i < size; i++)
1023 value[i] = mb.getFloat();
1024 list.add(value);
1025 }
1026
1027 else if (type == Sim0MQTypes.DOUBLE_64_ARRAY)
1028 {
1029 int size = mb.getInt();
1030 double[] value = new double[size];
1031 for (int i = 0; i < size; i++)
1032 value[i] = mb.getDouble();
1033 list.add(value);
1034 }
1035
1036 else if (type == Sim0MQTypes.BOOLEAN_8_ARRAY)
1037 {
1038 int size = mb.getInt();
1039 boolean[] value = new boolean[size];
1040 for (int i = 0; i < size; i++)
1041 value[i] = mb.getBoolean();
1042 list.add(value);
1043 }
1044
1045 else if (type == Sim0MQTypes.BYTE_8_MATRIX)
1046 {
1047 int rows = mb.getInt();
1048 int cols = mb.getInt();
1049 byte[][] value = new byte[rows][];
1050 for (int row = 0; row < rows; row++)
1051 {
1052 for (int col = 0; col < cols; col++)
1053 {
1054 if (col == 0)
1055 value[row] = new byte[cols];
1056 value[row][col] = mb.getByte();
1057 }
1058 }
1059 list.add(value);
1060 }
1061
1062 else if (type == Sim0MQTypes.SHORT_16_MATRIX)
1063 {
1064 int rows = mb.getInt();
1065 int cols = mb.getInt();
1066 short[][] value = new short[rows][];
1067 for (int row = 0; row < rows; row++)
1068 {
1069 for (int col = 0; col < cols; col++)
1070 {
1071 if (col == 0)
1072 value[row] = new short[cols];
1073 value[row][col] = mb.getShort();
1074 }
1075 }
1076 list.add(value);
1077 }
1078
1079 else if (type == Sim0MQTypes.INT_32_MATRIX)
1080 {
1081 int rows = mb.getInt();
1082 int cols = mb.getInt();
1083 int[][] value = new int[rows][];
1084 for (int row = 0; row < rows; row++)
1085 {
1086 for (int col = 0; col < cols; col++)
1087 {
1088 if (col == 0)
1089 value[row] = new int[cols];
1090 value[row][col] = mb.getInt();
1091 }
1092 }
1093 list.add(value);
1094 }
1095
1096 else if (type == Sim0MQTypes.LONG_64_MATRIX)
1097 {
1098 int rows = mb.getInt();
1099 int cols = mb.getInt();
1100 long[][] value = new long[rows][];
1101 for (int row = 0; row < rows; row++)
1102 {
1103 for (int col = 0; col < cols; col++)
1104 {
1105 if (col == 0)
1106 value[row] = new long[cols];
1107 value[row][col] = mb.getLong();
1108 }
1109 }
1110 list.add(value);
1111 }
1112
1113 else if (type == Sim0MQTypes.FLOAT_32_MATRIX)
1114 {
1115 int rows = mb.getInt();
1116 int cols = mb.getInt();
1117 float[][] value = new float[rows][];
1118 for (int row = 0; row < rows; row++)
1119 {
1120 for (int col = 0; col < cols; col++)
1121 {
1122 if (col == 0)
1123 value[row] = new float[cols];
1124 value[row][col] = mb.getFloat();
1125 }
1126 }
1127 list.add(value);
1128 }
1129
1130 else if (type == Sim0MQTypes.DOUBLE_64_MATRIX)
1131 {
1132 int rows = mb.getInt();
1133 int cols = mb.getInt();
1134 double[][] value = new double[rows][];
1135 for (int row = 0; row < rows; row++)
1136 {
1137 for (int col = 0; col < cols; col++)
1138 {
1139 if (col == 0)
1140 value[row] = new double[cols];
1141 value[row][col] = mb.getDouble();
1142 }
1143 }
1144 list.add(value);
1145 }
1146
1147 else if (type == Sim0MQTypes.BOOLEAN_8_MATRIX)
1148 {
1149 int rows = mb.getInt();
1150 int cols = mb.getInt();
1151 boolean[][] value = new boolean[rows][];
1152 for (int row = 0; row < rows; row++)
1153 {
1154 for (int col = 0; col < cols; col++)
1155 {
1156 if (col == 0)
1157 value[row] = new boolean[cols];
1158 value[row][col] = mb.getBoolean();
1159 }
1160 }
1161 list.add(value);
1162 }
1163
1164 else if (type == Sim0MQTypes.FLOAT_32_UNIT)
1165 {
1166 Unit<? extends Unit<?>> unit = mb.getUnit();
1167 float si = mb.getFloat();
1168 list.add(FloatScalarUtil.instantiateAnonymousSI(si, unit));
1169 }
1170
1171 else if (type == Sim0MQTypes.DOUBLE_64_UNIT)
1172 {
1173 Unit<? extends Unit<?>> unit = mb.getUnit();
1174 double si = mb.getDouble();
1175 list.add(DoubleScalarUtil.instantiateAnonymousSI(si, unit));
1176 }
1177
1178 else if (type == Sim0MQTypes.FLOAT_32_UNIT_ARRAY)
1179 {
1180 int size = mb.getInt();
1181 Unit<? extends Unit<?>> unit = mb.getUnit();
1182 float[] array = new float[size];
1183 for (int i = 0; i < size; i++)
1184 array[i] = mb.getFloat();
1185 try
1186 {
1187 list.add(FloatVectorUtil.instantiateAnonymousSI(array, unit, StorageType.DENSE));
1188 }
1189 catch (ValueException exception)
1190 {
1191 throw new Sim0MQException(exception);
1192 }
1193 }
1194
1195 else if (type == Sim0MQTypes.DOUBLE_64_UNIT_ARRAY)
1196 {
1197 int size = mb.getInt();
1198 Unit<? extends Unit<?>> unit = mb.getUnit();
1199 double[] array = new double[size];
1200 for (int i = 0; i < size; i++)
1201 array[i] = mb.getDouble();
1202 try
1203 {
1204 list.add(DoubleVectorUtil.instantiateAnonymousSI(array, unit, StorageType.DENSE));
1205 }
1206 catch (ValueException exception)
1207 {
1208 throw new Sim0MQException(exception);
1209 }
1210 }
1211
1212 else if (type == Sim0MQTypes.FLOAT_32_UNIT_MATRIX)
1213 {
1214 int rows = mb.getInt();
1215 int cols = mb.getInt();
1216 Unit<? extends Unit<?>> unit = mb.getUnit();
1217 float[][] matrix = new float[rows][cols];
1218 for (int row = 0; row < rows; row++)
1219 {
1220 for (int col = 0; col < cols; col++)
1221 {
1222 if (col == 0)
1223 matrix[row] = new float[cols];
1224 matrix[row][col] = mb.getFloat();
1225 }
1226 }
1227 try
1228 {
1229 list.add(FloatMatrixUtil.instantiateAnonymousSI(matrix, unit, StorageType.DENSE));
1230 }
1231 catch (ValueException exception)
1232 {
1233 throw new Sim0MQException(exception);
1234 }
1235 }
1236
1237 else if (type == Sim0MQTypes.DOUBLE_64_UNIT_MATRIX)
1238 {
1239 int rows = mb.getInt();
1240 int cols = mb.getInt();
1241 Unit<? extends Unit<?>> unit = mb.getUnit();
1242 double[][] matrix = new double[rows][cols];
1243 for (int row = 0; row < rows; row++)
1244 {
1245 for (int col = 0; col < cols; col++)
1246 {
1247 if (col == 0)
1248 matrix[row] = new double[cols];
1249 matrix[row][col] = mb.getDouble();
1250 }
1251 }
1252 try
1253 {
1254 list.add(DoubleMatrixUtil.instantiateAnonymousSI(matrix, unit, StorageType.DENSE));
1255 }
1256 catch (ValueException exception)
1257 {
1258 throw new Sim0MQException(exception);
1259 }
1260 }
1261
1262 else if (type == Sim0MQTypes.FLOAT_32_UNIT_COLUMN_ARRAY)
1263 {
1264 int rows = mb.getInt();
1265 int cols = mb.getInt();
1266 Unit<? extends Unit<?>>[] units = new Unit<?>[cols];
1267 AbstractFloatVector<?, ?>[] vArray = new AbstractFloatVector[cols];
1268 for (int col = 0; col < cols; col++)
1269 {
1270 units[col] = mb.getUnit();
1271 }
1272
1273 float[][] matrix = new float[cols][rows];
1274 for (int row = 0; row < rows; row++)
1275 {
1276 for (int col = 0; col < cols; col++)
1277 {
1278 if (col == 0)
1279 matrix[row] = new float[cols];
1280 matrix[col][row] = mb.getFloat();
1281 }
1282 }
1283 try
1284 {
1285 for (int col = 0; col < cols; col++)
1286 {
1287 vArray[col] = FloatVectorUtil.instantiateAnonymousSI(matrix[col], units[col], StorageType.DENSE);
1288 }
1289 list.add(vArray);
1290 }
1291 catch (ValueException exception)
1292 {
1293 throw new Sim0MQException(exception);
1294 }
1295 }
1296
1297 else if (type == Sim0MQTypes.DOUBLE_64_UNIT_COLUMN_ARRAY)
1298 {
1299 int rows = mb.getInt();
1300 int cols = mb.getInt();
1301 Unit<? extends Unit<?>>[] units = new Unit<?>[cols];
1302 AbstractDoubleVector<?, ?>[] vArray = new AbstractDoubleVector[cols];
1303 for (int col = 0; col < cols; col++)
1304 {
1305 units[col] = mb.getUnit();
1306 }
1307
1308 double[][] matrix = new double[cols][rows];
1309 for (int row = 0; row < rows; row++)
1310 {
1311 for (int col = 0; col < cols; col++)
1312 {
1313 if (col == 0)
1314 matrix[row] = new double[cols];
1315 matrix[col][row] = mb.getDouble();
1316 }
1317 }
1318 try
1319 {
1320 for (int col = 0; col < cols; col++)
1321 {
1322 vArray[col] = DoubleVectorUtil.instantiateAnonymousSI(matrix[col], units[col], StorageType.DENSE);
1323 }
1324 list.add(vArray);
1325 }
1326 catch (ValueException exception)
1327 {
1328 throw new Sim0MQException(exception);
1329 }
1330 }
1331
1332 else
1333 {
1334 throw new Sim0MQException("Unknown data type " + type + " in the ZeroMQ message while decoding");
1335 }
1336 }
1337
1338 Object[] array = list.toArray();
1339 return array;
1340 }
1341
1342
1343
1344
1345
1346
1347 private static int extraBytesMoney(final Object o)
1348 {
1349 if (o instanceof Money)
1350 {
1351 return 1;
1352 }
1353 else if (o instanceof MoneyPerArea || o instanceof MoneyPerEnergy || o instanceof MoneyPerLength
1354 || o instanceof MoneyPerMass || o instanceof MoneyPerDuration || o instanceof MoneyPerVolume)
1355 {
1356 return 2;
1357 }
1358 else if (o instanceof FloatMoney)
1359 {
1360 return 1;
1361 }
1362 else if (o instanceof FloatMoneyPerArea || o instanceof FloatMoneyPerEnergy || o instanceof FloatMoneyPerLength
1363 || o instanceof FloatMoneyPerMass || o instanceof FloatMoneyPerDuration || o instanceof FloatMoneyPerVolume)
1364 {
1365 return 2;
1366 }
1367 return 0;
1368 }
1369
1370
1371
1372
1373
1374
1375 public static String printBytes(final byte[] bytes)
1376 {
1377 StringBuffer s = new StringBuffer();
1378 s.append("|");
1379 for (int b : bytes)
1380 {
1381 if (b < 0)
1382 {
1383 b += 128;
1384 }
1385 if (b >= 32 && b <= 127)
1386 {
1387 s.append("#" + Integer.toString(b, 16).toUpperCase() + "(" + (char) (byte) b + ")|");
1388 }
1389 else
1390 {
1391 s.append("#" + Integer.toString(b, 16).toUpperCase() + "|");
1392 }
1393 }
1394 return s.toString();
1395 }
1396
1397 }