1 package org.sim0mq.message;
2
3 import java.io.Serializable;
4
5 import org.sim0mq.Sim0MQException;
6
7 import nl.tudelft.simulation.language.Throw;
8
9 /**
10 * The abstract body of the message with the first fields of every Sim0MQ message.
11 * <p>
12 * Copyright (c) 2016-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
13 * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
14 * </p>
15 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
16 * initial version Apr 22, 2017 <br>
17 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
18 */
19 public abstract class Sim0MQMessage implements Serializable
20 {
21 /** */
22 private static final long serialVersionUID = 20170422L;
23
24 /**
25 * the Simulation run ids can be provided in different types. Examples are two 64-bit longs indicating a UUID, or a String
26 * with a UUID number, a String with meaningful identification, or a short or an int with a simulation run number.
27 */
28 private final Object simulationRunId;
29
30 /** The sender id can be used to send back a message to the sender at some later time. */
31 private final Object senderId;
32
33 /**
34 * The receiver id can be used to check whether the message is meant for us, or should be discarded (or an error can be sent
35 * if we receive a message not meant for us).
36 */
37 private final Object receiverId;
38
39 /**
40 * Message type ids can be defined per type of simulation, and can be provided in different types. Examples are a String
41 * with a meaningful identification, or a short or an int with a message type number.
42 */
43 private final Object messageTypeId;
44
45 /**
46 * The unique message number is meant to confirm with a callback that the message has been received correctly. The number is
47 * unique for the sender, so not globally within the federation.
48 */
49 private final long messageId;
50
51 /**
52 * Three different status messages are defined: 1 for new, 2 for change, and 3 for delete. This field is coded as a byte.
53 */
54 private final MessageStatus messageStatus;
55
56 /**
57 * Encode the object array into a message.
58 * @param simulationRunId the Simulation run ids can be provided in different types. Examples are two 64-bit longs
59 * indicating a UUID, or a String with a UUID number, a String with meaningful identification, or a short or an
60 * int with a simulation run number.
61 * @param senderId The sender id can be used to send back a message to the sender at some later time.
62 * @param receiverId The receiver id can be used to check whether the message is meant for us, or should be discarded (or an
63 * error can be sent if we receive a message not meant for us).
64 * @param messageTypeId Message type ids can be defined per type of simulation, and can be provided in different types.
65 * Examples are a String with a meaningful identification, or a short or an int with a message type number.
66 * @param messageId The unique message number is meant to confirm with a callback that the message has been received
67 * correctly. The number is unique for the sender, so not globally within the federation.
68 * @param messageStatus Three different status messages are defined: 1 for new, 2 for change, and 3 for delete. This field
69 * is coded as a byte.
70 * @throws Sim0MQException on unknown data type
71 * @throws NullPointerException when one of the parameters is null
72 */
73 public Sim0MQMessage(final Object simulationRunId, final Object senderId, final Object receiverId,
74 final Object messageTypeId, final long messageId, final MessageStatus messageStatus)
75 throws Sim0MQException, NullPointerException
76 {
77 Throw.whenNull(simulationRunId, "simulationRunId cannot be null");
78 Throw.whenNull(senderId, "senderId cannot be null");
79 Throw.whenNull(receiverId, "receiverId cannot be null");
80 Throw.whenNull(messageTypeId, "messageTypeId cannot be null");
81 Throw.whenNull(messageId, "messageId cannot be null");
82 Throw.whenNull(messageStatus, "messageStatus cannot be null");
83
84 this.simulationRunId = simulationRunId;
85 this.senderId = senderId;
86 this.receiverId = receiverId;
87 this.messageTypeId = messageTypeId;
88 this.messageId = messageId;
89 this.messageStatus = messageStatus;
90 }
91
92 /**
93 * @return simulationRunId
94 */
95 public final Object getSimulationRunId()
96 {
97 return this.simulationRunId;
98 }
99
100 /**
101 * @return senderId
102 */
103 public final Object getSenderId()
104 {
105 return this.senderId;
106 }
107
108 /**
109 * @return receiverId
110 */
111 public final Object getReceiverId()
112 {
113 return this.receiverId;
114 }
115
116 /**
117 * @return messageTypeId
118 */
119 public final Object getMessageTypeId()
120 {
121 return this.messageTypeId;
122 }
123
124 /**
125 * @return messageId
126 */
127 public final long getMessageId()
128 {
129 return this.messageId;
130 }
131
132 /**
133 * @return messageStatus
134 */
135 public final MessageStatus getMessageStatus()
136 {
137 return this.messageStatus;
138 }
139
140 /**
141 * Create a Sim0MQ object array of the fields.
142 * @return Object[] a Sim0MQ object array of the fields
143 */
144 public abstract Object[] createObjectArray();
145
146 /**
147 * Create a byte array of the fields.
148 * @return byte[] a Sim0MQ byte array of the content
149 * @throws Sim0MQException on unknown data type as part of the content
150 */
151 public abstract byte[] createByteArray() throws Sim0MQException;
152
153 /**
154 * Check the consistency of a message from an Object[] that was received.
155 * @param fields Object[]; the fields in the message
156 * @param expectedPayloadFields the expected number of payload fields
157 * @param expectedMessageType the expected message type
158 * @param intendedReceiverId id of the intended receiver
159 * @throws Sim0MQException when errors in the message have been detected
160 */
161 public static void check(final Object[] fields, final int expectedPayloadFields, final String expectedMessageType,
162 final Object intendedReceiverId) throws Sim0MQException
163 {
164 Throw.when(fields.length != expectedPayloadFields + 8, Sim0MQException.class,
165 "Message " + expectedMessageType + " does not contain the right number of fields");
166
167 for (int i = 0; i < fields.length; i++)
168 {
169 Object field = fields[i];
170 if (field == null)
171 {
172 throw new Sim0MQException("Message " + expectedMessageType + " field " + i + " equals null");
173 }
174 }
175
176 Throw.when(!expectedMessageType.equals(fields[4].toString()), Sim0MQException.class,
177 "Message type not right -- should have been " + expectedMessageType);
178
179 Throw.when(!fields[3].equals(intendedReceiverId), Sim0MQException.class,
180 "Receiver in message of type " + expectedMessageType + " not right. Should have been: " + intendedReceiverId);
181
182 Throw.when(!(fields[7] instanceof Short), Sim0MQException.class,
183 "Message " + expectedMessageType + " does not have a short field[7] for the number of fields");
184 Throw.when(((Short) fields[7]).intValue() != expectedPayloadFields, Sim0MQException.class,
185 "Message " + expectedMessageType + " does not contain the right number of payload fields in field[7]");
186 }
187
188 /**
189 * Builder for the Sim0MQMessage. Can string setters together, and call build() at the end to build the actual message.
190 * <p>
191 * Copyright (c) 2016-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
192 * <br>
193 * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
194 * </p>
195 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
196 * initial version Apr 22, 2017 <br>
197 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
198 * @param <B> the actual inherited builder for the return types.
199 */
200 public abstract static class Builder<B extends Sim0MQMessage.Builder<B>>
201 {
202 /**
203 * the Simulation run ids can be provided in different types. Examples are two 64-bit longs indicating a UUID, or a
204 * String with a UUID number, a String with meaningful identification, or a short or an int with a simulation run
205 * number.
206 */
207 @SuppressWarnings("checkstyle:visibilitymodifier")
208 protected Object simulationRunId;
209
210 /** The sender id can be used to send back a message to the sender at some later time. */
211 @SuppressWarnings("checkstyle:visibilitymodifier")
212 protected Object senderId;
213
214 /**
215 * The receiver id can be used to check whether the message is meant for us, or should be discarded (or an error can be
216 * sent if we receive a message not meant for us).
217 */
218 @SuppressWarnings("checkstyle:visibilitymodifier")
219 protected Object receiverId;
220
221 /**
222 * Message type ids can be defined per type of simulation, and can be provided in different types. Examples are a String
223 * with a meaningful identification, or a short or an int with a message type number.
224 */
225 @SuppressWarnings("checkstyle:visibilitymodifier")
226 protected Object messageTypeId;
227
228 /**
229 * The unique message number is meant to confirm with a callback that the message has been received correctly. The
230 * number is unique for the sender, so not globally within the federation.
231 */
232 @SuppressWarnings("checkstyle:visibilitymodifier")
233 protected long messageId;
234
235 /**
236 * Three different status messages are defined: 1 for new, 2 for change, and 3 for delete. This field is coded as a
237 * byte.
238 */
239 @SuppressWarnings("checkstyle:visibilitymodifier")
240 protected MessageStatus messageStatus;
241
242 /**
243 * Empty constructor.
244 */
245 public Builder()
246 {
247 // nothing to do.
248 }
249
250 /**
251 * @param newSimulationRunId set simulationRunId
252 * @return the original object for chaining
253 */
254 @SuppressWarnings("unchecked")
255 public final B setSimulationRunId(final Object newSimulationRunId)
256 {
257 this.simulationRunId = newSimulationRunId;
258 return (B) this;
259 }
260
261 /**
262 * @param newSenderId set senderId
263 * @return the original object for chaining
264 */
265 @SuppressWarnings("unchecked")
266 public final B setSenderId(final Object newSenderId)
267 {
268 this.senderId = newSenderId;
269 return (B) this;
270 }
271
272 /**
273 * @param newReceiverId set receiverId
274 * @return the original object for chaining
275 */
276 @SuppressWarnings("unchecked")
277 public final B setReceiverId(final Object newReceiverId)
278 {
279 this.receiverId = newReceiverId;
280 return (B) this;
281 }
282
283 /**
284 * @param newMessageTypeId set messageTypeId
285 * @return the original object for chaining
286 */
287 @SuppressWarnings("unchecked")
288 protected final B setMessageTypeId(final Object newMessageTypeId)
289 {
290 this.messageTypeId = newMessageTypeId;
291 return (B) this;
292 }
293
294 /**
295 * @param newMessageId set messageId
296 * @return the original object for chaining
297 */
298 @SuppressWarnings("unchecked")
299 public final B setMessageId(final long newMessageId)
300 {
301 this.messageId = newMessageId;
302 return (B) this;
303 }
304
305 /**
306 * @param newMessageStatus set messageStatus
307 * @return the original object for chaining
308 */
309 @SuppressWarnings("unchecked")
310 protected final B setMessageStatus(final MessageStatus newMessageStatus)
311 {
312 this.messageStatus = newMessageStatus;
313 return (B) this;
314 }
315
316 /**
317 * Build the object.
318 * @return the message object from the builder.
319 * @throws Sim0MQException on unknown data type
320 * @throws NullPointerException when one of the parameters is null
321 */
322 public abstract Sim0MQMessage build() throws Sim0MQException, NullPointerException;
323
324 }
325 }