View Javadoc
1   package org.sim0mq.message.federationmanager;
2   
3   import org.djutils.exceptions.Throw;
4   import org.sim0mq.Sim0MQException;
5   import org.sim0mq.message.Sim0MQMessage;
6   
7   /**
8    * StartFederateMessage, FM.1. When it receives a StartFederate message, the Federate starter creates a process to run the model
9    * with the specifications given in the message, such as the working directory, model file, output and error files etc. Creating
10   * a model instance in this way also requires a port number, to which the model instance should bind as a ROUTER. This port
11   * number is assigned by the Federate Starter. Federate Starter picks an available port from a range of ports on the machine it
12   * is running (which must be open to outside connection) and gives this to the model as an argument. If the binding is not
13   * successful, the Federate Starter creates generates a new port number.
14   * <p>
15   * Copyright (c) 2016-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
16   * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
17   * </p>
18   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
19   */
20  public class FM1StartFederateMessage extends Sim0MQMessage
21  {
22      /**
23       * Id to identify the callback to know which model instance has been started, e.g. "IDVV.14". The model instance will use
24       * this as its sender id.
25       */
26      private final Object instanceId;
27  
28      /**
29       * Code for the software to run, will be looked up in a table on the local computer to determine the path to start the
30       * software on that computer. Example: "java". If the softwarePath is defined, softwareCode can be an empty String (0
31       * characters).
32       */
33      private final String softwareCode;
34  
35      /**
36       * Arguments that the software needs, before the model file path and name; e.g. "–Xmx2G -jar" in case of a Java model. This
37       * String can be empty (0 characters).
38       */
39      private final String argsBefore;
40  
41      /**
42       * The actual path on the target computer where the model resides, including the model that needs to be run. This String
43       * cannot be empty.
44       */
45      private final String modelPath;
46  
47      /**
48       * Arguments that the software or the model needs, after the model file path and name; e.g. arguments for the model itself
49       * to run like a data file or a data location . This String can be empty (0 characters), but usually we would want to send
50       * the port number(s) or a location where the model can find it as well as the name under which the model was registered.
51       */
52      private final String argsAfter;
53  
54      /**
55       * Full path on the target computer that will be used as the working directory. Some files may be temporarily stored there.
56       * If the working directory does not exist yet, it will be created.
57       */
58      private final String workingDirectory;
59  
60      /** Place to get user input from in case a model asks for it (it shouldn't, by the way). */
61      private final String redirectStdin;
62  
63      /**
64       * Place to send the output to that the model normally displays on the console. If this is not redirected, the memory buffer
65       * for the stdout might get full, and the model might stop as a result. On Linux systems, this often redirected to
66       * /dev/null. On Windows systems, this can e.g., be redirected to a file "out.txt" in the current working directory. For
67       * now, it has to be a path name (including /dev/null as being acceptable). If no full path is given, the filename is
68       * relative to the working directory.
69       */
70      private final String redirectStdout;
71  
72      /**
73       * Place to send the error messages to that the model normally displays on the console. If this is not redirected, the
74       * memory buffer for the stderr might get full, and the model might stop as a result. On Linux systems, this often
75       * redirected to /dev/null. On Windows systems, this can e.g., be redirected to a file "err.txt" in the current working
76       * directory. For now, it has to be a path name (including /dev/null as being acceptable). If no full path is given, the
77       * filename is relative to the working directory.
78       */
79      private final String redirectStderr;
80  
81      /** Whether to delete the working directory after the run of the model or not. */
82      private final boolean deleteWorkingDirectory;
83  
84      /**
85       * Whether to delete the redirected stdout after running or not (in case it is stored in a different place than the working
86       * directory).
87       */
88      private final boolean deleteStdout;
89  
90      /**
91       * Whether to delete the redirected stderr after running or not (in case it is stored in a different place than the working
92       * directory).
93       */
94      private final boolean deleteStderr;
95  
96      /** the unique message id. */
97      private static final String MESSAGETYPE = "FM.1";
98  
99      /** */
100     private static final long serialVersionUID = 20170422L;
101 
102     /**
103      * @param federationId the federation id can be coded using different types. Examples are two 64-bit longs indicating a
104      *            UUID, or a String with a UUID number, a String with meaningful identification, or a short or an int with a
105      *            simulation run number.
106      * @param senderId The sender id can be used to send back a message to the sender at some later time.
107      * @param receiverId The receiver id can be used to check whether the message is meant for us, or should be discarded (or an
108      *            error can be sent if we receive a message not meant for us).
109      * @param messageId The unique message number is meant to confirm with a callback that the message has been received
110      *            correctly. The number is unique for the sender, so not globally within the federation.
111      * @param instanceId Id to identify the callback to know which model instance has been started, e.g. "IDVV.14". The model
112      *            instance will use this as its sender id.
113      * @param softwareCode Code for the software to run, will be looked up in a table on the local computer to determine the
114      *            path to start the software on that computer. Example: "java". If the softwarePath is defined, softwareCode can
115      *            be an empty String (0 characters).
116      * @param argsBefore Arguments that the software needs, before the model file path and name; e.g. "–Xmx2G -jar" in case of a
117      *            Java model. This String can be empty (0 characters).
118      * @param modelPath The actual path on the target computer where the model resides, including the model that needs to be
119      *            run. This String cannot be empty.
120      * @param argsAfter Arguments that the software or the model needs, after the model file path and name; e.g. arguments for
121      *            the model itself to run like a data file or a data location . This String can be empty (0 characters), but
122      *            usually we would want to send the port number(s) or a location where the model can find it as well as the name
123      *            under which the model was registered.
124      * @param workingDirectory Full path on the target computer that will be used as the working directory. Some files may be
125      *            temporarily stored there. If the working directory does not exist yet, it will be created.
126      * @param redirectStdin Place to get user input from in case a model asks for it (it shouldn't, by the way).
127      * @param redirectStdout Place to send the output to that the model normally displays on the console. If this is not
128      *            redirected, the memory buffer for the stdout might get full, and the model might stop as a result. On Linux
129      *            systems, this often redirected to /dev/null. On Windows systems, this can e.g., be redirected to a file
130      *            "out.txt" in the current working directory. For now, it has to be a path name (including /dev/null as being
131      *            acceptable). If no full path is given, the filename is relative to the working directory.
132      * @param redirectStderr Place to send the error messages to that the model normally displays on the console. If this is not
133      *            redirected, the memory buffer for the stderr might get full, and the model might stop as a result. On Linux
134      *            systems, this often redirected to /dev/null. On Windows systems, this can e.g., be redirected to a file
135      *            "err.txt" in the current working directory. For now, it has to be a path name (including /dev/null as being
136      *            acceptable). If no full path is given, the filename is relative to the working directory.
137      * @param deleteWorkingDirectory Whether to delete the working directory after the run of the model or not.
138      * @param deleteStdout Whether to delete the redirected stdout after running or not (in case it is stored in a different
139      *            place than the working directory)
140      * @param deleteStderr Whether to delete the redirected stderr after running or not (in case it is stored in a different
141      *            place than the working directory)
142      * @throws Sim0MQException on unknown data type
143      * @throws NullPointerException when one of the parameters is null
144      */
145     @SuppressWarnings("checkstyle:parameternumber")
146     public FM1StartFederateMessage(final Object federationId, final Object senderId, final Object receiverId,
147             final Object messageId, final String instanceId, final String softwareCode, final String argsBefore,
148             final String modelPath, final String argsAfter, final String workingDirectory, final String redirectStdin,
149             final String redirectStdout, final String redirectStderr, final boolean deleteWorkingDirectory,
150             final boolean deleteStdout, final boolean deleteStderr) throws Sim0MQException, NullPointerException
151     {
152         this(new Object[] {Sim0MQMessage.VERSION, true, federationId, senderId, receiverId, MESSAGETYPE, messageId, 12,
153                 instanceId, softwareCode, argsBefore, modelPath, argsAfter, workingDirectory, redirectStdin, redirectStdout,
154                 redirectStderr, deleteWorkingDirectory, deleteStdout, deleteStderr});
155     }
156 
157     /**
158      * @param objectArray Object[]; the fields that constitute the message
159      * @throws Sim0MQException on unknown data type
160      * @throws NullPointerException when one of the parameters is null
161      */
162     public FM1StartFederateMessage(final Object[] objectArray) throws Sim0MQException, NullPointerException
163     {
164         super(objectArray, 12, MESSAGETYPE);
165         this.instanceId = objectArray[8];
166         Throw.when(!(objectArray[9] instanceof String), Sim0MQException.class, "softwareCode (field 9) should be a String");
167         this.softwareCode = objectArray[9].toString();
168         Throw.when(!(objectArray[10] instanceof String), Sim0MQException.class, "argsBefore (field 10) should be a String");
169         this.argsBefore = objectArray[10].toString();
170         Throw.when(!(objectArray[11] instanceof String), Sim0MQException.class, "modelPath (field 11) should be a String");
171         this.modelPath = objectArray[11].toString();
172         Throw.when(!(objectArray[12] instanceof String), Sim0MQException.class, "argsAfter (field 12) should be a String");
173         this.argsAfter = objectArray[12].toString();
174         Throw.when(!(objectArray[13] instanceof String), Sim0MQException.class,
175                 "workingDirectory (field 13) should be a String");
176         this.workingDirectory = objectArray[13].toString();
177         Throw.when(!(objectArray[14] instanceof String), Sim0MQException.class, "redirectStdin (field 14) should be a String");
178         this.redirectStdin = objectArray[14].toString();
179         Throw.when(!(objectArray[15] instanceof String), Sim0MQException.class, "redirectStdout (field 15) should be a String");
180         this.redirectStdout = objectArray[15].toString();
181         Throw.when(!(objectArray[16] instanceof String), Sim0MQException.class, "redirectStdin (field 16) should be a String");
182         this.redirectStderr = objectArray[16].toString();
183         Throw.when(!(objectArray[17] instanceof Boolean), Sim0MQException.class,
184                 "redirectStdin (field 17) should be a Boolean");
185         this.deleteWorkingDirectory = ((Boolean) objectArray[17]).booleanValue();
186         Throw.when(!(objectArray[18] instanceof Boolean), Sim0MQException.class,
187                 "redirectStdout (field 18) should be a Boolean");
188         this.deleteStdout = ((Boolean) objectArray[18]).booleanValue();
189         Throw.when(!(objectArray[19] instanceof Boolean), Sim0MQException.class,
190                 "redirectStderr (field 19) should be a Boolean");
191         this.deleteStderr = ((Boolean) objectArray[19]).booleanValue();
192     }
193 
194     /**
195      * @return instanceId
196      */
197     public final Object getInstanceId()
198     {
199         return this.instanceId;
200     }
201 
202     /**
203      * @return softwareCode
204      */
205     public final String getSoftwareCode()
206     {
207         return this.softwareCode;
208     }
209 
210     /**
211      * @return argsBefore
212      */
213     public final String getArgsBefore()
214     {
215         return this.argsBefore;
216     }
217 
218     /**
219      * @return modelPath
220      */
221     public final String getModelPath()
222     {
223         return this.modelPath;
224     }
225 
226     /**
227      * @return argsAfter
228      */
229     public final String getArgsAfter()
230     {
231         return this.argsAfter;
232     }
233 
234     /**
235      * @return workingDirectory
236      */
237     public final String getWorkingDirectory()
238     {
239         return this.workingDirectory;
240     }
241 
242     /**
243      * @return redirectStdin
244      */
245     public final String getRedirectStdin()
246     {
247         return this.redirectStdin;
248     }
249 
250     /**
251      * @return redirectStdout
252      */
253     public final String getRedirectStdout()
254     {
255         return this.redirectStdout;
256     }
257 
258     /**
259      * @return redirectStderr
260      */
261     public final String getRedirectStderr()
262     {
263         return this.redirectStderr;
264     }
265 
266     /**
267      * @return deleteWorkingDirectory
268      */
269     public final boolean isDeleteWorkingDirectory()
270     {
271         return this.deleteWorkingDirectory;
272     }
273 
274     /**
275      * @return deleteStdout
276      */
277     public final boolean isDeleteStdout()
278     {
279         return this.deleteStdout;
280     }
281 
282     /**
283      * @return deleteStderr
284      */
285     public final boolean isDeleteStderr()
286     {
287         return this.deleteStderr;
288     }
289 
290     /**
291      * Builder for the StartFederate Message. Can string setters together, and call build() at the end to build the actual
292      * message.
293      * <p>
294      * Copyright (c) 2016-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
295      * <br>
296      * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
297      * </p>
298      * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
299      */
300     public static class Builder extends Sim0MQMessage.Builder<FM1StartFederateMessage.Builder>
301     {
302         /**
303          * Id to identify the callback to know which model instance has been started, e.g. "IDVV.14". The model instance will
304          * use this as its sender id.
305          */
306         private String instanceId;
307 
308         /**
309          * Code for the software to run, will be looked up in a table on the local computer to determine the path to start the
310          * software on that computer. Example: "java". If the softwarePath is defined, softwareCode can be an empty String (0
311          * characters).
312          */
313         private String softwareCode;
314 
315         /**
316          * Arguments that the software needs, before the model file path and name; e.g. "–Xmx2G -jar" in case of a Java model.
317          * This String can be empty (0 characters).
318          */
319         private String argsBefore;
320 
321         /**
322          * The actual path on the target computer where the model resides, including the model that needs to be run. This String
323          * cannot be empty.
324          */
325         private String modelPath;
326 
327         /**
328          * Arguments that the software or the model needs, after the model file path and name; e.g. arguments for the model
329          * itself to run like a data file or a data location . This String can be empty (0 characters), but usually we would
330          * want to send the port number(s) or a location where the model can find it as well as the name under which the model
331          * was registered.
332          */
333         private String argsAfter;
334 
335         /**
336          * Full path on the target computer that will be used as the working directory. Some files may be temporarily stored
337          * there. If the working directory does not exist yet, it will be created.
338          */
339         private String workingDirectory;
340 
341         /** Place to get user input from in case a model asks for it (it shouldn't, by the way). */
342         private String redirectStdin;
343 
344         /**
345          * Place to send the output to that the model normally displays on the console. If this is not redirected, the memory
346          * buffer for the stdout might get full, and the model might stop as a result. On Linux systems, this often redirected
347          * to /dev/null. On Windows systems, this can e.g., be redirected to a file "out.txt" in the current working directory.
348          * For now, it has to be a path name (including /dev/null as being acceptable). If no full path is given, the filename
349          * is relative to the working directory.
350          */
351         private String redirectStdout;
352 
353         /**
354          * Place to send the error messages to that the model normally displays on the console. If this is not redirected, the
355          * memory buffer for the stderr might get full, and the model might stop as a result. On Linux systems, this often
356          * redirected to /dev/null. On Windows systems, this can e.g., be redirected to a file "err.txt" in the current working
357          * directory. For now, it has to be a path name (including /dev/null as being acceptable). If no full path is given, the
358          * filename is relative to the working directory.
359          */
360         private String redirectStderr;
361 
362         /** Whether to delete the working directory after the run of the model or not. */
363         private boolean deleteWorkingDirectory;
364 
365         /**
366          * Whether to delete the redirected stdout after running or not (in case it is stored in a different place than the
367          * working directory).
368          */
369         private boolean deleteStdout;
370 
371         /**
372          * Whether to delete the redirected stderr after running or not (in case it is stored in a different place than the
373          * working directory).
374          */
375         private boolean deleteStderr;
376 
377         /**
378          * Empty constructor.
379          */
380         public Builder()
381         {
382             // nothing to do.
383         }
384 
385         /**
386          * @param newInstanceId set instanceId
387          * @return the original object for chaining
388          */
389         public final Builder setInstanceId(final String newInstanceId)
390         {
391             this.instanceId = newInstanceId;
392             return this;
393         }
394 
395         /**
396          * @param newSoftwareCode set softwareCode
397          * @return the original object for chaining
398          */
399         public final Builder setSoftwareCode(final String newSoftwareCode)
400         {
401             this.softwareCode = newSoftwareCode;
402             return this;
403         }
404 
405         /**
406          * @param newArgsBefore set argsBefore
407          * @return the original object for chaining
408          */
409         public final Builder setArgsBefore(final String newArgsBefore)
410         {
411             this.argsBefore = newArgsBefore;
412             return this;
413         }
414 
415         /**
416          * @param newModelPath set modelPath
417          * @return the original object for chaining
418          */
419         public final Builder setModelPath(final String newModelPath)
420         {
421             this.modelPath = newModelPath;
422             return this;
423         }
424 
425         /**
426          * @param newArgsAfter set argsAfter
427          * @return the original object for chaining
428          */
429         public final Builder setArgsAfter(final String newArgsAfter)
430         {
431             this.argsAfter = newArgsAfter;
432             return this;
433         }
434 
435         /**
436          * @param newWorkingDirectory set workingDirectory
437          * @return the original object for chaining
438          */
439         public final Builder setWorkingDirectory(final String newWorkingDirectory)
440         {
441             this.workingDirectory = newWorkingDirectory;
442             return this;
443         }
444 
445         /**
446          * @param newRedirectStdin set redirectStdin
447          * @return the original object for chaining
448          */
449         public final Builder setRedirectStdin(final String newRedirectStdin)
450         {
451             this.redirectStdin = newRedirectStdin;
452             return this;
453         }
454 
455         /**
456          * @param newRedirectStdout set redirectStdout
457          * @return the original object for chaining
458          */
459         public final Builder setRedirectStdout(final String newRedirectStdout)
460         {
461             this.redirectStdout = newRedirectStdout;
462             return this;
463         }
464 
465         /**
466          * @param rewRedirectStderr set redirectStderr
467          * @return the original object for chaining
468          */
469         public final Builder setRedirectStderr(final String rewRedirectStderr)
470         {
471             this.redirectStderr = rewRedirectStderr;
472             return this;
473         }
474 
475         /**
476          * @param newDeleteWorkingDirectory set deleteWorkingDirectory
477          * @return the original object for chaining
478          */
479         public final Builder setDeleteWorkingDirectory(final boolean newDeleteWorkingDirectory)
480         {
481             this.deleteWorkingDirectory = newDeleteWorkingDirectory;
482             return this;
483         }
484 
485         /**
486          * @param newDeleteStdout set deleteStdout
487          * @return the original object for chaining
488          */
489         public final Builder setDeleteStdout(final boolean newDeleteStdout)
490         {
491             this.deleteStdout = newDeleteStdout;
492             return this;
493         }
494 
495         /**
496          * @param newDeleteStderr set deleteStderr
497          * @return the original object for chaining
498          */
499         public final Builder setDeleteStderr(final boolean newDeleteStderr)
500         {
501             this.deleteStderr = newDeleteStderr;
502             return this;
503         }
504 
505         @Override
506         public FM1StartFederateMessage build() throws Sim0MQException, NullPointerException
507         {
508             return new FM1StartFederateMessage(this.federationId, this.senderId, this.receiverId, this.messageId,
509                     this.instanceId, this.softwareCode, this.argsBefore, this.modelPath, this.argsAfter, this.workingDirectory,
510                     this.redirectStdin, this.redirectStdout, this.redirectStderr, this.deleteWorkingDirectory,
511                     this.deleteStdout, this.deleteStderr);
512         }
513 
514     }
515 }