Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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>&lt;date&gt;&lt;blank&gt;&lt;time&gt;</tt> where <tt>&lt;date&gt; =
272  * [d]d.[M]M.[yy]yy</tt> and
273  * <tt>&lt;time&gt; = [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>&lt;date&gt;&lt;blank&gt;&lt;time&gt;</tt> where <tt>&lt;date&gt; =
307  * [d]d.[M]M.[yy]yy</tt> and
308  * <tt>&lt;time&gt; = [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