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