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 }