Source code: desmoj/Experiment.java
1 package desmoj;
2
3 import java.awt.event.*; // import the stuff to close window of progress bar
4 import javax.swing.*; // import the stuff to display a progress bar
5 import desmoj.exception.*; // import special exceptions
6 import desmoj.dist.*; // import distributions
7 import desmoj.report.*; // import reporting & messaging
8 import java.util.Enumeration; // import Enumeration needed for reporting
9 import java.text.ParseException; // import ParseException needed if parsing
10 // of reference time fails
11 import java.io.File; // import for file handling
12
13 /**
14 * Experiment is the class that provides the infrastructure
15 * for running the simulation of a model.
16 * It contains all data structures necessary to simulate the model
17 * and takes care of all necessary output. To actually run an experiment,
18 * a new instance of the experiment class and a new instance of the
19 * desired model have to be created. To link both instances, call the
20 * <code>connectToExperiment(Experiment e)</code> method of the model instance
21 * and pass the new experiment as a parameter.
22 * Additional functionality by Ruth Meyer: Experiments may be "timed", i.e.
23 * the simulation time (represented as doubles) may be mapped to a true date
24 * and time. This requires the specification of a time unit, too.
25 * Example: Simulation starts at sim time 0.0 = true time 23.5.1999 10:00,
26 * time unit is minutes, so sim time 5.0 = true time 23.5.1999 10:05.
27 *
28 * @author Tim Lechler
29 * @author modified by Soenke Claassen, Ruth Meyer, Nicolas Knaak
30 *
31 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
32 */
33 public class Experiment extends NamedObject {
34
35 /**
36 * Status of an Experiment just created without any accessories created yet.
37 */
38 public static final int NOT_INITIALIZED = -3;
39
40 /**
41 * Status of an Experiment instantiated with all needed accessories
42 * available.
43 */
44 public static final int INITIALIZED = -2;
45
46 /**
47 * Status of an Experiment connected to a Model and ready to be started.
48 */
49 public static final int CONNECTED = -1;
50
51 /**
52 * Status of an Experiment being started.
53 * Only if an Experiment is
54 */
55 public static final int STARTED = 0;
56
57 /**
58 * Status of an Experiment stopped after having run.
59 */
60 public static final int STOPPED = 1;
61
62 /**
63 * Status of an Experiment currently running the simulation.
64 */
65 public static final int RUNNING = 2;
66
67 /**
68 * Status of an Experiment finished and to be cleared.
69 */
70 public static final int ABORTED = 3;
71
72 /**
73 * The last suffix used with filenames when creating multiple batch
74 * runs of an experiment.
75 */
76 private static int lastSuffix;
77
78 /**
79 * The class reference to messages of type desmoj.report.TraceNote
80 */
81 static Class tracenote;
82
83 /**
84 * The class reference to messages of type desmoj.report.DebugNote
85 */
86 static Class debugnote;
87
88 /**
89 * The class reference to messages of type desmoj.report.ErrorMessage
90 */
91 static Class errormessage;
92
93 /**
94 * The class reference to messages of type desmoj.report.Reporter
95 */
96 static Class reporter;
97
98 /**
99 * The <code>Condition</code> which can cause an experiment to stop.
100 * The user has to implement the <code>check()</code> method of this
101 * <code>Condition</code> in order to effectively stop an experiment.
102 */
103 private Condition stopper;
104
105 /**
106 * Flag indicating if the simulation is supposed to stop after the current
107 * event is processed.
108 */
109 private boolean abortFlag;
110
111 /**
112 * Flag indicating if the simulation is running.
113 */
114 private int status;
115
116 /**
117 * The model to be run by this experiment.
118 */
119 private Model client;
120
121 /**
122 * The scheduler used for this experiment.
123 */
124 private Scheduler clientScheduler;
125
126 /**
127 * The distribution manager for the model's distributions.
128 */
129 private DistributionManager distMan;
130
131 /**
132 * The report manager for the model's reports.
133 */
134 private ReportManager repMan;
135
136 /**
137 * The message manager for the model's messages.
138 */
139 private MessageDistributor messMan;
140
141 /**
142 * The seed used to start the SeedGenerator with. Default is zero, but can be
143 * set via the ExperimentOptions to individual values.
144 */
145 private long seedGeneratorSeed;
146
147 /**
148 * The ThreadGroup for this Experiment.
149 */
150 private ThreadGroup expThreads;
151
152 /**
153 * The number of floating point digits of simulation time to be
154 * printed in Reports.
155 */
156 private int timeFloats;
157
158 /**
159 * The Vector to register all FileOutput objects to close them after finishing
160 * the Experiment.
161 */
162 private java.util.Vector fileRegistry;
163
164 /**
165 * The resource database storing all resource allocations and requests. Also
166 * needed to detect deadlocks.
167 */
168 private ResourceDB resDB;
169
170 /**
171 * The SimTime when the experiment is supposed to stop. Is initially
172 * <code>null</code> and will be set only if the user provides a time
173 * limit as some kind of stop <code>Condition</code>.
174 */
175 private SimTime stopTime = null;
176
177 /**
178 * Flag indicating whether a progressbar for this experiment should be
179 * displayed or not.
180 */
181 private boolean showProgressBar;
182
183 /**
184 * The time converter used to convert sim time to true time and vice versa.
185 */
186 private TimeConverter trueTimer;
187
188 /**
189 * Flag to indicate if this experiment is "timed", i.e. if sim time is
190 * mapped to a true date and time. Default is <tt>false</tt>.
191 */
192 private boolean isTimed;
193
194 /**
195 * Specifies an output path for the report files
196 * (Modification by Nicolas Knaak, 02/2001)
197 */
198 private String pathname;
199 /**
200 * Specifies an output path for the report files
201 * (Modification by Nicolas Knaak, 02/2001)
202 */
203 private String pathName;
204
205 /**
206 * Constructs a new Experiment with the given name.
207 * This is the shortcut constructor with just the name needed as parameter
208 * to identify the outputfiles produced by this experiment.
209 * All other possible settings are set to default values.
210 * These settings for an experiment without special ExperimentOptions are:
211 * <ol>
212 * <li>epsilon = 0.00001 : The minimum distinguishable timespan</li>
213 * <li>time floats = 4 : The number of floating point digits displayed for
214 * simulation time in reports</li>
215 * <li>seed = 979 : The initial seed setting for the seed-generator</li>
216 * </ol>
217 * The default stop condition for this experiment will never interfere, always
218 * returning false.
219 * @param name String : The name of the experiment determining the outputfile's
220 * names, too. So please avoid characters that your local filesystem does not
221 * support in filenames.
222 */
223 public Experiment(String name) {
224
225 this(name, ".", null, 0); // call most special constructor
226
227 }
228 /**
229 * Constructs a new Experiment with the given name.
230 * This is the shortcut constructor with just the name needed as parameter
231 * to identify the outputfiles produced by this experiment.
232 * All other possible settings are set to default values.
233 * These settings for an experiment without special ExperimentOptions are:
234 * <ol>
235 * <li>epsilon = 0.00001 : The minimum distinguishable timespan</li>
236 * <li>time floats = 4 : The number of floating point digits displayed for
237 * simulation time in reports</li>
238 * <li>seed = 979 : The initial seed setting for the seed-generator</li>
239 * </ol>
240 * The default stop condition for this experiment will never interfere, always
241 * returning false.
242 * @param name String : The name of the experiment determining the outputfile's
243 * names, too. So please avoid characters that your local filesystem does not
244 * support in filenames.
245 * @param pathName java.lang.String : The output path for report files
246 */
247 public Experiment(String name, String pathName) {
248
249 this(name, pathName, null, 0); // call most special constructor
250
251 }
252 /**
253 * Constructs a new Experiment with the given name.
254 * This is the shortcut constructor with just the name needed as parameter
255 * to identify the outputfiles produced by this experiment.
256 * All other possible settings are set to default values.
257 * These settings for an experiment without special ExperimentOptions are:
258 * <ol>
259 * <li>epsilon = 0.00001 : The minimum distinguishable timespan</li>
260 * <li>time floats = 4 : The number of floating point digits displayed for
261 * simulation time in reports</li>
262 * <li>seed = 979 : The initial seed setting for the seed-generator</li>
263 * </ol>
264 * The default stop condition for this experiment will never interfere, always
265 * returning false.
266 * @param name String : The name of the experiment determining the outputfile's
267 * names, too. So please avoid characters that your local filesystem does not
268 * support in filenames.
269 * @param referenceTime java.lang.String : The true date and time when this simulation starts.
270 * The reference time has to be specified as a String following the pattern
271 * <tt><date><blank><time></tt> where <tt><date> =
272 * [d]d.[M]M.[yy]yy</tt> and
273 * <tt><time> = [H]H[:[m]m[:[s]s[:[S][S]S]]]</tt>
274 * It is mapped to simulation time 0.0 if no other start time is given (via call
275 * of the <code>start(SimTime initTime)</code> method.
276 * @param referenceUnit int : The time unit to be mapped to a simulation time
277 * step of 1.0 . So far, Hour, Minute, Second and Millisecond are supported.
278 * Please use the constants defined in the interface <tt>Units</tt>.
279 * @see desmoj.Units
280 */
281 public Experiment(String name, String referenceTime, int referenceUnit) {
282
283 this(name, ".", referenceTime, referenceUnit); // call most special constructor
284
285 }
286 /**
287 * Constructs a new Experiment with the given name.
288 * This is the shortcut constructor with just the name needed as parameter
289 * to identify the outputfiles produced by this experiment.
290 * All other possible settings are set to default values.
291 * These settings for an experiment without special ExperimentOptions are:
292 * <ol>
293 * <li>epsilon = 0.00001 : The minimum distinguishable timespan</li>
294 * <li>time floats = 4 : The number of floating point digits displayed for
295 * simulation time in reports</li>
296 * <li>seed = 979 : The initial seed setting for the seed-generator</li>
297 * </ol>
298 * The default stop condition for this experiment will never interfere, always
299 * returning false.
300 * @param name String : The name of the experiment determining the outputfile's
301 * names, too. So please avoid characters that your local filesystem does not
302 * support in filenames.
303 * @param pathName java.lang.String : The output path for report files
304 * @param referenceTime java.lang.String : The true date and time when this simulation starts.
305 * The reference time has to be specified as a String following the pattern
306 * <tt><date><blank><time></tt> where <tt><date> =
307 * [d]d.[M]M.[yy]yy</tt> and
308 * <tt><time> = [H]H[:[m]m[:[s]s[:[S][S]S]]]</tt>
309 * It is mapped to simulation time 0.0 if no other start time is given (via call
310 * of the <code>start(SimTime initTime)</code> method.
311 * @param referenceUnit int : The time unit to be mapped to a simulation time
312 * step of 1.0 . So far, Hour, Minute, Second and Millisecond are supported.
313 * Please use the constants defined in the interface <tt>Units</tt>.
314 * @see desmoj.Units
315 */
316 public Experiment(String name, String pathName, String referenceTime, int referenceUnit) {
317 super(name); // create a NamedObject with an attitude ;-)
318
319 // initialize variables
320 status = NOT_INITIALIZED;
321 stopper = null; // no Stopper can be set at instantiation time
322 expThreads = new ThreadGroup(name);
323 abortFlag = false;
324 timeFloats = 4;
325 fileRegistry = new java.util.Vector(4); // usually 4 files open
326 lastSuffix = 0; // no batches have run so far ;-)
327 showProgressBar = true; // display a progress bar for this experiment
328
329 // Check and set output path
330 if (pathName == null || pathName == "" || pathName == ".")
331 this.pathName = System.getProperty("user.dir", ".");
332 else this.pathName = pathName;
333
334 // set class variables for basic messagetypes
335 try {
336 tracenote = Class.forName("desmoj.report.TraceNote");
337 debugnote = Class.forName("desmoj.report.DebugNote");
338 errormessage = Class.forName("desmoj.report.ErrorMessage");
339 reporter = Class.forName("desmoj.report.Reporter");
340 }
341 catch (ClassNotFoundException cnfEx) {
342 System.out.println("Can not create Experiment!");
343 System.out.println("Constructor of desmoj.Experiment.");
344 System.out.println("Classes are probably not installed correctly.");
345 System.out.println("Check your CLASSPATH setting.");
346 System.out.println("Exception caught : "+cnfEx);
347 }
348
349 // create output system first
350 messMan = new MessageDistributor();
351
352 // create and register the debug output
353 DebugFileOut dbg = new DebugFileOut(timeFloats);
354 dbg.open(pathName, name);
355 messMan.register(dbg, debugnote);
356 messMan.switchOff(debugnote);
357 register(dbg);
358
359 // create and register the report output
360 ReportFileOut rpt = new ReportMultRowsFileOut(timeFloats);
361 // ReportFileOut rpt = new ReportFileOut(timeFloats);
362 rpt.open(pathName, name);
363 messMan.register(rpt, reporter);
364 register(rpt);
365
366 // create and register the error output
367 ErrorFileOut err = new ErrorFileOut(timeFloats);
368 err.open(pathName, name);
369 messMan.register(err, errormessage);
370 register(err);
371
372 // create and register the trace output
373 TraceFileOut trc = new TraceFileOut(timeFloats);
374 trc.open(pathName, name);
375 messMan.register(trc, tracenote);
376 messMan.switchOff(tracenote);
377 register(trc);
378
379 // create the distributionmanager to register distributions at
380 distMan = new DistributionManager(name, 979, this);
381
382 // now create the simulation runtime accessories
383 client = null; // no object connected
384
385 // make a default epsilon
386 SimTime epsilon = new SimTime(0.00001);
387
388 // create the scheduler and clock
389 clientScheduler = new Scheduler(this, name, epsilon);
390
391 // create a resource database and tell it that it belongs to this experiment
392 resDB = new ResourceDB(this);
393
394 // set status to first valid value - initialized, but not connected
395 status = INITIALIZED;
396
397 // initialize time converter with reference time und reference unit
398 trueTimer = null;
399 isTimed = false;
400 try {
401 if (referenceTime == null) {
402 trueTimer = new TimeConverter();
403 }
404 else {
405 trueTimer = new TimeConverter(referenceTime, referenceUnit);
406 // set timedFlag to true
407 isTimed = true;
408 }
409 }
410 catch (java.text.ParseException e) {
411 // referenceTime seems to be invalid
412 throw (new desmoj.exception.SimAbortedException(
413 new desmoj.report.ErrorMessage (null,
414 "Can't create timed Experiment! Simulation aborted.",
415 "Class : TimeConverter Constructor : TimeConverter(String, int)",
416 "the value passed for parameter referenceTime failed parsing : "+referenceTime,
417 "Required time format is : d.M.yy H[:m[:s[:S]]]",
418 null)));
419 }
420
421
422 }
423 /**
424 * Adds a messagereceiver for debugnotes to the experiment.
425 * Whenever a model produces a message of that type, it will also be sent to
426 * the given messagereceiver for further processing.
427 * Note that the given receiver must be capable of handling debugnotes.
428 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver for the
429 * given type of messages
430 */
431 public void addDebugReceiver(MessageReceiver trcRec) {
432
433 if ( trcRec==null) {
434 sendWarning (
435 "Can not add receiver to experiment! Command ignored.",
436 "Experiment '"+getName()+"', method 'void addDebugReceiver("+
437 "MessageReceiver trcRec)'",
438 "The parameter 'trc' passed was a null reference.",
439 "Make sure to construct a valid MessageReciever before adding it to "+
440 "the experiment's messaging system.");
441 return; // do nothing
442 }
443
444 messMan.register(trcRec, debugnote);
445
446 }
447 /**
448 * Adds a messagereceiver for error messages to the experiment.
449 * Whenever a model produces a message of that type, it will also be sent to
450 * the given messagereceiver for further processing.
451 * Note that the given receiver must be capable of handling messagereceiver.
452 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver for the
453 * given type of messages
454 */
455 public void addErrorReceiver(MessageReceiver trcRec) {
456
457 if ( trcRec==null) {
458 sendWarning (
459 "Can not add receiver to experiment! Command ignored.",
460 "Experiment '"+getName()+"', method 'void addErrorReceiver("+
461 "MessageReceiver trcRec)'",
462 "The parameter 'trc' passed was a null reference.",
463 "Make sure to construct a valid MessageReciever before adding it to "+
464 "the experiment's messaging system.");
465 return; // do nothing
466 }
467
468 messMan.register(trcRec, errormessage);
469
470 }
471 /**
472 * Adds a messagereceiver for the given subtype of message to the experiment.
473 * Whenever a model produces a message of that type, it will also be sent to
474 * the given messagereceiver for further processing.
475 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver for the
476 * given type of messages
477 * @param messageType Class : The type of message to be sent to the given
478 * messagereceiver
479 */
480 public void addReceiver(MessageReceiver trcRec, Class messageType) {
481
482 if ( trcRec==null) {
483 sendWarning (
484 "Can not add receiver to experiment! Command ignored.",
485 "Experiment '"+getName()+"', method 'void addReceiver(MessageReceiver "+
486 "trcRec, Class messageType)'",
487 "The parameter 'trc' passed was a null reference.",
488 "Make sure to construct a valid MessageReciever before adding it to "+
489 "the experiment's messaging system.");
490 return; // do nothing
491 }
492
493 if ( messageType==null) { // again these damned null values
494 sendWarning (
495 "Can not add receiver to experiment! Command ignored.",
496 "Experiment '"+getName()+"', method 'void addReceiver(MessageReceiver "+
497 "trcRec, Class messageType)'",
498 "The parameter 'messageType' passed was a null reference.",
499 "Make sure to construct a valid Class object before adding it to "+
500 "the experiment's messaging system.");
501 return; // do nothing
502 }
503
504 messMan.register(trcRec, messageType);
505
506 }
507 /**
508 * Adds a messagereceiver for tracenotes to the experiment.
509 * Whenever a model produces a message of that type, it will also be sent to
510 * the given messagereceiver for further processing.
511 * Note that the given Receiver must be capable of handling tracenotes.
512 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver for the
513 * given type of messages
514 */
515 public void addTraceReceiver(MessageReceiver trcRec) {
516
517 if ( trcRec==null) {
518 sendWarning (
519 "Can not add receiver to experiment! Command ignored.",
520 "Experiment '"+getName()+"', method 'void addTraceReceiver("+
521 "MessageReceiver trcRec)'",
522 "The parameter 'trc' passed was a null reference.",
523 "Make sure to construct a valid MessageReciever before adding it to "+
524 "the experiment's messaging system.");
525 return; // do nothing
526 }
527
528 messMan.register(trcRec, tracenote);
529
530 }
531 /**
532 * Returns a boolean indicating whether debug notes are forwarded to the debug
533 * ouput or not.
534 * Debug ouput can be switched on and off using the methods
535 * <code>debugOn(SimTime startTime)</code> or
536 * <code>debugOff(SimTime stopTime)</code>
537 * @return boolean
538 */
539 public boolean debugIsOn() {
540
541 return messMan.isOn(debugnote);
542
543 }
544 /**
545 * Switches the debug output off at the given point of simulation time.
546 * @param duration SimTime : The point in simulation time to switch off debug
547 */
548 public void debugOff(SimTime stopTime) {
549
550 // check initial SimTime parameter
551 if ( stopTime == null ) {
552 sendWarning (
553 "Invalid start time parameter for debug output given! "+
554 "StopTime is set to current time.",
555 "Experiment '"+getName()+"', method 'void debugOn(SimTime startTime)'",
556 "A null value or a not initialized SimTime reference has been passed.",
557 "Make sure to have a valid SimTime object, otherwise use method "+
558 "start() without SimTime parameter.");
559 stopTime = SimTime.NOW;
560 }
561
562 // check if parameter is in future
563 if ( SimTime.isLarger(clientScheduler.currentTime(), stopTime) ) {
564 sendWarning (
565 "Invalid start time parameter for debug output given! "+
566 "StopTime is set to current time.",
567 "Experiment '"+getName()+"', method 'void debugOn(SimTime stopTime)'",
568 "The stopTime given is in the past.",
569 "Make sure to give a SimTime parameter larger than the current time.");
570 stopTime = SimTime.NOW;
571 }
572
573 ExternalEvent debugOff = new ExternalEventDebugOff(client, true);
574
575 debugOff.schedule(stopTime);
576
577 }
578 /**
579 * Switches the debug output on at the given point of simulation time.
580 * @param duration SimTime : The point in simulation time to switch on debug
581 */
582 public void debugOn(SimTime startTime) {
583
584 // check initial SimTime parameter
585 if ( startTime == null ) {
586 sendWarning (
587 "Invalid start time parameter for debug output given! "+
588 "StartTime is set to current time.",
589 "Experiment '"+getName()+"', method 'void debugOn(SimTime startTime)'",
590 "A null value or a not initialized SimTime reference has been passed.",
591 "Make sure to have a valid SimTime object, otherwise use method "+
592 "start() without SimTime parameter.");
593 startTime = SimTime.NOW;
594 }
595
596 // check if parameter is in future
597 if ( SimTime.isLarger(clientScheduler.currentTime(), startTime) ) {
598 sendWarning (
599 "Invalid start time parameter for debug output given! "+
600 "StartTime is set to current time.",
601 "Experiment '"+getName()+"', method 'void debugOn(SimTime startTime)'",
602 "The startTime given is in the past.",
603 "Make sure to give a SimTime parameter larger than the current time.");
604 startTime = SimTime.NOW;
605 }
606
607 ExternalEvent debugOn = new ExternalEventDebugOn(client, true);
608
609 debugOn.schedule(startTime);
610
611 }
612 /**
613 * Switches the debug output on for the given period of simulation time.
614 * If the second parameter (off) is "sooner" then the first parameter (on),
615 * they will be swapped automatically.
616 * Same parameters will result in no debug output at all!
617 * @param duration SimTime : The point in simulation time to switch debug
618 * on
619 * @param duration SimTime : The point in simulation time to switch debug
620 * off
621 */
622 public void debugPeriod(SimTime startTime, SimTime stopTime) {
623
624 // check initial SimTime parameter
625 if ( startTime == null ) {
626 sendWarning (
627 "Invalid start time parameter for debug output given! Command ignored",
628 "Experiment '"+getName()+"', Method 'debugPeriod(SimTime startTime, "+
629 "SimTime stopTime)'",
630 "A null value or a not initialized SimTime reference has been passed.",
631 "Make sure to have a valid SimTime object.");
632 return;
633 }
634
635 // check initial SimTime parameter
636 if ( stopTime == null ) {
637 sendWarning (
638 "Invalid stop time parameter for debug output given! Command ignored.",
639 "Experiment '"+getName()+"', Method 'debugPeriod(SimTime startTime, "+
640 "SimTime stopTime)'",
641 "A null value or a not initialized SimTime reference has been passed.",
642 "Make sure to have a valid SimTime object.");
643 return;
644 }
645
646 // check for correct order in parameters
647 if ( SimTime.isLarger(startTime, stopTime) ) {
648
649 // swap parameters
650 SimTime buffer = stopTime;
651 stopTime = startTime;
652 startTime = buffer;
653
654 }
655
656 // check if stop parameter is in future
657 if ( SimTime.isLarger(clientScheduler.currentTime(), stopTime) ) {
658 sendWarning (
659 "Invalid stop time parameter for debug output given! Command ignored.",
660 "Experiment '"+getName()+"', Method 'debugPeriod(SimTime startTime, "+
661 "SimTime stopTime)'",
662 "The stopTime given is in the past.",
663 "Make sure to give a SimTime parameter larger than the current time.");
664 return;
665 }
666
667 // check if start parameter is in past
668 if ( SimTime.isLarger(clientScheduler.currentTime(), startTime) ) {
669 sendWarning (
670 "Invalid start time parameter for debug output given! "+
671 "Debug output has been set to start immediately.",
672 "Experiment '"+getName()+"', Method 'debugPeriod(SimTime startTime, "+
673 "SimTime startTime)'",
674 "The startTime given is in the past.",
675 "Make sure to give a SimTime parameter larger than the current time.");
676 startTime = clientScheduler.currentTime();
677 }
678
679 // set debug to switch on
680 ExternalEvent debugOn = new ExternalEventDebugOn(client, true);
681 debugOn.schedule(startTime);
682
683 // set debug to switch off
684 ExternalEvent debugOff = new ExternalEventDebugOff(client, true);
685 debugOff.schedule(stopTime);
686
687 }
688 /**
689 * De-registers a file at the experiment.
690 * Registered files will be flushed and closed after the experiment
691 * has finished. If the file is manually closed by the user and has been
692 * registered at the Experiment,
693 * deRegister it
694 * @param file desmoj.report.FileOutput : The file to be closed with the
695 * end of an Experiment
696 */
697 public void deRegister(FileOutput file) {
698
699 if ( file == null ) {
700 sendWarning (
701 "Can not de-register FileOutput! Command ignored.",
702 "Experiment '"+getName()+"' method 'void deRegister(FileOutput file).'",
703 "The parameter given was a null reference.",
704 "Make sure to only connect valid FileOutputs at the Experiment.");
705 return;
706 }
707
708 fileRegistry.removeElement(file); // remove whether it was inside or not
709
710 }
711 /**
712 * Stopps all running simprocesses that might still be scheduled and
713 * closes the output files.
714 */
715 public void finish() {
716
717 // check if experiment has not been aborted before
718 if ( status >= ABORTED ) {
719 return;
720 }
721
722 // set status to let all simthreads be killed
723 status = ABORTED;
724
725 // close all files still open
726 if ( !fileRegistry.isEmpty() ) {
727 for ( int i = 0 ; i < fileRegistry.size() ; i++ ) {
728 ((FileOutput)fileRegistry.elementAt(i)).close();
729 }
730 }
731
732 // kill all SimThreads still active
733 Thread[] survivors = new Thread[expThreads.activeCount()];
734 expThreads.enumerate(survivors);
735
736 for ( int i = 0 ; i < survivors.length ; i++ ) {
737
738 // print existing threads for controlling purposes only
739 // System.out.println(survivors[i]);
740
741 // if we get the enumeration of survivors, some of them
742 // might not have made it until here and die in between
743 // so an occasional NullPointerException is perfectly
744 // alright and no reason to worry -> we just dump it.
745 try {
746 ((SimThread)survivors[i]).kill();
747 }
748 catch (NullPointerException e){
749 ; // forget it anyway...
750 }
751 }
752
753 }
754 /**
755 * Returns the distributionmanager for this experiment.
756 * Distributions need access to the distributionmanager for handling
757 * antithetic modes, resetting and their initial seeds.
758 * @return desmoj.dist.DistributionManager : The distributionmanager for this
759 * experiment
760 */
761 public DistributionManager getDistributionManager() {
762
763 return distMan;
764
765 }
766 /**
767 * Returns the epsilon value representing the minimum distinguishable
768 * span of simulation time for this experiment.
769 * This has effect on the simulation clock, that won't advance if the
770 * new point of simulation time is smaller than epsilon. In this case
771 * two events are occurring at the same point of simulation time in the report.
772 * @return SimTime : The minimum difference in simulation time
773 */
774 public SimTime getEpsilon() {
775
776 return clientScheduler.getSimClock().getEpsilon();
777
778 }
779 /**
780 * Returns the messagemanager for this experiment.
781 * Messages need access to the MessageManager for distributing the messages
782 * to one or more specified output streams.
783 * @return desmoj.dist.MessageManager : The messagemanager for this
784 * experiment
785 */
786 public MessageDistributor getMessageManager() {
787
788 return messMan;
789
790 }
791 /**
792 * Returns the model that is connected to this experiment or <code>null</code>
793 * if no model is connected so far.
794 * @return Model : The model that this experiment is connected to
795 * or <code>null</code> if no connection is established.
796 */
797 public Model getModel() {
798
799 return client;
800
801 }
802 /**
803 * Returns the name of the path the experiment's report-, trace-, debug- and
804 * error-files are written to.
805 * @return String the experiment's output path
806 */
807 public String getOutputPath() {
808 return new File(pathName).getAbsolutePath();
809 }
810 /** Returns the reference time for this experiment. This is the true
811 * date and time of the start of the simulation run. If no reference
812 * time was specified for this experiment, the default reference time
813 * is returned.
814 * @return String the reference time
815 */
816 public String getReferenceTime() {
817 return trueTimer.getReferenceTime();
818 }
819 /** Returns the reference unit for this experiment. This is the time
820 * unit mapped to a time step of 1.0 in simulation time. So far, Hour,
821 * Minute, Second and Millisecond are supported.
822 * @return int the reference unit as a constant defined in the interface
823 * <code>Units</code>.
824 * @see desmoj.Units
825 */
826 public int getReferenceUnit() {
827 return trueTimer.getReferenceUnit();
828 }
829 /**
830 * Returns the reportmanager for this experiment.
831 * Reports need access to the reportmanager for handling output,
832 * report width parameters and proper sorting of individual reports.
833 * @return desmoj.dist.ReportManager : The reportmanager for this
834 * experiment
835 */
836 public ReportManager getReportManager() {
837
838 return repMan;
839
840 }
841 /**
842 * Returns the resource database for this experiment.
843 * The <code>Res</code> objects need access to the resource database
844 * to note their resource allocations and requests and for deadlock detection.
845 * @return desmoj.ResourceDB : the resource database storing all resource
846 * allocations and requests.
847 * @author Soenke Claassen
848 */
849 public ResourceDB getResourceDB() {
850
851 return resDB;
852 }
853 /**
854 * Returns the scheduler for this experiment.
855 * ModelComponents need access to the scheduler for identifying the
856 * current active entity or process and to schedule themselves or other
857 * schedulables to activate at a given time in the future.
858 * @return Scheduler : The scheduler for this experiment
859 */
860 public Scheduler getScheduler() {
861
862 return clientScheduler;
863
864 }
865 /**
866 * Returns the simclock for this experiment.
867 * ModelComponents need access to the simclock for retrieveing the current
868 * simulation time.
869 * @return SimCLock : The simclock for this experiment
870 */
871 public SimClock getSimClock() {
872
873 return clientScheduler.getSimClock();
874
875 }
876 /**
877 * Returns the SimTime when the experiment is expected to stop running.
878 * @return desmoj.SimTime : The time, the experiment is expected to stop
879 * running.
880 */
881 public SimTime getStopTime() {
882
883 return stopTime;
884 }
885 /**
886 * Returns the threadgroup associated to this experiment.
887 * All Threads are associated to this threadgroup to get control of their
888 * number and state and to have a means to differentiate them
889 * from possible other experiments' threads.
890 * @return java.lang.ThreadGroup
891 */
892 ThreadGroup getThreadGroup() {
893
894 return expThreads;
895
896 }
897 /**
898 * Returns the experiment's number of floating point digits of simulation time
899 * that are displayed in the various output files
900 * @return int : The number of floating point digits of simulation time
901 * to be displayed in output files
902 */
903 public int getTimeFloats() {
904
905 return timeFloats;
906
907 }
908 /**
909 * Displays the current state of the simulation run.
910 * If an experient is aborted, it can not be proceeded.
911 * All SimThreads still active are stopped, the main routine can finish.
912 * @return boolean : Is <code>true</code> if the simulation is aborted,
913 * <code>false</code> if it has not started yet or is still running
914 */
915 public boolean isAborted() {
916
917 return (status>=ABORTED);
918
919 }
920 /**
921 * Shows if this experiment has already been connected to a model.
922 * @return boolean : Is <code>true</code>, if experiment is connected to
923 * a model, <code>false</code> otherwise
924 */
925 public boolean isConnected() {
926
927 return ( status >= CONNECTED ); // model connected
928
929 }
930 /**
931 * Displays the current state of the simulation run.
932 * @return boolean : Is <code>true</code> if the simulation is running,
933 * <code>false</code> if it has not started yet or has already finished
934 */
935 public boolean isRunning() {
936
937 return (status==RUNNING);
938
939 }
940 /**
941 * Returns if a progress bar should be displayed for this experiment or not.
942 * @return boolean : <code>true</code> if a progress bar should be displayed for
943 * this experiment, <code>false</code> otherwise.
944 */
945 public boolean isShowProgressBar() {
946
947 return showProgressBar;
948 }
949 /**
950 * Proceeds with a stopped experiment.
951 * An experiment can be stopped, if either its status is changed from
952 * <code>RUNNING</code> to some other state, the scheduler runs out of
953 * scheduled events or if the <code>check()</code> method of the given
954 * stop <code>Condition</code> returns <code>true</code> after
955 * an Event has been processed.
956 */
957 public void proceed() {
958
959 if ( status < STARTED ) {
960 sendWarning (
961 "Can not proceed with Experiment! Command ignored.",
962 "Experiment: "+getName()+" Method: void proceed().",
963 "The Experiment has not been started yet.",
964 "Only Experiments that have been stopped after method 'start()' has "+
965 "been called can use method 'proceed()' to continue.");
966 return;
967 }
968
969 if ( status > STOPPED ) {
970 sendWarning (
971 "Can not proceed with Experiment! Command ignored.",
972 "Experiment "+getName()+" Method: void proceed().",
973 "The Experiment has already been aborted.",
974 "Use method 'proceed()' only on stopped experiments.");
975 return;
976 }
977
978 // print status message to calm users waiting long, long, long hours...
979 System.out.println(getName() + " starts at simulation time "+
980 getScheduler().currentTime()+"\n ...please wait...");
981
982 // display a progress bar if stop time is known and showProgressBar is true
983 if ( stopTime != null && showProgressBar)
984 {
985 JFrame frame = new ExpProgressBar (this);
986
987 frame.addWindowListener( new WindowAdapter() {
988 public void windowClosing( WindowEvent e ) {
989 System.exit(0);
990 }
991 });
992
993 frame.pack();
994 // frame.setSize(380,90);
995 frame.setVisible(true);
996 }
997
998 status = RUNNING; // now checked to run
999 boolean gotEvent = false; // buffer to check if scheduler works
1000
1001 try {
1002
1003 while ( status==RUNNING ) { // infinite loop until condition/time expired
1004 gotEvent = clientScheduler.processNextEventNote();
1005 if ( gotEvent == false ) status = STOPPED;
1006
1007 // only check stopper if a stopper is set up
1008 if ( stopper!=null ) {
1009 if ( stopper.check() ) status = STOPPED;
1010 }
1011
1012 }
1013
1014 }
1015 catch (DESMOJException e) {
1016 // this is the desaster recovery routine to stop simulation and save
1017 // the report to disc before exiting the faulty experiment
1018 messMan.receive(e.getErrorMessage());
1019 report();
1020 finish();
1021 status = ABORTED;
1022 }
1023
1024 // give warning if reason for stopping was empty eventlist
1025 if ( gotEvent==false ) {
1026 sendWarning (
1027 "No more events scheduled! Experiment is stopped.",
1028 "Experiment '"+getName()+"' method void proceed().",
1029 "The scheduler has run out of events to handle .",
1030 "Make sure to always have events to be scheduled i.e. by letting an "+
1031 "Entity create and schedule its successor.");
1032 }
1033
1034 // print status message to user...
1035 System.out.println(getName()+" stopped at simulation time "+
1036 getScheduler().currentTime());
1037
1038}
1039/**
1040 * Registers a file output at the experiment.
1041 * Registered files will be flushed and closed after the experiment
1042 * has finished. This is handy for modellers producing their own
1043 * output who want their files to be closed at the end of the experiment.
1044 * @param file desmoj.report.FileOutput : The file to be closed with the
1045 * end of an experiment
1046 */
1047public void register(FileOutput file) {
1048
1049 if ( file == null ) {
1050 sendWarning (
1051 "Can not register FileOutput! Command ignored.",
1052 "Experiment '"+getName()+"' method void register(FileOutput file).",
1053 "The parameter given was a null reference.",
1054 "Make sure to only connect valid FileOutputs at the Experiment.");
1055 return;
1056 }
1057
1058 if ( fileRegistry.contains(file) ) return; // file already registered
1059
1060 fileRegistry.addElement(file);
1061
1062}
1063/**
1064 * Connects a model to this experiment.
1065 * The given model must not be submodel of other models and not already be
1066 * connected to some other experiment.
1067 * Otherwise an errormessage will be given and the experiment will
1068 * be stopped.
1069 */
1070void registerModel(Model mainModel) {
1071
1072 if ( mainModel == null ) {
1073 sendWarning (
1074 "Can not register model at experiment! Command ignored.",
1075 "Experiment '"+getName()+"', Method 'void registerModel(Model mainModel)'",
1076 "The parameter passed was a null reference.",
1077 "Make sure to connect a valid main model to this experiment.");
1078 return; // no connection possible.
1079 }
1080
1081 if ( mainModel.getModel() != null ) {
1082 sendWarning (
1083 "Can not register model at experiment! Command ignored.",
1084 "Experiment '"+getName()+"', Method 'void registerModel(Model mainModel)'",
1085 "The model references another model as its owner, thus can not be the "+
1086 "main model.",
1087 "Make sure to connect a valid main model to this experiment.");
1088 return; // no connection possible.
1089 }
1090
1091 if ( isConnected() ) {
1092 sendWarning (
1093 "Can not register model at experiment! Command ignored.",
1094 "Experiment '"+getName()+"', Method 'void registerModel(Model mainModel)'",
1095 "This experiment is already connected to model : "+client.getName(),
1096 "An experiment may only be connected to one main model at a time.");
1097 return; // no connection possible.
1098 }
1099
1100 status = CONNECTED;
1101 client = mainModel;
1102 client.setMain();
1103
1104}
1105/**
1106 * Removes a messagereceiver for debugnotes from the
1107 * experiment's messagedistributor.
1108 * Whenever a model produces a message of that type, it will not be sent to
1109 * the given messagereceiver anymore.
1110 * Note that if the messagereceiver is also registered for other types of
1111 * messages, these will not be affected.
1112 * Use method <code>removeReceiverAll(MessageReceiver msgRec)</code>
1113 * to remove a messagereceiver from all types of messages.
1114 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver to be
1115 * removed from the messagedistributor's list for the given messagetype
1116 */
1117public void removeDebugReceiver(MessageReceiver msgRec) {
1118
1119 if ( msgRec==null) {
1120 sendWarning (
1121 "Can not remove receiver to experiment! Command ignored.",
1122 "Experiment '"+getName()+"', Method 'void removeDebugReceiver"+
1123 "(MessageReceiver msgRec)'",
1124 "The parameter 'msgRec' passed was a null reference.",
1125 "Make sure to give a valid MessageReciever reference before removing it "+
1126 "from the experiment's messaging system.");
1127 return; // do nothing
1128 }
1129
1130 messMan.deRegister(msgRec, debugnote);
1131
1132}
1133/**
1134 * Removes a messagereceiver for errormessages from the
1135 * experiment's messagedistributor.
1136 * Whenever a model produces a message of that type, it will not be sent to
1137 * the given messagereceiver anymore.
1138 * Note that if the messagereceiver is also registered for other types of
1139 * messages, these will not be affected.
1140 * Use method <code>removeReceiverAll(MessageReceiver msgRec)</code>
1141 * to remove a messagereceiver from all types of messages.
1142 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver to be
1143 * removed from the vessagedistributor's list for the given messagetype
1144 */
1145public void removeErrorReceiver(MessageReceiver msgRec) {
1146
1147 if ( msgRec==null) {
1148 sendWarning (
1149 "Can not remove receiver to experiment! Command ignored.",
1150 "Experiment '"+getName()+"', Method 'void removeErrorReceiver"+
1151 "(MessageReceiver msgRec)'",
1152 "The parameter 'msgRec' passed was a null reference.",
1153 "Make sure to give a valid MessageReciever reference before removing it "+
1154 "from the experiment's messaging system.");
1155 return; // do nothing
1156 }
1157
1158 messMan.deRegister(msgRec, errormessage);
1159
1160}
1161/**
1162 * Removes a messagereceiver from the experiment's messagedistributor.
1163 * The given messagereceiver will not receive messages of any type any more
1164 * Use method <code>removeReceiver(MessageReceiver msgRec, Class
1165 * messageType)</code> to remove the messagereceiver from one type of messages
1166 * only.
1167 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver to be
1168 * removed from the messagedistributor's list for the given messagetype
1169 */
1170public void removeReceiver(MessageReceiver msgRec) {
1171
1172 if ( msgRec==null) {
1173 sendWarning (
1174 "Can not remove receiver to experiment! Command ignored.",
1175 "Experiment '"+getName()+"', Method 'void removeReceiver(MessageReceiver "+
1176 "msgRec)'",
1177 "The parameter 'msgRec' passed was a null reference.",
1178 "Make sure to give a valid MessageReciever reference before removing it "+
1179 "from the experiment's messaging system.");
1180 return; // do nothing
1181 }
1182
1183 messMan.deRegister(msgRec);
1184
1185}
1186/**
1187 * Removes a messagereceiver for the given subtype of message from the
1188 * Experiment's messagedistributor.
1189 * Whenever a model produces a message of that type, it will not be sent to
1190 * the given messagereceiver anymore.
1191 * Note that if the messagereceiver is also registered for other types of
1192 * messages, these will not be affected.
1193 * Use method <code>removeReceiverAll(MessageReceiver msgRec)</code>
1194 * to remove a messagereceiver from all types of messages.
1195 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver to be
1196 * removed from the messagedistributor's list for the given messagetype
1197 * @param messageType Class : The type of message not to be sent to the given
1198 * messagereceiver
1199 */
1200public void removeReceiver(MessageReceiver msgRec, Class messageType) {
1201
1202 if ( msgRec==null) {
1203 sendWarning (
1204 "Can not remove receiver to experiment! Command ignored.",
1205 "Experiment '"+getName()+"', Method 'void removeReceiver(MessageReceiver "+
1206 "msgRec, Class messageType)'",
1207 "The parameter 'msgRec' passed was a null reference.",
1208 "Make sure to give a valid MessageReciever reference before removing it "+
1209 "from the experiment's messaging system.");
1210 return; // do nothing
1211 }
1212
1213 if ( messageType==null) {
1214 sendWarning (
1215 "Can not remove receiver to experiment! Command ignored.",
1216 "Experiment '"+getName()+"', Method 'void removeReceiver(MessageReceiver "+
1217 "msgRec, Class messageType)'",
1218 "The parameter 'msgRec' passed was a null reference.",
1219 "Make sure to give a valid MessageReciever reference before removing it "+
1220 "from the experiment's messaging system.");
1221 return; // do nothing
1222 }
1223
1224 messMan.deRegister(msgRec, messageType);
1225
1226}
1227/**
1228 * Removes a messagereceiver for tracenotes from the
1229 * experiment's messagedistributor.
1230 * Whenever a model produces a message of that type, it will not be sent to
1231 * the given messagereceiver anymore.
1232 * Note that if the messagereceiver is also registered for other types of
1233 * messages, these will not be affected.
1234 * Use method <code>removeReceiverAll(MessageReceiver msgRec)</code>
1235 * to remove a messagereceiver from all types of messages.
1236 * @param trcRec desmoj.report.MessageReceiver : The new messagereceiver to be
1237 * removed from the messagedistributor's list for the given messagetype
1238 */
1239public void removeTraceReceiver(MessageReceiver msgRec) {
1240
1241 if ( msgRec==null) {
1242 sendWarning (
1243 "Can not remove receiver to experiment! Command ignored.",
1244 "Experiment '"+getName()+"', Method 'void removeTraceReceiver"+
1245 "(MessageReceiver msgRec)'",
1246 "The parameter 'msgRec' passed was a null reference.",
1247 "Make sure to give a valid MessageReciever reference before removing it "+
1248 "from the experiment's messaging system.");
1249 return; // do nothing
1250 }
1251
1252 messMan.deRegister(msgRec, tracenote);
1253
1254}
1255/**
1256 * Overrides inherited <code>NamedObjectImp.rename(String newName)</code> method
1257 * to prevent the user from changing the experiment's name during an
1258 * experiment.
1259 * Renaming is not allowed with experiments, since it would not allow
1260 * the user to identify the reports produced by an experiment.
1261 * The method simply returns without changing the experiment's name,
1262 * ignoring the given parameter.
1263 * @param newName java.lang.String : The parameter given is not taken as the
1264 * new name, method simply returns
1265 */
1266public void reName(String newName) {
1267
1268 // do nothing since renaming experiments is not allowed
1269 // would do too much confusion
1270
1271}
1272/**
1273 * Writes a report about the model connected top this experiment,
1274 * its reportable components and all related submodels into the report output.
1275 * Note that a report can only be produced, if a valid main model
1276 * is already connected to the experiment.
1277 */
1278public void report() {
1279
1280 // just pass on the call with main model as parameter
1281 report(client);
1282
1283}
1284/**
1285 * Writes a report about the given model which has to be connected to this
1286 * experiment as main model or as a submodel.
1287 * Note that this will report about a branch of the tree of submodels
1288 * constructed. A report will only be produced, if the model given is connected
1289 * to this experiment.
1290 * All reportable components of this model and all related submodels will be
1291 * sent to the report output configured at the experiment's messagedistributor.
1292 * Note that a report can only be produced, if a valid main model
1293 * is already connected to the experiment.
1294 */
1295public void report(Model m) {
1296
1297 Enumeration reporters; // buffer for the reportmanager returned by client
1298
1299 if ( status < CONNECTED ) {
1300 sendWarning (
1301 "Can not produce report! Command ignored.",
1302 "Experiment: "+getName()+" Method: void report(Model m).",
1303 "The Experiment has not been connected to a model to report about yet.",
1304 "Connect a model to the experiment first using the model's method "+
1305 "connectToExperiment(Experiment exp).");
1306 return; // no client there to be reported
1307 }
1308
1309 if ( status >= ABORTED ) {
1310 // do nothing since experiment has already been aborted and all
1311 // output channels are already shut down
1312 return; // Experiment aborted
1313 }
1314
1315 if ( m == null ) {
1316 sendWarning (
1317 "Can not produce report! Command ignored.",
1318 "Experiment: "+getName()+" Method: void report(Model m).",
1319 "The model parameter given is a null reference.",
1320 "Always make sure to use valid references.");
1321 return; // no model there to be reported
1322 }
1323
1324 if ( m.getExperiment() != this ) {
1325 sendWarning (
1326 "Can not produce report! Command ignored.",
1327 "Experiment: "+getName()+" Method: void report(Model m).",
1328 "The model parameter given is connected to a different experiment.",
1329 "Only experiments connected to theat model can produce reports "+
1330 "about that model.");
1331 return; // model connected to other experiment
1332 }
1333
1334 // get the client's reportmanager containing all reporters in sorted order
1335 reporters = m.report();
1336
1337 // get all out according to sorted order and send them to the report output
1338 // registered at the experiment's messagemanager
1339 while ( reporters.hasMoreElements() ) {
1340
1341 messMan.receive( ( (Reporter)reporters.nextElement() ) );
1342
1343 }
1344
1345}
1346 /** Resets the time format to be used for output of true time Strings to
1347 * the default pattern: <tt>dd.MM.yyyy HH:mm:ss:SSS</tt>.
1348 */
1349 public void resetOutputTimeFormat() {
1350 trueTimer.resetTimeFormat();
1351 }
1352 /** Schedules an <code>ExternalEventTimedTrace</code> event to insert an entry
1353 * in the trace file stating the true time (and time unit) of the given
1354 * sim time. This private helper method is called in the methods <code>
1355 * tracePeriod(SimTime, SimTime)</code>, <code>traceOn(SimTime)</code>
1356 * and <code>traceOff(SimTime)</code>.
1357 * @param simTime SimTime : the sim time for the event to take place
1358 * @param whatTime String : a description of this point in (simulation) time
1359 * @param directSuccessor Event : the event before which the generated
1360 * <code>ExternalEventTimedTrace</code> event should be scheduled; if no
1361 * such event is specified the generated event is scheduled "normally"
1362 * at the given sim time.
1363 */
1364 private void scheduleTimedTraceEvent(SimTime simTime, String whatTime,
1365 Event directSuccessor)
1366 {
1367 int refUnit = trueTimer.getReferenceUnit();
1368 StringBuffer pattern = new StringBuffer("dd.MM.yyyy HH:mm");
1369 switch (refUnit) {
1370 case Units.MS: pattern.insert(16, ":SSS");
1371 case Units.S : pattern.insert(16, ":ss");
1372 }
1373 trueTimer.setTimeFormat(pattern.toString());
1374 String time = trueTimer.toTrueTime(simTime);
1375 trueTimer.resetTimeFormat();
1376 ExternalEventTimedTrace event = new ExternalEventTimedTrace(time,
1377 refUnit,
1378 whatTime,
1379 this.client);
1380 if (directSuccessor == null) {
1381 event.schedule(simTime);
1382 }
1383 else {
1384 event.scheduleBefore(directSuccessor);
1385 }
1386 }
1387/**
1388 * Creates and sends a debugnote to the messagedistributor.
1389 * Be sure to have a correct location, since the object and method that the
1390 * error becomes apparent is not necessary the location it was produced in.
1391 * The information about the simulation time is extracted from the
1392 * Experiment and must not be given as a parameter.
1393 * @param description java.lang.String : The description of the error that
1394 * occured
1395 * @param location java.lang.String : The class and method the error occured in
1396 * @param reason java.lang.String : The reason most probably responsible for
1397 * the error to occur
1398 * @param prevention java.lang.String : The measures a user should take to
1399 * prevent this warning to be issued again
1400 */
1401void sendDebugNote(String component, String description) {
1402
1403 // comnpose the DebugNote and send it in one command
1404 sendMessage( new DebugNote( clientScheduler.getCurrentModel(),
1405 clientScheduler.getSimClock().getTime(),
1406 component, description ) );
1407
1408}
1409/**
1410 * Sends a message to the messagedistributor.
1411 * Note that there are other shorthands for sending the standard DESMO-J
1412 * messages.
1413 * @param m Message : The Message to be transmitted
1414 * @see ModelComponent#sendTraceNote
1415 * @see ModelComponent#sendDebugNote
1416 * @see ModelComponent#sendWarning
1417 */
1418void sendMessage(Message m) {
1419
1420 if ( m==null ) {
1421 sendWarning ( "Can't send Message!",
1422 "Experiment :"+getName()+" Method: SendMessage(Message m)",
1423 "The Message given as parameter is a null reference.",
1424 "Be sure to have a valid Message reference.");
1425 return; // no proper parameter
1426 }
1427
1428 messMan.receive(m);
1429
1430}
1431/**
1432 * Creates and sends an error message to the messagedistributor to warn the
1433 * modeller that some conditions required by the framework are not met.
1434 * Be sure to have a correct location, since the object and method that the
1435 * error becomes apparent is not necessary the location it was produced in.
1436 * The information about the simulation time is extracted from the
1437 * experiment and must not be given as a parameter.
1438 * @param description java.lang.String : The description of the error that
1439 * occured
1440 * @param location java.lang.String : The class and method the error occured in
1441 * @param reason java.lang.String : The reason most probably responsible for
1442 * the error to occur
1443 * @param prevention java.lang.String : The measures a user should take to
1444 * prevent this warning to be issued again
1445 */
1446void sendWarning(String description, String location,
1447 String reason, String prevention) {
1448
1449 // comnpose the WarningMessage and send it in one command
1450 sendMessage( new ErrorMessage( clientScheduler.getCurrentModel(),
1451 description, location,
1452 reason, prevention,
1453 clientScheduler.getSimClock().g