| 1 | package desmoj.core.simulator; |
| 2 | |
| 3 | import java.awt.event.WindowAdapter; |
| 4 | import java.awt.event.WindowEvent; |
| 5 | import java.io.File; |
| 6 | import java.util.ArrayList; |
| 7 | import java.util.List; |
| 8 | import java.util.concurrent.TimeUnit; |
| 9 | |
| 10 | import javax.swing.JFrame; |
| 11 | |
| 12 | import desmoj.core.dist.DistributionManager; |
| 13 | import desmoj.core.exception.DESMOJException; |
| 14 | import desmoj.core.report.DebugNote; |
| 15 | import desmoj.core.report.ErrorMessage; |
| 16 | import desmoj.core.report.FileOutput; |
| 17 | import desmoj.core.report.Message; |
| 18 | import desmoj.core.report.MessageDistributor; |
| 19 | import desmoj.core.report.MessageReceiver; |
| 20 | import desmoj.core.report.OutputType; |
| 21 | import desmoj.core.report.OutputTypeEndToExport; |
| 22 | import desmoj.core.report.Reporter; |
| 23 | import desmoj.core.report.TraceNote; |
| 24 | |
| 25 | /** |
| 26 | * Experiment is the class that provides the infrastructure for running the |
| 27 | * simulation of a model. It contains all data structures necessary to simulate |
| 28 | * the model and takes care of all necessary output. To actually run an |
| 29 | * experiment, a new instance of the experiment class and a new instance of the |
| 30 | * desired model have to be created. To link both instances, call the |
| 31 | * <code>connectToExperiment(Experiment e)</code> method of the model instance |
| 32 | * and pass the new experiment as a parameter. |
| 33 | * |
| 34 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
| 35 | * @author Tim Lechler |
| 36 | * @author modified by Soenke Claassen, Ruth Meyer, Nicolas Knaak, Gunnar |
| 37 | * Kiesel,Felix Klueckmann |
| 38 | * |
| 39 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 40 | * you may not use this file except in compliance with the License. You |
| 41 | * may obtain a copy of the License at |
| 42 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 43 | * |
| 44 | * Unless required by applicable law or agreed to in writing, software |
| 45 | * distributed under the License is distributed on an "AS IS" |
| 46 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
| 47 | * or implied. See the License for the specific language governing |
| 48 | * permissions and limitations under the License. |
| 49 | * |
| 50 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
| 51 | * @modifier new Example Variable _traceOutput, _reportOutput for Outputclasscollection |
| 52 | * new class constructors |
| 53 | * Experiment(String , String , ArrayList<String> , ArrayList<String> ,ArrayList<String> , ArrayList<String> ) and |
| 54 | * Experiment(String , String , TimeUnit ,TimeUnit , TimeFormatter ,ArrayList<String> , |
| 55 | * ArrayList<String> ,ArrayList<String> ,ArrayList<String> ) |
| 56 | * @author Xiufeng Li |
| 57 | */ |
| 58 | public class Experiment extends NamedObject { |
| 59 | |
| 60 | /** |
| 61 | * The experiment's name catalog for ensuring uniqueness of simulation |
| 62 | * object names within a single experiment. |
| 63 | */ |
| 64 | private NameCatalog _nameCatalog = new NameCatalog(); |
| 65 | |
| 66 | /** |
| 67 | * The default report output |
| 68 | */ |
| 69 | public static final String DEFAULT_REPORT_OUTPUT_TYPE = "desmoj.core.report.HTMLReportOutput"; |
| 70 | |
| 71 | /** |
| 72 | * The default trace output |
| 73 | */ |
| 74 | public static final String DEFAULT_TRACE_OUTPUT_TYPE = "desmoj.core.report.HTMLTraceOutput"; |
| 75 | |
| 76 | /** |
| 77 | * The default error output |
| 78 | */ |
| 79 | public static final String DEFAULT_ERROR_OUTPUT_TYPE = "desmoj.core.report.HTMLErrorOutput"; |
| 80 | |
| 81 | /** |
| 82 | * The default debug output |
| 83 | */ |
| 84 | public static final String DEFAULT_DEBUG_OUTPUT_TYPE = "desmoj.core.report.HTMLDebugOutput"; |
| 85 | |
| 86 | /** |
| 87 | * Status of an Experiment just created without any accessories created yet. |
| 88 | */ |
| 89 | public static final int NOT_INITIALIZED = -3; |
| 90 | |
| 91 | /** |
| 92 | * Status of an Experiment instantiated with all needed accessories |
| 93 | * available. |
| 94 | */ |
| 95 | public static final int INITIALIZED = -2; |
| 96 | |
| 97 | /** |
| 98 | * Status of an Experiment connected to a Model and ready to be started. |
| 99 | */ |
| 100 | public static final int CONNECTED = -1; |
| 101 | |
| 102 | /** |
| 103 | * Status of an Experiment being started. Only if an Experiment is |
| 104 | */ |
| 105 | public static final int STARTED = 0; |
| 106 | |
| 107 | /** |
| 108 | * Status of an Experiment stopped after having run. |
| 109 | */ |
| 110 | public static final int STOPPED = 1; |
| 111 | |
| 112 | /** |
| 113 | * Status of an Experiment currently running the simulation. |
| 114 | */ |
| 115 | public static final int RUNNING = 2; |
| 116 | |
| 117 | /** |
| 118 | * Status of an Experiment finished and to be cleared. |
| 119 | */ |
| 120 | public static final int ABORTED = 3; |
| 121 | |
| 122 | /** |
| 123 | * The last suffix used with filenames when creating multiple batch runs of |
| 124 | * an experiment. |
| 125 | */ |
| 126 | private static int lastSuffix; |
| 127 | |
| 128 | /** |
| 129 | * The class reference to messages of type desmoj.core.report.TraceNote |
| 130 | */ |
| 131 | static Class<desmoj.core.report.TraceNote> tracenote; |
| 132 | |
| 133 | /** |
| 134 | * The class reference to messages of type desmoj.core.report.DebugNote |
| 135 | */ |
| 136 | static Class<desmoj.core.report.DebugNote> debugnote; |
| 137 | |
| 138 | /** |
| 139 | * The class reference to messages of type desmoj.core.report.ErrorMessage |
| 140 | */ |
| 141 | static Class<desmoj.core.report.ErrorMessage> errormessage; |
| 142 | |
| 143 | /** |
| 144 | * The class reference to messages of type desmoj.core.report.Reporter |
| 145 | */ |
| 146 | static Class<desmoj.core.report.Reporter> reporter; |
| 147 | |
| 148 | /** |
| 149 | * Flag indicating to suppress notifications like 'experiment started'. |
| 150 | */ |
| 151 | private boolean _silent; |
| 152 | |
| 153 | /** |
| 154 | * The description of this Experiment |
| 155 | */ |
| 156 | private String _description = null; |
| 157 | |
| 158 | /** |
| 159 | * Flag indicating if the simulation is running. |
| 160 | */ |
| 161 | private int _status; |
| 162 | |
| 163 | /** |
| 164 | * The model to be run by this experiment. |
| 165 | */ |
| 166 | private Model _client; |
| 167 | |
| 168 | /** |
| 169 | * The scheduler used for this experiment. |
| 170 | */ |
| 171 | protected Scheduler clientScheduler; |
| 172 | |
| 173 | /** |
| 174 | * The distribution manager for the model's distributions. |
| 175 | */ |
| 176 | private DistributionManager _distMan; |
| 177 | |
| 178 | /** |
| 179 | * The message manager for the model's messages. |
| 180 | */ |
| 181 | private MessageDistributor _messMan; |
| 182 | |
| 183 | /** |
| 184 | * The ThreadGroup for this Experiment. |
| 185 | */ |
| 186 | private ThreadGroup _expThreads; |
| 187 | |
| 188 | /** |
| 189 | * The list to register all OutputType objects to close them after finishing |
| 190 | * the Experiment. |
| 191 | */ |
| 192 | private java.util.ArrayList<OutputType> _registryOutputType; |
| 193 | |
| 194 | /** |
| 195 | * The list to register all FileOutput objects to close them after finishing |
| 196 | * the Experiment. |
| 197 | */ |
| 198 | private java.util.ArrayList<FileOutput> _registryFileOutput; |
| 199 | |
| 200 | /** |
| 201 | * The resource database storing all resource allocations and requests. Also |
| 202 | * needed to detect deadlocks. |
| 203 | */ |
| 204 | private ResourceDB _resDB; |
| 205 | |
| 206 | /** |
| 207 | * The TimeInstant when the experiment is supposed to stop. Is initially |
| 208 | * <code>null</code> and will be set only if the user provides a time limit. |
| 209 | */ |
| 210 | private TimeInstant _stopTime = null; |
| 211 | |
| 212 | /** |
| 213 | * The event to stop the experiment. Is initially <code>null</code> and will |
| 214 | * be set only if the user provides a time limit. |
| 215 | */ |
| 216 | private ExternalEventStop _stopTimeEvent = null; |
| 217 | |
| 218 | /** |
| 219 | * A list of <code>Condition</code>s which cause the experiment to stop. The |
| 220 | * user has to implement the <code>check()</code> method of the |
| 221 | * <code>Condition</code>s in order to effectively stop an experiment. |
| 222 | */ |
| 223 | private List<ModelCondition> _stopConditions; |
| 224 | |
| 225 | /** |
| 226 | * Flag indicating whether a progressbar for this experiment should be |
| 227 | * displayed or not. |
| 228 | */ |
| 229 | private boolean _showProgressBar; |
| 230 | |
| 231 | /** |
| 232 | * Specifies an output path for the report files (Modification by Nicolas |
| 233 | * Knaak, 02/2001) |
| 234 | */ |
| 235 | private String _pathName; |
| 236 | |
| 237 | /** |
| 238 | * Delay between steps of the scheduler in milliseconds. Necessary for |
| 239 | * online observation of experiments in FAMOS. (Modification by Nicolas |
| 240 | * Knaak, 07/2001) |
| 241 | */ |
| 242 | private long _delayInMillis = 0; |
| 243 | |
| 244 | /** |
| 245 | * The real time (wallclock time) start time of the simulation run. |
| 246 | * (Modification by Felix Klueckmann, 05/2009) |
| 247 | */ |
| 248 | private long _realTimeStartTime; |
| 249 | |
| 250 | /** |
| 251 | * The output types of the debug channel. |
| 252 | */ |
| 253 | private ArrayList<OutputType> _debugOutput; |
| 254 | |
| 255 | /** |
| 256 | * The output types of the report channel. |
| 257 | */ |
| 258 | private ArrayList<OutputType> _reportOutput; |
| 259 | |
| 260 | /** |
| 261 | * The output types of the error channel. |
| 262 | */ |
| 263 | private ArrayList<OutputType> _errorOutput; |
| 264 | |
| 265 | /** |
| 266 | * The output types of the trance channel. |
| 267 | */ |
| 268 | private ArrayList<OutputType> _traceOutput; |
| 269 | |
| 270 | /** |
| 271 | * Constructs a new Experiment with a given name. |
| 272 | * Data channel output (report, error, debug, trace) will either be |
| 273 | * written to HTML files in the current directory. |
| 274 | * Epsilon (granularity of simulation) defaults to a microsecond, |
| 275 | * reference time (default time unit) to a second. |
| 276 | * |
| 277 | * @param name |
| 278 | * String : The name of the experiment determining the |
| 279 | * outputfile's names, too. So please avoid characters that your |
| 280 | * local filesystem does not support in filenames. |
| 281 | */ |
| 282 | public Experiment(String name) { |
| 283 | this(name, true); |
| 284 | } |
| 285 | |
| 286 | /** |
| 287 | * Constructs a new Experiment with the given parameters. Experiment name can be specified. |
| 288 | * Data channel output (report, error, debug, trace) will either be |
| 289 | * suppressed or written to HTML files in the current directory. |
| 290 | * Epsilon (granularity of simulation) defaults to a microsecond, |
| 291 | * reference time (default time unit) to a second. |
| 292 | * |
| 293 | * @param name |
| 294 | * String : The name of the experiment determining the |
| 295 | * outputfile's names, too. So please avoid characters that your |
| 296 | * local filesystem does not support in filenames. |
| 297 | * @param output |
| 298 | * boolean : This flag indicates if the experiment should write |
| 299 | * output files in the default format (HTML) or no output files |
| 300 | * at all. |
| 301 | */ |
| 302 | public Experiment(String name, boolean output) { |
| 303 | this(name, ".", TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
| 304 | output ? DEFAULT_REPORT_OUTPUT_TYPE : null, |
| 305 | output ? DEFAULT_TRACE_OUTPUT_TYPE : null, |
| 306 | output ? DEFAULT_ERROR_OUTPUT_TYPE : null, |
| 307 | output ? DEFAULT_DEBUG_OUTPUT_TYPE : null); // call most special |
| 308 | // constructor |
| 309 | } |
| 310 | |
| 311 | /** |
| 312 | * Constructs a new Experiment with the given parameters. Experiment name and output path |
| 313 | * can be specified. Data channel output (report, error, debug, trace) will either be |
| 314 | * written to HTML files, epsilon (granularity of simulation) defaults to a microsecond, |
| 315 | * reference time (default time unit) to a second. |
| 316 | * |
| 317 | * @param name |
| 318 | * String : The name of the experiment determining the |
| 319 | * outputfile's names, too. So please avoid characters that your |
| 320 | * local filesystem does not support in filenames. |
| 321 | * @param pathName |
| 322 | * java.lang.String : The output path for report files |
| 323 | */ |
| 324 | public Experiment(String name, String pathName) { |
| 325 | |
| 326 | this(name, pathName, DEFAULT_REPORT_OUTPUT_TYPE, |
| 327 | DEFAULT_TRACE_OUTPUT_TYPE, DEFAULT_ERROR_OUTPUT_TYPE, |
| 328 | DEFAULT_DEBUG_OUTPUT_TYPE); |
| 329 | // call more special constructor |
| 330 | |
| 331 | } |
| 332 | |
| 333 | /** |
| 334 | * Constructs a new Experiment with the given parameters. This is a shortcut |
| 335 | * constructor. Parameters for the name, the granularity(epsilon), the |
| 336 | * reference time unit and a time formatter are needed. All other possible |
| 337 | * settings are set to default values. These settings for an experiment |
| 338 | * without special ExperimentOptions are: |
| 339 | * <ol> |
| 340 | * <li>seed = 979 : The initial seed setting for the seed-generator</li> |
| 341 | * </ol> |
| 342 | * The default stop condition for this experiment will never interfere, |
| 343 | * always returning false. |
| 344 | * |
| 345 | * @param name |
| 346 | * String : The name of the experiment determining the |
| 347 | * outputfile's names, too. So please avoid characters that your |
| 348 | * local filesystem does not support in filenames. |
| 349 | * @param epsilon |
| 350 | * java.util.concurrent.TimeUnit: The granularity of simulation |
| 351 | * time. |
| 352 | * @param referenceUnit |
| 353 | * java.util.concurrent.TimeUnit : In statements without an |
| 354 | * explicit declaration of a TimeUnit the reference unit is used. |
| 355 | * @param formatter |
| 356 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
| 357 | * will be formatted in the output files. |
| 358 | * |
| 359 | * @see java.util.concurrent.TimeUnit |
| 360 | */ |
| 361 | public Experiment(String name, TimeUnit epsilon, TimeUnit referenceUnit, |
| 362 | TimeFormatter formatter) { |
| 363 | // call most special constructor |
| 364 | this(name, ".", epsilon, referenceUnit, formatter, |
| 365 | DEFAULT_REPORT_OUTPUT_TYPE, DEFAULT_TRACE_OUTPUT_TYPE, |
| 366 | DEFAULT_ERROR_OUTPUT_TYPE, DEFAULT_DEBUG_OUTPUT_TYPE); |
| 367 | |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * Constructs a new Experiment with the given parameters. Experiment name, output path |
| 372 | * and a single file type per output channel can be specified. |
| 373 | * Epsilon (granularity of simulation) defaults to a microsecond, |
| 374 | * reference time (default time unit) to a second. |
| 375 | * |
| 376 | * @param name |
| 377 | * String : The name of the experiment determining the |
| 378 | * outputfile's names, too. So please avoid characters that your |
| 379 | * local filesystem does not support in filenames. |
| 380 | * @param pathName |
| 381 | * java.lang.String : The output path for report files |
| 382 | * @see desmoj.core.simulator.Units |
| 383 | * @param reportOutputType |
| 384 | * @param traceOutputType |
| 385 | * @param errorOutputType |
| 386 | * @param debugOutputType |
| 387 | */ |
| 388 | public Experiment(String name, String pathName, String reportOutputType, |
| 389 | String traceOutputType, String errorOutputType, |
| 390 | String debugOutputType) { |
| 391 | this(name, pathName, TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
| 392 | reportOutputType, traceOutputType, errorOutputType, |
| 393 | debugOutputType); |
| 394 | } |
| 395 | |
| 396 | /** |
| 397 | * Constructs a new Experiment with the given parameters. Experiment name, output path, epsilon, reference time unit, time format, |
| 398 | * can be specified. Same holds for file output channels, though this constructor assumes a single file type per output channel. |
| 399 | * |
| 400 | * @param name |
| 401 | * String : The name of the experiment determining the |
| 402 | * outputfile's names, too. So please avoid characters that your |
| 403 | * local filesystem does not support in filenames. |
| 404 | * @param pathName |
| 405 | * java.lang.String : The output path for report files |
| 406 | * @param epsilon |
| 407 | * java.util.concurrent.TimeUnit: The granularity of simulation |
| 408 | * time. |
| 409 | * @param referenceUnit |
| 410 | * java.util.concurrent.TimeUnit : In statements without an |
| 411 | * explicit declaration of a TimeUnit the reference unit is used. |
| 412 | * @param formatter |
| 413 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
| 414 | * will be formatted in the output files. |
| 415 | * |
| 416 | * @see java.util.concurrent.TimeUnit |
| 417 | */ |
| 418 | public Experiment(String name, String pathName, TimeUnit epsilon, |
| 419 | TimeUnit referenceUnit, TimeFormatter formatter, |
| 420 | String reportOutputType, String traceOutputType, |
| 421 | String errorOutputType, String debugOutputType) { |
| 422 | super(name); // create a NamedObject with an attitude ;-) |
| 423 | |
| 424 | ArrayList<String> reportOutputs = new ArrayList<String>(); if (reportOutputType!=null) reportOutputs.add(reportOutputType); |
| 425 | ArrayList<String> traceOutputs = new ArrayList<String>(); if (traceOutputType!=null) traceOutputs.add(traceOutputType); |
| 426 | ArrayList<String> errorOutputs = new ArrayList<String>(); if (errorOutputType!=null) errorOutputs.add(errorOutputType); |
| 427 | ArrayList<String> debugOutputs = new ArrayList<String>(); if (debugOutputType!=null) debugOutputs.add(debugOutputType); |
| 428 | |
| 429 | setupExperiment(name, pathName, epsilon, referenceUnit, formatter, reportOutputs, traceOutputs, errorOutputs, debugOutputs); |
| 430 | } |
| 431 | |
| 432 | /** |
| 433 | * Constructs a new Experiment with the given parameters. This is the most |
| 434 | * flexible constructor. Experiment name, output path, epsilon, reference time unit, time format, |
| 435 | * and multiple file types per output channel can be specified. |
| 436 | * |
| 437 | * @param name |
| 438 | * String : The name of the experiment determining the |
| 439 | * outputfile's names, too. So please avoid characters that your |
| 440 | * local filesystem does not support in filenames. |
| 441 | * @param outputPath |
| 442 | * java.lang.String : The output path for report files |
| 443 | * @param epsilon |
| 444 | * java.util.concurrent.TimeUnit: The granularity of simulation |
| 445 | * time. |
| 446 | * @param referenceUnit |
| 447 | * java.util.concurrent.TimeUnit : In statements without an |
| 448 | * explicit declaration of a TimeUnit the reference unit is used. |
| 449 | * @param formatter |
| 450 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
| 451 | * will be formatted in the output files. |
| 452 | * |
| 453 | * @see java.util.concurrent.TimeUnit |
| 454 | */ |
| 455 | public Experiment(String name, String outputPath, TimeUnit epsilon, |
| 456 | TimeUnit referenceUnit, TimeFormatter formatter, |
| 457 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
| 458 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) |
| 459 | { |
| 460 | super(name); |
| 461 | setupExperiment(name, outputPath, epsilon, referenceUnit, formatter, reportOutputs, traceOutputs, errorOutputs, debugOutputs); |
| 462 | } |
| 463 | /** |
| 464 | * Constructs a new Experiment with the given parameters. Experiment name, output path |
| 465 | * and a multiple file type per output channel can be specified. |
| 466 | * Epsilon (granularity of simulation) defaults to a microsecond, |
| 467 | * reference time (default time unit) to a second. |
| 468 | * |
| 469 | * @param name |
| 470 | * String : The name of the experiment determining the |
| 471 | * outputfile's names, too. So please avoid characters that your |
| 472 | * local filesystem does not support in filenames. |
| 473 | * @param outputPath |
| 474 | * java.lang.String : The output path for report files |
| 475 | * @see desmoj.core.simulator.Units |
| 476 | */ |
| 477 | public Experiment(String name, String outputPath, |
| 478 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
| 479 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) { |
| 480 | this(name, outputPath, TimeUnit.MICROSECONDS, TimeUnit.SECONDS, null, |
| 481 | reportOutputs, traceOutputs, errorOutputs, |
| 482 | debugOutputs); |
| 483 | } |
| 484 | |
| 485 | |
| 486 | /** |
| 487 | * Private helper method to initialize the experiment; should be called |
| 488 | * from all constructors. |
| 489 | * |
| 490 | * @param name |
| 491 | * String : The name of the experiment determining the |
| 492 | * outputfile's names, too. So please avoid characters that your |
| 493 | * local filesystem does not support in filenames. |
| 494 | * @param outputPath |
| 495 | * java.lang.String : The output path for report files |
| 496 | * @param epsilon |
| 497 | * java.util.concurrent.TimeUnit: The granularity of simulation |
| 498 | * time. |
| 499 | * @param referenceUnit |
| 500 | * java.util.concurrent.TimeUnit : In statements without an |
| 501 | * explicit declaration of a TimeUnit the reference unit is used. |
| 502 | * @param formatter |
| 503 | * desmoj.core.simulator.TimeFormatter: Defines how time values |
| 504 | * will be formatted in the output files. |
| 505 | * |
| 506 | * @see java.util.concurrent.TimeUnit |
| 507 | */ |
| 508 | private void setupExperiment(String name, String outputPath, TimeUnit epsilon, |
| 509 | TimeUnit referenceUnit, TimeFormatter formatter, |
| 510 | ArrayList<String> reportOutputs, ArrayList<String> traceOutputs, |
| 511 | ArrayList<String> errorOutputs, ArrayList<String> debugOutputs) |
| 512 | { |
| 513 | // initialize variables |
| 514 | _traceOutput = new ArrayList<OutputType>(); |
| 515 | _debugOutput = new ArrayList<OutputType>(); |
| 516 | _errorOutput = new ArrayList<OutputType>(); |
| 517 | _reportOutput = new ArrayList<OutputType>(); |
| 518 | _status = NOT_INITIALIZED; |
| 519 | _stopConditions = new ArrayList<ModelCondition>(); // empty, i.e. no Stopper |
| 520 | // can be set at |
| 521 | // instantiation time |
| 522 | _expThreads = new ThreadGroup(name); |
| 523 | _registryFileOutput = new ArrayList<FileOutput>(); |
| 524 | _registryOutputType = new ArrayList<OutputType>(); |
| 525 | lastSuffix = 0; // no batches have run so far ;-) |
| 526 | _showProgressBar = true; // display a progress bar for this experiment |
| 527 | _silent = false; // notify the user about what is going on |
| 528 | |
| 529 | // Check and set output path |
| 530 | // if (pathName == null |
| 531 | // || (pathName != null && (pathName.isEmpty() || pathName |
| 532 | // .equals(".")))) |
| 533 | // this.pathName = System.getProperty("user.dir", "."); |
| 534 | // else |
| 535 | this._pathName = outputPath; |
| 536 | |
| 537 | // set class variables for basic messagetypes |
| 538 | try |
| 539 | { |
| 540 | tracenote = (Class<TraceNote>) Class |
| 541 | .forName("desmoj.core.report.TraceNote"); |
| 542 | debugnote = (Class<DebugNote>) Class |
| 543 | .forName("desmoj.core.report.DebugNote"); |
| 544 | errormessage = (Class<ErrorMessage>) Class |
| 545 | .forName("desmoj.core.report.ErrorMessage"); |
| 546 | reporter = (Class<Reporter>) Class |
| 547 | .forName("desmoj.core.report.Reporter"); |
| 548 | } catch (ClassNotFoundException cnfEx) |
| 549 | { |
| 550 | System.err.println("Can not create Experiment!"); |
| 551 | System.err.println("Constructor of desmoj.core.Experiment."); |
| 552 | System.err.println("Classes are probably not installed correctly."); |
| 553 | System.err.println("Check your CLASSPATH setting."); |
| 554 | System.err.println("Exception caught : " + cnfEx); |
| 555 | } |
| 556 | |
| 557 | // create output system first |
| 558 | _messMan = new MessageDistributor(); |
| 559 | |
| 560 | // create and register the debug output |
| 561 | for (String debugOutputType : debugOutputs) |
| 562 | { |
| 563 | try |
| 564 | { |
| 565 | Class<OutputType> debugOType = (Class<OutputType>) Class |
| 566 | .forName((debugOutputType != null) ? debugOutputType |
| 567 | : DEFAULT_DEBUG_OUTPUT_TYPE); |
| 568 | OutputType dbg = debugOType.newInstance(); |
| 569 | _debugOutput.add(dbg); |
| 570 | if (debugOutputType != null) |
| 571 | dbg.open(_pathName, name); |
| 572 | _messMan.register(dbg, debugnote); |
| 573 | _messMan.switchOff(debugnote); |
| 574 | register(dbg); |
| 575 | } catch (Exception e) |
| 576 | { |
| 577 | System.err.println(e.toString()); |
| 578 | } |
| 579 | } |
| 580 | |
| 581 | // create and register the report output |
| 582 | for (String reportOutputType : reportOutputs) |
| 583 | { |
| 584 | try |
| 585 | { |
| 586 | Class<OutputType> reportOType = (Class<OutputType>) Class |
| 587 | .forName((reportOutputType != null) ? reportOutputType |
| 588 | : DEFAULT_REPORT_OUTPUT_TYPE); |
| 589 | OutputType rpt = reportOType.newInstance(); |
| 590 | _reportOutput.add(rpt); |
| 591 | if (reportOutputType != null) |
| 592 | rpt.open(_pathName, name); |
| 593 | _messMan.register(rpt, reporter); |
| 594 | register(rpt); |
| 595 | } catch (Exception e) |
| 596 | { |
| 597 | System.err.println(e.toString()); |
| 598 | } |
| 599 | } |
| 600 | |
| 601 | // create and register the error output |
| 602 | for (String errorOutputType : errorOutputs) |
| 603 | { |
| 604 | try |
| 605 | { |
| 606 | Class<OutputType> errorOType = (Class<OutputType>) Class |
| 607 | .forName((errorOutputType != null) ? errorOutputType |
| 608 | : DEFAULT_ERROR_OUTPUT_TYPE); |
| 609 | OutputType err = errorOType.newInstance(); |
| 610 | _errorOutput.add(err); |
| 611 | // err.setTimeFloats(timeFloats); |
| 612 | if (errorOutputType != null) |
| 613 | err.open(_pathName, name); |
| 614 | _messMan.register(err, errormessage); |
| 615 | register(err); |
| 616 | } catch (Exception e) |
| 617 | { |
| 618 | System.err.println(e.toString()); |
| 619 | } |
| 620 | } |
| 621 | // create and register the trace output |
| 622 | for (String traceOutputType : traceOutputs) |
| 623 | { |
| 624 | try |
| 625 | { |
| 626 | |
| 627 | Class<OutputType> traceOType = (Class<OutputType>) Class |
| 628 | .forName((traceOutputType != null) ? traceOutputType |
| 629 | : DEFAULT_TRACE_OUTPUT_TYPE); |
| 630 | OutputType trc = traceOType.newInstance(); |
| 631 | _traceOutput.add(trc); |
| 632 | if (traceOutputType != null) |
| 633 | trc.open(_pathName, name); |
| 634 | _messMan.register(trc, tracenote); |
| 635 | _messMan.switchOff(tracenote); |
| 636 | register(trc); |
| 637 | } catch (Exception e) |
| 638 | { |
| 639 | System.err.println(e.toString()); |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | // create the distributionmanager to register distributions at |
| 644 | _distMan = new DistributionManager(name, 979); |
| 645 | |
| 646 | // now create the simulation runtime accessories |
| 647 | _client = null; // no object connected |
| 648 | |
| 649 | // check for null reference |
| 650 | if (epsilon == null) |
| 651 | { |
| 652 | // set to default unit |
| 653 | epsilon = TimeUnit.MICROSECONDS; |
| 654 | } |
| 655 | if (referenceUnit == null) |
| 656 | { |
| 657 | // set to default unit |
| 658 | referenceUnit = TimeUnit.SECONDS; |
| 659 | } |
| 660 | // interchange epsilon and reference unit if the reference unit has a |
| 661 | // finer granularity than epsilon |
| 662 | if (referenceUnit.compareTo(epsilon) < 0) |
| 663 | { |
| 664 | TimeUnit buffer = referenceUnit; |
| 665 | referenceUnit = epsilon; |
| 666 | epsilon = buffer; |
| 667 | } |
| 668 | // set epsilon and referenceUnit |
| 669 | TimeOperations.setEpsilon(epsilon); |
| 670 | TimeOperations.setReferenceUnit(referenceUnit); |
| 671 | |
| 672 | // check for null reference |
| 673 | if (formatter == null) |
| 674 | { |
| 675 | formatter = new SingleUnitTimeFormatter(referenceUnit, epsilon, 4, |
| 676 | false); |
| 677 | } |
| 678 | TimeOperations.setTimeFormatter(formatter); |
| 679 | |
| 680 | // building the scheduler: prepare event list... |
| 681 | // (for efficiency reasons, we use the TreeList-basd implementation) |
| 682 | EventList eventList = new EventTreeList(); |
| 683 | |
| 684 | // create the scheduler (and clock) |
| 685 | clientScheduler = createScheduler(name, eventList); |
| 686 | |
| 687 | // create a resource database and tell it that it belongs to this |
| 688 | // experiment |
| 689 | _resDB = new ResourceDB(this); |
| 690 | |
| 691 | // set status to first valid value - initialized, but not connected |
| 692 | _status = INITIALIZED; |
| 693 | } |
| 694 | |
| 695 | /** |
| 696 | * Creates a scheduler for this experiment. |
| 697 | * |
| 698 | * @param name |
| 699 | * experiment name |
| 700 | * @return a new scheduler |
| 701 | */ |
| 702 | protected Scheduler createScheduler(String name, EventList evl) { |
| 703 | Scheduler s = new Scheduler(this, name, evl); |
| 704 | return s; |
| 705 | } |
| 706 | |
| 707 | /** |
| 708 | * Adds a messagereceiver for debugnotes to the experiment. Whenever a model |
| 709 | * produces a message of that type, it will also be sent to the given |
| 710 | * messagereceiver for further processing. Note that the given receiver must |
| 711 | * be capable of handling debugnotes. |
| 712 | * |
| 713 | * @param trcRec |
| 714 | * desmoj.report.MessageReceiver : The new messagereceiver for |
| 715 | * the given type of messages |
| 716 | */ |
| 717 | public void addDebugReceiver(MessageReceiver trcRec) { |
| 718 | |
| 719 | if (trcRec == null) { |
| 720 | sendWarning("Can not add receiver to experiment! Command ignored.", |
| 721 | "Experiment '" + getName() |
| 722 | + "', method 'void addDebugReceiver(" |
| 723 | + "MessageReceiver trcRec)'", |
| 724 | "The parameter 'trc' passed was a null reference.", |
| 725 | "Make sure to construct a valid MessageReciever before adding it to " |
| 726 | + "the experiment's messaging system."); |
| 727 | return; // do nothing |
| 728 | } |
| 729 | |
| 730 | _messMan.register(trcRec, debugnote); |
| 731 | |
| 732 | } |
| 733 | |
| 734 | /** |
| 735 | * Adds a messagereceiver for error messages to the experiment. Whenever a |
| 736 | * model produces a message of that type, it will also be sent to the given |
| 737 | * messagereceiver for further processing. Note that the given receiver must |
| 738 | * be capable of handling messagereceiver. |
| 739 | * |
| 740 | * @param trcRec |
| 741 | * desmoj.report.MessageReceiver : The new messagereceiver for |
| 742 | * the given type of messages |
| 743 | */ |
| 744 | public void addErrorReceiver(MessageReceiver trcRec) { |
| 745 | |
| 746 | if (trcRec == null) { |
| 747 | sendWarning("Can not add receiver to experiment! Command ignored.", |
| 748 | "Experiment '" + getName() |
| 749 | + "', method 'void addErrorReceiver(" |
| 750 | + "MessageReceiver trcRec)'", |
| 751 | "The parameter 'trc' passed was a null reference.", |
| 752 | "Make sure to construct a valid MessageReciever before adding it to " |
| 753 | + "the experiment's messaging system."); |
| 754 | return; // do nothing |
| 755 | } |
| 756 | |
| 757 | _messMan.register(trcRec, errormessage); |
| 758 | |
| 759 | } |
| 760 | |
| 761 | /** |
| 762 | * Returns the experiments name catalog for ensuring unique names of |
| 763 | * simulation objects within a single experiment. |
| 764 | */ |
| 765 | NameCatalog getNameCatalog() { |
| 766 | return _nameCatalog; |
| 767 | } |
| 768 | |
| 769 | /** |
| 770 | * Adds a messagereceiver for the given subtype of message to the |
| 771 | * experiment. Whenever a model produces a message of that type, it will |
| 772 | * also be sent to the given messagereceiver for further processing. |
| 773 | * |
| 774 | * @param trcRec |
| 775 | * desmoj.report.MessageReceiver : The new messagereceiver for |
| 776 | * the given type of messages |
| 777 | * @param messageType |
| 778 | * Class : The type of message to be sent to the given |
| 779 | * messagereceiver |
| 780 | */ |
| 781 | public void addReceiver(MessageReceiver trcRec, Class<?> messageType) { |
| 782 | |
| 783 | if (trcRec == null) { |
| 784 | sendWarning("Can not add receiver to experiment! Command ignored.", |
| 785 | "Experiment '" + getName() |
| 786 | + "', method 'void addReceiver(MessageReceiver " |
| 787 | + "trcRec, Class messageType)'", |
| 788 | "The parameter 'trc' passed was a null reference.", |
| 789 | "Make sure to construct a valid MessageReciever before adding it to " |
| 790 | + "the experiment's messaging system."); |
| 791 | return; // do nothing |
| 792 | } |
| 793 | |
| 794 | if (messageType == null) { // again these damned null values |
| 795 | sendWarning("Can not add receiver to experiment! Command ignored.", |
| 796 | "Experiment '" + getName() |
| 797 | + "', method 'void addReceiver(MessageReceiver " |
| 798 | + "trcRec, Class messageType)'", |
| 799 | "The parameter 'messageType' passed was a null reference.", |
| 800 | "Make sure to construct a valid Class object before adding it to " |
| 801 | + "the experiment's messaging system."); |
| 802 | return; // do nothing |
| 803 | } |
| 804 | |
| 805 | _messMan.register(trcRec, messageType); |
| 806 | |
| 807 | } |
| 808 | |
| 809 | /** |
| 810 | * Adds a messagereceiver for tracenotes to the experiment. Whenever a model |
| 811 | * produces a message of that type, it will also be sent to the given |
| 812 | * messagereceiver for further processing. Note that the given Receiver must |
| 813 | * be capable of handling tracenotes. |
| 814 | * |
| 815 | * @param trcRec |
| 816 | * desmoj.report.MessageReceiver : The new messagereceiver for |
| 817 | * the given type of messages |
| 818 | */ |
| 819 | public void addTraceReceiver(MessageReceiver trcRec) { |
| 820 | |
| 821 | if (trcRec == null) { |
| 822 | sendWarning("Can not add receiver to experiment! Command ignored.", |
| 823 | "Experiment '" + getName() |
| 824 | + "', method 'void addTraceReceiver(" |
| 825 | + "MessageReceiver trcRec)'", |
| 826 | "The parameter 'trc' passed was a null reference.", |
| 827 | "Make sure to construct a valid MessageReciever before adding it to " |
| 828 | + "the experiment's messaging system."); |
| 829 | return; // do nothing |
| 830 | } |
| 831 | |
| 832 | _messMan.register(trcRec, tracenote); |
| 833 | |
| 834 | } |
| 835 | |
| 836 | /** |
| 837 | * Returns a boolean indicating whether debug notes are forwarded to the |
| 838 | * debug ouput or not. Debug ouput can be switched on and off using the |
| 839 | * methods <code>debugOn(TimeInstant startTime)</code> or |
| 840 | * <code>debugOff(TimeInstant stopTime)</code> |
| 841 | * |
| 842 | * @return boolean |
| 843 | */ |
| 844 | public boolean debugIsOn() { |
| 845 | |
| 846 | return _messMan.isOn(debugnote); |
| 847 | |
| 848 | } |
| 849 | |
| 850 | /** |
| 851 | * Switches the debug output off at the given point of simulation time. |
| 852 | * |
| 853 | * @param stopTime |
| 854 | * TimeInstant : The point in simulation time to switch off debug |
| 855 | */ |
| 856 | public void debugOff(TimeInstant stopTime) { |
| 857 | |
| 858 | // check initial TimeInstant parameter |
| 859 | if (stopTime == null) { |
| 860 | sendWarning( |
| 861 | "Invalid start time parameter for debug output given! " |
| 862 | + "StopTime is set to current time.", |
| 863 | "Experiment '" + getName() |
| 864 | + "', method 'void debugOn(TimeInstant startTime)'", |
| 865 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 866 | "Make sure to have a valid TimeInstant object, otherwise use method " |
| 867 | + "start() without TimeInstant parameter."); |
| 868 | stopTime = clientScheduler.presentTime(); |
| 869 | } |
| 870 | |
| 871 | // check if parameter is in future |
| 872 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
| 873 | sendWarning("Invalid start time parameter for debug output given! " |
| 874 | + "StopTime is set to current time.", "Experiment '" |
| 875 | + getName() |
| 876 | + "', method 'void debugOn(TimeInstant stopTime)'", |
| 877 | "The stopTime given is in the past.", |
| 878 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 879 | stopTime = clientScheduler.presentTime(); |
| 880 | } |
| 881 | |
| 882 | ExternalEvent debugOff = new ExternalEventDebugOff(_client, true); |
| 883 | |
| 884 | debugOff.schedule(stopTime); |
| 885 | |
| 886 | } |
| 887 | |
| 888 | /** |
| 889 | * @deprecated Use debugOff(TimeInstant startTime). Switches the debug output off at the given point of simulation time. |
| 890 | * |
| 891 | * @param stopTime |
| 892 | * SimTime : The point in simulation time to switch debug off |
| 893 | */ |
| 894 | public void debugOff(SimTime stopTime) { |
| 895 | this.debugOff(SimTime.toTimeInstant(stopTime)); |
| 896 | } |
| 897 | |
| 898 | /** |
| 899 | * Switches the debug output on at the given point of simulation time. |
| 900 | * |
| 901 | * @param startTime |
| 902 | * TimeInstant : The point in simulation time to switch on debug |
| 903 | */ |
| 904 | public void debugOn(TimeInstant startTime) { |
| 905 | |
| 906 | // check initial TimeInstant parameter |
| 907 | if (startTime == null) { |
| 908 | sendWarning( |
| 909 | "Invalid start time parameter for debug output given! " |
| 910 | + "StartTime is set to current time.", |
| 911 | "Experiment '" + getName() |
| 912 | + "', method 'void debugOn(TimeInstant startTime)'", |
| 913 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 914 | "Make sure to have a valid TimeInstant object, otherwise use method " |
| 915 | + "start() without TimeInstant parameter."); |
| 916 | startTime = clientScheduler.presentTime(); |
| 917 | } |
| 918 | |
| 919 | // check if parameter is in future |
| 920 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
| 921 | sendWarning("Invalid start time parameter for debug output given! " |
| 922 | + "StartTime is set to current time.", "Experiment '" |
| 923 | + getName() |
| 924 | + "', method 'void debugOn(TimeInstant startTime)'", |
| 925 | "The startTime given is in the past.", |
| 926 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 927 | startTime = clientScheduler.presentTime(); |
| 928 | } |
| 929 | |
| 930 | // if parameter equals current time, set trace on immediately, e.g. |
| 931 | // to include initial scheduling |
| 932 | if (TimeInstant.isEqual(clientScheduler.presentTime(), startTime)) { |
| 933 | this.getMessageManager().switchOn(Experiment.debugnote); |
| 934 | _client.sendTraceNote("Debug switched on"); |
| 935 | // Otherwise schedule an appropriate event |
| 936 | } else { |
| 937 | ExternalEvent debugOn = new ExternalEventDebugOn(_client, true); |
| 938 | debugOn.schedule(startTime); |
| 939 | } |
| 940 | |
| 941 | } |
| 942 | |
| 943 | /** |
| 944 | * @deprecated Use debugOn(TimeInstant startTime). Switches the debug output on at the given point of simulation time. |
| 945 | * |
| 946 | * @param startTime |
| 947 | * SimTime : The point in simulation time to switch debug on |
| 948 | */ |
| 949 | public void debugOn(SimTime startTime) { |
| 950 | this.debugOn(SimTime.toTimeInstant(startTime)); |
| 951 | } |
| 952 | |
| 953 | /** |
| 954 | * Switches the debug output on for the given period of simulation time. If |
| 955 | * the second parameter (off) is "sooner" then the first parameter (on), |
| 956 | * they will be swapped automatically. Same parameters will result in no |
| 957 | * debug output at all! |
| 958 | * |
| 959 | * @param startTime |
| 960 | * TimeInstant : The point in simulation time to switch debug on |
| 961 | * @param stopTime |
| 962 | * TimeInstant : The point in simulation time to switch debug off |
| 963 | */ |
| 964 | public void debugPeriod(TimeInstant startTime, TimeInstant stopTime) { |
| 965 | // check initial TimeInstant parameter |
| 966 | if (startTime == null) { |
| 967 | sendWarning( |
| 968 | "Invalid start time parameter for debug output given! Command ignored", |
| 969 | "Experiment '" + getName() |
| 970 | + "', Method 'debugPeriod(TimeInstant startTime, " |
| 971 | + "TimeInstant stopTime)'", |
| 972 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 973 | "Make sure to have a valid TimeInstant object."); |
| 974 | return; |
| 975 | } |
| 976 | |
| 977 | // check initial TimeInstant parameter |
| 978 | if (stopTime == null) { |
| 979 | sendWarning( |
| 980 | "Invalid stop time parameter for debug output given! Command ignored.", |
| 981 | "Experiment '" + getName() |
| 982 | + "', Method 'debugPeriod(TimeInstant startTime, " |
| 983 | + "TimeInstant stopTime)'", |
| 984 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 985 | "Make sure to have a valid TimeInstant object."); |
| 986 | return; |
| 987 | } |
| 988 | |
| 989 | // check for correct order in parameters |
| 990 | if (TimeInstant.isAfter(startTime, stopTime)) { |
| 991 | |
| 992 | // swap parameters |
| 993 | TimeInstant buffer = stopTime; |
| 994 | stopTime = startTime; |
| 995 | startTime = buffer; |
| 996 | |
| 997 | } |
| 998 | |
| 999 | // check if stop parameter is in future |
| 1000 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
| 1001 | sendWarning( |
| 1002 | "Invalid stop time parameter for debug output given! Command ignored.", |
| 1003 | "Experiment '" + getName() |
| 1004 | + "', Method 'debugPeriod(TimeInstant startTime, " |
| 1005 | + "TimeInstant stopTime)'", |
| 1006 | "The stopTime given is in the past.", |
| 1007 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 1008 | return; |
| 1009 | } |
| 1010 | |
| 1011 | // check if start parameter is in past |
| 1012 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
| 1013 | sendWarning("Invalid start time parameter for debug output given! " |
| 1014 | + "Debug output has been set to start immediately.", |
| 1015 | "Experiment '" + getName() |
| 1016 | + "', Method 'debugPeriod(TimeInstant startTime, " |
| 1017 | + "TimeInstant stopTime)'", |
| 1018 | "The startTime given is in the past.", |
| 1019 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 1020 | startTime = clientScheduler.presentTime(); |
| 1021 | } |
| 1022 | |
| 1023 | // set debug to switch on |
| 1024 | debugOn(startTime); |
| 1025 | |
| 1026 | // set debug to switch off |
| 1027 | debugOff(stopTime); |
| 1028 | } |
| 1029 | |
| 1030 | /** |
| 1031 | * @deprecated Replaced by debugTime(TimeInstant a, TimeInstant b). Switches |
| 1032 | * the debug output on for the given period of simulation time. |
| 1033 | * If the second parameter (off) is "sooner" then the first |
| 1034 | * parameter (on), they will be swapped automatically. Same |
| 1035 | * parameters will result in no debug output at all! |
| 1036 | * |
| 1037 | * @param startTime |
| 1038 | * SimTime : The point in simulation time to switch debug on |
| 1039 | * @param stopTime |
| 1040 | * SimTime : The point in simulation time to switch debug off |
| 1041 | */ |
| 1042 | @Deprecated |
| 1043 | public void debugPeriod(SimTime startTime, SimTime stopTime) { |
| 1044 | debugPeriod(SimTime.toTimeInstant(startTime), SimTime |
| 1045 | .toTimeInstant(stopTime)); |
| 1046 | } |
| 1047 | |
| 1048 | /** |
| 1049 | * De-registers a file at the experiment. Registered files will be flushed |
| 1050 | * and closed after the experiment has finished. If the file is manually |
| 1051 | * closed by the user and has been registered at the Experiment, deRegister |
| 1052 | * it |
| 1053 | * |
| 1054 | * @param file |
| 1055 | * desmoj.report.FileOutput : The file to be closed with the end |
| 1056 | * of an Experiment |
| 1057 | */ |
| 1058 | public void deRegister(FileOutput file) { |
| 1059 | |
| 1060 | if (file == null) { |
| 1061 | sendWarning("Can not de-register FileOutput! Command ignored.", |
| 1062 | "Experiment '" + getName() |
| 1063 | + "' method 'void deRegister(FileOutput file).'", |
| 1064 | "The parameter given was a null reference.", |
| 1065 | "Make sure to only connect valid FileOutputs at the Experiment."); |
| 1066 | return; |
| 1067 | } |
| 1068 | |
| 1069 | _registryFileOutput.remove(file); |
| 1070 | // remove whether it was inside or not |
| 1071 | |
| 1072 | } |
| 1073 | |
| 1074 | /** |
| 1075 | * Stopps all running simprocesses that might still be scheduled and closes |
| 1076 | * the output files. |
| 1077 | */ |
| 1078 | public void finish() { |
| 1079 | |
| 1080 | // check if experiment has not been aborted before |
| 1081 | if (_status >= ABORTED) { |
| 1082 | return; |
| 1083 | } |
| 1084 | |
| 1085 | if (_traceOutput != null) { |
| 1086 | for (OutputType trc : _traceOutput) |
| 1087 | { |
| 1088 | if (trc instanceof OutputTypeEndToExport) { |
| 1089 | ((OutputTypeEndToExport) trc).export(_pathName, getName()); |
| 1090 | } |
| 1091 | } |
| 1092 | } |
| 1093 | if (_debugOutput != null) { |
| 1094 | for (OutputType dbg : _debugOutput) { |
| 1095 | if (dbg instanceof OutputTypeEndToExport) { |
| 1096 | ((OutputTypeEndToExport) dbg).export(_pathName, getName()); |
| 1097 | } |
| 1098 | } |
| 1099 | } |
| 1100 | if (_errorOutput != null) { |
| 1101 | for (OutputType err : _errorOutput) { |
| 1102 | if (err instanceof OutputTypeEndToExport) { |
| 1103 | ((OutputTypeEndToExport) err).export(_pathName, getName()); |
| 1104 | } |
| 1105 | } |
| 1106 | } |
| 1107 | if (_reportOutput != null){ |
| 1108 | for (OutputType rpt : _reportOutput) { |
| 1109 | if (rpt instanceof OutputTypeEndToExport){ |
| 1110 | ((OutputTypeEndToExport) rpt).export(_pathName, getName()); |
| 1111 | } |
| 1112 | } |
| 1113 | } |
| 1114 | |
| 1115 | // set status to let all simthreads be killed |
| 1116 | _status = ABORTED; |
| 1117 | |
| 1118 | // close all files still open |
| 1119 | for (OutputType o : _registryOutputType) |
| 1120 | o.close(); |
| 1121 | for (FileOutput f : _registryFileOutput) |
| 1122 | f.close(); |
| 1123 | |
| 1124 | // kill all SimThreads still active |
| 1125 | Thread[] survivors = new Thread[_expThreads.activeCount()]; |
| 1126 | _expThreads.enumerate(survivors); |
| 1127 | |
| 1128 | for (int i = 0; i < survivors.length; i++) { |
| 1129 | |
| 1130 | // print existing threads for controlling purposes only |
| 1131 | // System.out.println(survivors[i]); |
| 1132 | |
| 1133 | // if we get the enumeration of survivors, some of them |
| 1134 | // might not have made it until here and die in between |
| 1135 | // so an occasional NullPointerException is perfectly |
| 1136 | // alright and no reason to worry -> we just dump it. |
| 1137 | if (survivors[i] instanceof SimThread) { |
| 1138 | try { |
| 1139 | ((SimThread) survivors[i]).kill(); |
| 1140 | } catch (NullPointerException e) { |
| 1141 | ; // forget it anyway... |
| 1142 | } |
| 1143 | } |
| 1144 | } |
| 1145 | |
| 1146 | } |
| 1147 | |
| 1148 | /** |
| 1149 | * Returns the distributionmanager for this experiment. Distributions need |
| 1150 | * access to the distributionmanager for handling antithetic modes, |
| 1151 | * resetting and their initial seeds. |
| 1152 | * |
| 1153 | * @return desmoj.dist.DistributionManager : The distributionmanager for |
| 1154 | * this experiment |
| 1155 | */ |
| 1156 | public DistributionManager getDistributionManager() { |
| 1157 | |
| 1158 | return _distMan; |
| 1159 | |
| 1160 | } |
| 1161 | |
| 1162 | /** |
| 1163 | * Returns the epsilon value representing the granularity |
| 1164 | * of simulation time for this experiment. So far, Hour, Minute, |
| 1165 | * Second and Millisecond are supported. |
| 1166 | * Default (unless set explicitly) is TimeUnit.MICROSECONDS. |
| 1167 | * |
| 1168 | * @return TimeUnit : The Granularity of the simulation time |
| 1169 | */ |
| 1170 | public TimeUnit getEpsilonUnit() { |
| 1171 | |
| 1172 | return TimeOperations.getEpsilon(); |
| 1173 | } |
| 1174 | |
| 1175 | /** |
| 1176 | * @deprecated Use getEpsilonUnit(). |
| 1177 | * Returns a SimTime representation of the granularity of simulation time |
| 1178 | * for this experiment. So far, Hour, Minute, |
| 1179 | * Second and Millisecond are supported. |
| 1180 | * |
| 1181 | * @return SimTime : The Granularity of the simulation time |
| 1182 | */ |
| 1183 | public SimTime getEpsilon() { |
| 1184 | |
| 1185 | return SimTime.toSimTime(new TimeSpan (1L, TimeOperations.getEpsilon())); |
| 1186 | } |
| 1187 | |
| 1188 | /** |
| 1189 | * Returns the current execution Speed Rate. |
| 1190 | * |
| 1191 | * @return double : The current execution speed rate. |
| 1192 | */ |
| 1193 | public double getExecutionSpeedRate() { |
| 1194 | return this.clientScheduler.getExecutionSpeedRate(); |
| 1195 | } |
| 1196 | |
| 1197 | /** |
| 1198 | * Returns the messagemanager for this experiment. Messages need access to |
| 1199 | * the MessageManager for distributing the messages to one or more specified |
| 1200 | * output streams. |
| 1201 | * |
| 1202 | * @return desmoj.dist.MessageManager : The messagemanager for this |
| 1203 | * experiment |
| 1204 | */ |
| 1205 | public MessageDistributor getMessageManager() { |
| 1206 | |
| 1207 | return _messMan; |
| 1208 | |
| 1209 | } |
| 1210 | |
| 1211 | /** |
| 1212 | * Returns the model that is connected to this experiment or |
| 1213 | * <code>null</code> if no model is connected so far. |
| 1214 | * |
| 1215 | * @return Model : The model that this experiment is connected to or |
| 1216 | * <code>null</code> if no connection is established. |
| 1217 | */ |
| 1218 | public Model getModel() { |
| 1219 | |
| 1220 | return _client; |
| 1221 | |
| 1222 | } |
| 1223 | |
| 1224 | /** |
| 1225 | * Returns the name of the path the experiment's report-, trace-, debug- and |
| 1226 | * error-files are written to. |
| 1227 | * |
| 1228 | * @return String the experiment's output path |
| 1229 | */ |
| 1230 | public String getOutputPath() { |
| 1231 | return new File(_pathName).getAbsolutePath(); |
| 1232 | } |
| 1233 | |
| 1234 | public List<List<String>> getOutputAppendixes() { |
| 1235 | |
| 1236 | List<List<String>> appendixes = new ArrayList<List<String>>(); |
| 1237 | |
| 1238 | ArrayList<String> debugAppendixes = new ArrayList<String>(); |
| 1239 | for (OutputType o : this._debugOutput) { |
| 1240 | debugAppendixes.add(o.getAppendix()); |
| 1241 | } |
| 1242 | appendixes.add(debugAppendixes); |
| 1243 | |
| 1244 | ArrayList<String> traceAppendixes = new ArrayList<String>(); |
| 1245 | for (OutputType o : this._debugOutput) { |
| 1246 | traceAppendixes.add(o.getAppendix()); |
| 1247 | } |
| 1248 | appendixes.add(traceAppendixes); |
| 1249 | |
| 1250 | ArrayList<String> errorAppendixes = new ArrayList<String>(); |
| 1251 | for (OutputType o : this._debugOutput) { |
| 1252 | errorAppendixes.add(o.getAppendix()); |
| 1253 | } |
| 1254 | appendixes.add(errorAppendixes); |
| 1255 | |
| 1256 | ArrayList<String> reportAppendixes = new ArrayList<String>(); |
| 1257 | for (OutputType o : this._debugOutput) { |
| 1258 | reportAppendixes.add(o.getAppendix()); |
| 1259 | } |
| 1260 | appendixes.add(reportAppendixes); |
| 1261 | |
| 1262 | return appendixes; |
| 1263 | } |
| 1264 | |
| 1265 | public long getRealTimeStartTime() { |
| 1266 | return _realTimeStartTime; |
| 1267 | } |
| 1268 | |
| 1269 | /** |
| 1270 | * Returns the reference unit for this experiment. This is the time unit |
| 1271 | * mapped to a time step of 1.0 in simulation time. So far, Hour, Minute, |
| 1272 | * Second and Millisecond are supported. |
| 1273 | * Default (unless set explicitly) is TimeUnit.SECONDS. |
| 1274 | * |
| 1275 | * @return TimeUnit : The reference unit. |
| 1276 | */ |
| 1277 | public TimeUnit getReferenceUnit() { |
| 1278 | return TimeOperations.getReferenceUnit(); |
| 1279 | } |
| 1280 | |
| 1281 | /** |
| 1282 | * Returns the resource database for this experiment. The <code>Res</code> |
| 1283 | * objects need access to the resource database to note their resource |
| 1284 | * allocations and requests and for deadlock detection. |
| 1285 | * |
| 1286 | * @return desmoj.ResourceDB : the resource database storing all resource |
| 1287 | * allocations and requests. |
| 1288 | * @author Soenke Claassen |
| 1289 | */ |
| 1290 | public ResourceDB getResourceDB() { |
| 1291 | |
| 1292 | return _resDB; |
| 1293 | } |
| 1294 | |
| 1295 | /** |
| 1296 | * Returns the scheduler for this experiment. ModelComponents need access to |
| 1297 | * the scheduler for identifying the current active entity or process and to |
| 1298 | * schedule themselves or other schedulables to activate at a given time in |
| 1299 | * the future. |
| 1300 | * |
| 1301 | * @return Scheduler : The scheduler for this experiment |
| 1302 | */ |
| 1303 | public Scheduler getScheduler() { |
| 1304 | |
| 1305 | return clientScheduler; |
| 1306 | |
| 1307 | } |
| 1308 | |
| 1309 | /** |
| 1310 | * Returns the simclock for this experiment. ModelComponents need access to |
| 1311 | * the simclock for retrieveing the current simulation time. |
| 1312 | * |
| 1313 | * @return SimCLock : The simclock for this experiment |
| 1314 | */ |
| 1315 | public SimClock getSimClock() { |
| 1316 | |
| 1317 | return clientScheduler.getSimClock(); |
| 1318 | |
| 1319 | } |
| 1320 | |
| 1321 | /** |
| 1322 | * Returns the TimeInstant when the experiment is expected to stop running. |
| 1323 | * |
| 1324 | * @return desmoj.TimeInstant : The time, the experiment is expected to stop |
| 1325 | * running. |
| 1326 | */ |
| 1327 | public TimeInstant getStopTime() { |
| 1328 | |
| 1329 | return _stopTime; |
| 1330 | } |
| 1331 | |
| 1332 | /** |
| 1333 | * Returns the Conditions which can cause an experiment to stop. |
| 1334 | * May be empty if there are no such Conditions. |
| 1335 | * |
| 1336 | * @return Condition |
| 1337 | * @author Tim Janz |
| 1338 | */ |
| 1339 | public List<ModelCondition> getStopConditions() { |
| 1340 | |
| 1341 | return new java.util.ArrayList<ModelCondition>(this._stopConditions); |
| 1342 | } |
| 1343 | |
| 1344 | /** |
| 1345 | * Removes all conditions set to stop the experiment. |
| 1346 | */ |
| 1347 | public void removeStopConditions() { |
| 1348 | |
| 1349 | this._stopConditions.clear(); |
| 1350 | } |
| 1351 | |
| 1352 | /** |
| 1353 | * Returns the threadgroup associated to this experiment. All Threads are |
| 1354 | * associated to this threadgroup to get control of their number and state |
| 1355 | * and to have a means to differentiate them from possible other |
| 1356 | * experiments' threads. |
| 1357 | * |
| 1358 | * @return java.lang.ThreadGroup |
| 1359 | */ |
| 1360 | ThreadGroup getThreadGroup() { |
| 1361 | |
| 1362 | return _expThreads; |
| 1363 | |
| 1364 | } |
| 1365 | |
| 1366 | /** |
| 1367 | * @deprecated Depends on TimeFormatter in use. Returns the experiment's number |
| 1368 | * of floating point digits of simulation time that are displayed in the various output files, |
| 1369 | * as read from the SingleUnitTimeFormatter, if in use. Otherwise, 0 will be returned. |
| 1370 | * |
| 1371 | * @return int : The number of floating point digits of simulation time to |
| 1372 | * be displayed in output files |
| 1373 | */ |
| 1374 | public int getTimeFloats() { |
| 1375 | |
| 1376 | if (TimeOperations.getTimeFormatter() instanceof SingleUnitTimeFormatter) { |
| 1377 | return (int) ((SingleUnitTimeFormatter)TimeOperations.getTimeFormatter())._floats; |
| 1378 | } else |
| 1379 | return 0; |
| 1380 | } |
| 1381 | |
| 1382 | /** |
| 1383 | * Displays the current state of the simulation run. If an experient is |
| 1384 | * aborted, it can not be proceeded. All SimThreads still active are |
| 1385 | * stopped, the main routine can finish. |
| 1386 | * |
| 1387 | * @return boolean : Is <code>true</code> if the simulation is aborted, |
| 1388 | * <code>false</code> if it has not started yet or is still running |
| 1389 | */ |
| 1390 | public boolean isAborted() { |
| 1391 | |
| 1392 | return (_status >= ABORTED); |
| 1393 | |
| 1394 | } |
| 1395 | |
| 1396 | /** |
| 1397 | * Shows if this experiment has already been connected to a model. |
| 1398 | * |
| 1399 | * @return boolean : Is <code>true</code>, if experiment is connected to a |
| 1400 | * model, <code>false</code> otherwise |
| 1401 | */ |
| 1402 | public boolean isConnected() { |
| 1403 | |
| 1404 | return (_status >= CONNECTED); // model connected |
| 1405 | |
| 1406 | } |
| 1407 | |
| 1408 | /** |
| 1409 | * Returns if the event-list processes concurrent Events in random order or |
| 1410 | * not. Default is not. |
| 1411 | * |
| 1412 | * @return boolean: <code>true</code> if concurrent Events are randomized, |
| 1413 | * <code>false</code> otherwise |
| 1414 | * @author Ruth Meyer |
| 1415 | */ |
| 1416 | public boolean isRandomizingConcurrentEvents() { |
| 1417 | return clientScheduler.isRandomizingConcurrentEvents(); |
| 1418 | } |
| 1419 | |
| 1420 | /** |
| 1421 | * Displays the current state of the simulation run. |
| 1422 | * |
| 1423 | * @return boolean : Is <code>true</code> if the simulation is running, |
| 1424 | * <code>false</code> if it has not started yet or has already |
| 1425 | * finished |
| 1426 | */ |
| 1427 | public boolean isRunning() { |
| 1428 | |
| 1429 | return (_status == RUNNING); |
| 1430 | |
| 1431 | } |
| 1432 | |
| 1433 | /** |
| 1434 | * Returns if a progress bar should be displayed for this experiment or not. |
| 1435 | * |
| 1436 | * @return boolean :<code>true</code> if a progress bar should be displayed |
| 1437 | * for this experiment, <code>false</code> otherwise. |
| 1438 | */ |
| 1439 | public boolean isShowProgressBar() { |
| 1440 | |
| 1441 | return _showProgressBar; |
| 1442 | } |
| 1443 | |
| 1444 | /** |
| 1445 | * Displays the current state of the simulation run. If an experient is |
| 1446 | * stopped, it can be proceeded by calling proceed(). |
| 1447 | * |
| 1448 | * @return boolean : Is <code>true</code>, if experiment is stopped, |
| 1449 | * <code>false</code> otherwise |
| 1450 | */ |
| 1451 | public boolean isStopped() { |
| 1452 | |
| 1453 | return (_status == STOPPED); // model stopped |
| 1454 | |
| 1455 | } |
| 1456 | |
| 1457 | /** |
| 1458 | * Proceeds with a stopped experiment. An experiment can be stopped, if |
| 1459 | * either its status is changed from <code>RUNNING</code> to some other |
| 1460 | * state, the scheduler runs out of scheduled events or if the |
| 1461 | * <code>check()</code> method of the given stop <code>Condition</code> |
| 1462 | * returns <code>true</code> after an event has been processed. |
| 1463 | */ |
| 1464 | public void proceed() { |
| 1465 | |
| 1466 | if (_status < STARTED) { |
| 1467 | sendWarning( |
| 1468 | "Can not proceed with Experiment! Command ignored.", |
| 1469 | "Experiment: " + getName() + " Method: void proceed().", |
| 1470 | "The Experiment has not been started yet.", |
| 1471 | "Only Experiments that have been stopped after method 'start()' has " |
| 1472 | + "been called can use method 'proceed()' to continue."); |
| 1473 | return; |
| 1474 | } |
| 1475 | |
| 1476 | if (_status > STOPPED) { |
| 1477 | sendWarning("Can not proceed with Experiment! Command ignored.", |
| 1478 | "Experiment " + getName() + " Method: void proceed().", |
| 1479 | "The Experiment has already been aborted.", |
| 1480 | "Use method 'proceed()' only on stopped experiments."); |
| 1481 | return; |
| 1482 | } |
| 1483 | if (_status == STARTED) { |
| 1484 | // print status message to calm users waiting long, long, long |
| 1485 | // hours... |
| 1486 | if (!_silent) System.out.println("***** DESMO-J version " + getDesmoJVersion() |
| 1487 | + " ***** \n" + getName() + " starts at simulation time " |
| 1488 | + getScheduler().presentTime() + "\n ...please wait..."); |
| 1489 | } |
| 1490 | else{ |
| 1491 | if (!_silent) System.out.println(getName() + " resumes at simulation time " |
| 1492 | + getScheduler().presentTime() + "\n ...please wait..."); |
| 1493 | } |
| 1494 | // display a progress bar if stop time is known and showProgressBar is |
| 1495 | // true |
| 1496 | if (_stopTime != null && _showProgressBar) { |
| 1497 | JFrame frame = new ExpProgressBar(this); |
| 1498 | |
| 1499 | frame.addWindowListener(new WindowAdapter() { |
| 1500 | public void windowClosing(WindowEvent e) { |
| 1501 | System.exit(0); |
| 1502 | } |
| 1503 | }); |
| 1504 | |
| 1505 | frame.pack(); |
| 1506 | // frame.setSize(380,90); |
| 1507 | frame.setVisible(true); |
| 1508 | } |
| 1509 | |
| 1510 | _status = RUNNING; // now checked to run |
| 1511 | boolean gotEvent = false; // buffer to check if scheduler works |
| 1512 | |
| 1513 | try { |
| 1514 | |
| 1515 | while (_status == RUNNING) { |
| 1516 | // infinite loop until condition/time expired |
| 1517 | gotEvent = clientScheduler.processNextEventNote(); |
| 1518 | if (gotEvent == false) { |
| 1519 | _status = STOPPED; |
| 1520 | } |
| 1521 | |
| 1522 | // check potential stop conditions |
| 1523 | if (!_stopConditions.isEmpty()) { |
| 1524 | for (ModelCondition c : _stopConditions) { |
| 1525 | if (c.check()) { |
| 1526 | _status = STOPPED; |
| 1527 | break; |
| 1528 | } |
| 1529 | } |
| 1530 | } |
| 1531 | |
| 1532 | // Sleep a while (modified by N. Knaak) |
| 1533 | if (_status == RUNNING && _delayInMillis != 0) |
| 1534 | Thread.sleep(_delayInMillis); |
| 1535 | } |
| 1536 | } catch (DESMOJException e) { |
| 1537 | System.err.println("desaster recovery"); |
| 1538 | // this is the desaster recovery routine to stop simulation and save |
| 1539 | // the report to disc before exiting the faulty experiment |
| 1540 | _messMan.receive(e.getErrorMessage()); |
| 1541 | report(); |
| 1542 | finish(); |
| 1543 | _status = ABORTED; |
| 1544 | e.printStackTrace(); |
| 1545 | } catch (java.lang.InterruptedException e) { |
| 1546 | System.err.println("desaster recovery"); |
| 1547 | // this is the disaster recovery routine to stop simulation and save |
| 1548 | // the report to disc before exiting the faulty experiment |
| 1549 | // messMan.receive(e.getMessage()); |
| 1550 | report(); |
| 1551 | finish(); |
| 1552 | _status = ABORTED; |
| 1553 | } |
| 1554 | |
| 1555 | // give warning if reason for stopping was empty EventList |
| 1556 | if (gotEvent == false) { |
| 1557 | sendWarning("No more events scheduled! Experiment is stopped.", |
| 1558 | "Experiment '" + getName() + "' method void proceed().", |
| 1559 | "The scheduler has run out of events to handle.", |
| 1560 | "Make sure to always have events to be scheduled i.e. by letting an " |
| 1561 | + "Entity create and schedule its successor."); |
| 1562 | } |
| 1563 | |
| 1564 | // print status message to user... |
| 1565 | if (!_silent) System.out.println(getName() + " stopped at simulation time " |
| 1566 | + getScheduler().presentTime()); |
| 1567 | |
| 1568 | } |
| 1569 | |
| 1570 | /** |
| 1571 | * Sets the delay between each step of the scheduler. |
| 1572 | * |
| 1573 | * @param delay |
| 1574 | * : Delay time in milliseconds as a long value |
| 1575 | * @author Nicolas Knaak |
| 1576 | */ |
| 1577 | public void setDelayInMillis(long delay) { |
| 1578 | _delayInMillis = delay; |
| 1579 | } |
| 1580 | |
| 1581 | /** |
| 1582 | * Returns the delay between each step of the scheduler |
| 1583 | * |
| 1584 | * @return A long value representing the delay time in milliseconds |
| 1585 | * @author Nicolas Knaak |
| 1586 | * |
| 1587 | */ |
| 1588 | public long getDelayInMillis() { |
| 1589 | return _delayInMillis; |
| 1590 | } |
| 1591 | |
| 1592 | |
| 1593 | /** |
| 1594 | * Registers a file output (Report, Trace, Error, Debug) in specific formats |
| 1595 | * (e.g. HTML, ASCII, XML) at the experiment. Registered files will be |
| 1596 | * flushed and closed after the experiment has finished. This is handy for |
| 1597 | * modellers producing their own output who want their files to be closed at |
| 1598 | * the end of the experiment. |
| 1599 | * |
| 1600 | * @param file |
| 1601 | * desmoj.report.FileOutput : The file to be closed with the end |
| 1602 | * of an experiment |
| 1603 | */ |
| 1604 | public void register(OutputType file) { |
| 1605 | |
| 1606 | if (file == null) { |
| 1607 | sendWarning("Can not register OutputType! Command ignored.", |
| 1608 | "Experiment '" + getName() |
| 1609 | + "' method void register(OutputType file).", |
| 1610 | "The parameter given was a null reference.", |
| 1611 | "Make sure to only connect valid OutputType at the Experiment."); |
| 1612 | return; |
| 1613 | } |
| 1614 | |
| 1615 | if (_registryOutputType.contains(file)) |
| 1616 | return; // file already registered |
| 1617 | |
| 1618 | _registryOutputType.add(file); |
| 1619 | |
| 1620 | } |
| 1621 | |
| 1622 | /** |
| 1623 | * Registers a custom file output at the experiment, e.g. TimeSeries |
| 1624 | * plotting data to a file. Registered files will be flushed and closed |
| 1625 | * after the experiment has finished. This is handy for modellers producing |
| 1626 | * their own output who want their files to be closed at the end of the |
| 1627 | * experiment. |
| 1628 | * |
| 1629 | * @param file |
| 1630 | * desmoj.report.FileOutput : The file to be closed with the end |
| 1631 | * of an experiment |
| 1632 | */ |
| 1633 | public void registerFileOutput(FileOutput file) { |
| 1634 | |
| 1635 | if (file == null) { |
| 1636 | sendWarning("Can not register FileOutput! Command ignored.", |
| 1637 | "Experiment '" + getName() |
| 1638 | + "' method void register(OutputType file).", |
| 1639 | "The parameter given was a null reference.", |
| 1640 | "Make sure to only connect valid FileOutput at the Experiment."); |
| 1641 | return; |
| 1642 | } |
| 1643 | |
| 1644 | if (_registryFileOutput.contains(file)) |
| 1645 | return; // file already registered |
| 1646 | |
| 1647 | _registryFileOutput.add(file); |
| 1648 | |
| 1649 | } |
| 1650 | |
| 1651 | /** |
| 1652 | * Connects a model to this experiment. The given model must not be submodel |
| 1653 | * of other models and not already be connected to some other experiment. |
| 1654 | * Otherwise an errormessage will be given and the experiment will be |
| 1655 | * stopped. |
| 1656 | */ |
| 1657 | void registerModel(Model mainModel) { |
| 1658 | |
| 1659 | if (mainModel == null) { |
| 1660 | sendWarning( |
| 1661 | "Can not register model at experiment! Command ignored.", |
| 1662 | "Experiment '" + getName() |
| 1663 | + "', Method 'void registerModel(Model mainModel)'", |
| 1664 | "The parameter passed was a null reference.", |
| 1665 | "Make sure to connect a valid main model to this experiment."); |
| 1666 | return; // no connection possible. |
| 1667 | } |
| 1668 | |
| 1669 | if (mainModel.getModel() != null) { |
| 1670 | sendWarning( |
| 1671 | "Can not register model at experiment! Command ignored.", |
| 1672 | "Experiment '" + getName() |
| 1673 | + "', Method 'void registerModel(Model mainModel)'", |
| 1674 | "The model references another model as its owner, thus can not be the " |
| 1675 | + "main model.", |
| 1676 | "Make sure to connect a valid main model to this experiment."); |
| 1677 | return; // no connection possible. |
| 1678 | } |
| 1679 | |
| 1680 | if (isConnected()) { |
| 1681 | sendWarning( |
| 1682 | "Can not register model at experiment! Command ignored.", |
| 1683 | "Experiment '" + getName() |
| 1684 | + "', Method 'void registerModel(Model mainModel)'", |
| 1685 | "This experiment is already connected to model : " |
| 1686 | + _client.getName(), |
| 1687 | "An experiment may only be connected to one main model at a time."); |
| 1688 | return; // no connection possible. |
| 1689 | } |
| 1690 | |
| 1691 | _status = CONNECTED; |
| 1692 | _client = mainModel; |
| 1693 | _client.setMain(); |
| 1694 | |
| 1695 | } |
| 1696 | |
| 1697 | /** |
| 1698 | * Removes a messagereceiver for debugnotes from the experiment's |
| 1699 | * messagedistributor. Whenever a model produces a message of that type, it |
| 1700 | * will not be sent to the given messagereceiver anymore. Note that if the |
| 1701 | * messagereceiver is also registered for other types of messages, these |
| 1702 | * will not be affected. Use method |
| 1703 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
| 1704 | * messagereceiver from all types of messages. |
| 1705 | * |
| 1706 | * @param msgRec |
| 1707 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
| 1708 | * removed from the messagedistributor's list for the given |
| 1709 | * messagetype |
| 1710 | */ |
| 1711 | public void removeDebugReceiver(MessageReceiver msgRec) { |
| 1712 | |
| 1713 | if (msgRec == null) { |
| 1714 | sendWarning( |
| 1715 | "Can not remove receiver to experiment! Command ignored.", |
| 1716 | "Experiment '" + getName() |
| 1717 | + "', Method 'void removeDebugReceiver" |
| 1718 | + "(MessageReceiver msgRec)'", |
| 1719 | "The parameter 'msgRec' passed was a null reference.", |
| 1720 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1721 | + "from the experiment's messaging system."); |
| 1722 | return; // do nothing |
| 1723 | } |
| 1724 | |
| 1725 | _messMan.deRegister(msgRec, debugnote); |
| 1726 | |
| 1727 | } |
| 1728 | |
| 1729 | /** |
| 1730 | * Removes a messagereceiver for errormessages from the experiment's |
| 1731 | * messagedistributor. Whenever a model produces a message of that type, it |
| 1732 | * will not be sent to the given messagereceiver anymore. Note that if the |
| 1733 | * messagereceiver is also registered for other types of messages, these |
| 1734 | * will not be affected. Use method |
| 1735 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
| 1736 | * messagereceiver from all types of messages. |
| 1737 | * |
| 1738 | * @param msgRec |
| 1739 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
| 1740 | * removed from the vessagedistributor's list for the given |
| 1741 | * messagetype |
| 1742 | */ |
| 1743 | public void removeErrorReceiver(MessageReceiver msgRec) { |
| 1744 | |
| 1745 | if (msgRec == null) { |
| 1746 | sendWarning( |
| 1747 | "Can not remove receiver to experiment! Command ignored.", |
| 1748 | "Experiment '" + getName() |
| 1749 | + "', Method 'void removeErrorReceiver" |
| 1750 | + "(MessageReceiver msgRec)'", |
| 1751 | "The parameter 'msgRec' passed was a null reference.", |
| 1752 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1753 | + "from the experiment's messaging system."); |
| 1754 | return; // do nothing |
| 1755 | } |
| 1756 | |
| 1757 | _messMan.deRegister(msgRec, errormessage); |
| 1758 | |
| 1759 | } |
| 1760 | |
| 1761 | /** |
| 1762 | * Removes a messagereceiver from the experiment's messagedistributor. The |
| 1763 | * given messagereceiver will not receive messages of any type any more Use |
| 1764 | * method <code>removeReceiver(MessageReceiver msgRec, Class |
| 1765 | * messageType)</code> to remove the messagereceiver from one type of |
| 1766 | * messages only. |
| 1767 | * |
| 1768 | * @param msgRec |
| 1769 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
| 1770 | * removed from the messagedistributor's list for the given |
| 1771 | * messagetype |
| 1772 | */ |
| 1773 | public void removeReceiver(MessageReceiver msgRec) { |
| 1774 | |
| 1775 | if (msgRec == null) { |
| 1776 | sendWarning( |
| 1777 | "Can not remove receiver to experiment! Command ignored.", |
| 1778 | "Experiment '" + getName() |
| 1779 | + "', Method 'void removeReceiver(MessageReceiver " |
| 1780 | + "msgRec)'", |
| 1781 | "The parameter 'msgRec' passed was a null reference.", |
| 1782 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1783 | + "from the experiment's messaging system."); |
| 1784 | return; // do nothing |
| 1785 | } |
| 1786 | |
| 1787 | _messMan.deRegister(msgRec); |
| 1788 | |
| 1789 | } |
| 1790 | |
| 1791 | /** |
| 1792 | * Removes a messagereceiver for the given subtype of message from the |
| 1793 | * Experiment's messagedistributor. Whenever a model produces a message of |
| 1794 | * that type, it will not be sent to the given messagereceiver anymore. Note |
| 1795 | * that if the messagereceiver is also registered for other types of |
| 1796 | * messages, these will not be affected. Use method |
| 1797 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
| 1798 | * messagereceiver from all types of messages. |
| 1799 | * |
| 1800 | * @param msgRec |
| 1801 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
| 1802 | * removed from the messagedistributor's list for the given |
| 1803 | * messagetype |
| 1804 | * @param messageType |
| 1805 | * Class : The type of message not to be sent to the given |
| 1806 | * messagereceiver |
| 1807 | */ |
| 1808 | public void removeReceiver(MessageReceiver msgRec, Class<?> messageType) { |
| 1809 | |
| 1810 | if (msgRec == null) { |
| 1811 | sendWarning( |
| 1812 | "Can not remove receiver to experiment! Command ignored.", |
| 1813 | "Experiment '" + getName() |
| 1814 | + "', Method 'void removeReceiver(MessageReceiver " |
| 1815 | + "msgRec, Class messageType)'", |
| 1816 | "The parameter 'msgRec' passed was a null reference.", |
| 1817 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1818 | + "from the experiment's messaging system."); |
| 1819 | return; // do nothing |
| 1820 | } |
| 1821 | |
| 1822 | if (messageType == null) { |
| 1823 | sendWarning( |
| 1824 | "Can not remove receiver to experiment! Command ignored.", |
| 1825 | "Experiment '" + getName() |
| 1826 | + "', Method 'void removeReceiver(MessageReceiver " |
| 1827 | + "msgRec, Class messageType)'", |
| 1828 | "The parameter 'msgRec' passed was a null reference.", |
| 1829 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1830 | + "from the experiment's messaging system."); |
| 1831 | return; // do nothing |
| 1832 | } |
| 1833 | |
| 1834 | _messMan.deRegister(msgRec, messageType); |
| 1835 | |
| 1836 | } |
| 1837 | |
| 1838 | /** |
| 1839 | * Removes a messagereceiver for tracenotes from the experiment's |
| 1840 | * messagedistributor. Whenever a model produces a message of that type, it |
| 1841 | * will not be sent to the given messagereceiver anymore. Note that if the |
| 1842 | * messagereceiver is also registered for other types of messages, these |
| 1843 | * will not be affected. Use method |
| 1844 | * <code>removeReceiverAll(MessageReceiver msgRec)</code> to remove a |
| 1845 | * messagereceiver from all types of messages. |
| 1846 | * |
| 1847 | * @param msgRec |
| 1848 | * desmoj.report.MessageReceiver : The new messagereceiver to be |
| 1849 | * removed from the messagedistributor's list for the given |
| 1850 | * messagetype |
| 1851 | */ |
| 1852 | public void removeTraceReceiver(MessageReceiver msgRec) { |
| 1853 | |
| 1854 | if (msgRec == null) { |
| 1855 | sendWarning( |
| 1856 | "Can not remove receiver to experiment! Command ignored.", |
| 1857 | "Experiment '" + getName() |
| 1858 | + "', Method 'void removeTraceReceiver" |
| 1859 | + "(MessageReceiver msgRec)'", |
| 1860 | "The parameter 'msgRec' passed was a null reference.", |
| 1861 | "Make sure to give a valid MessageReciever reference before removing it " |
| 1862 | + "from the experiment's messaging system."); |
| 1863 | return; // do nothing |
| 1864 | } |
| 1865 | |
| 1866 | _messMan.deRegister(msgRec, tracenote); |
| 1867 | |
| 1868 | } |
| 1869 | |
| 1870 | /** |
| 1871 | * Overrides inherited <code>NamedObjectImp.rename(String newName)</code> |
| 1872 | * method to prevent the user from changing the experiment's name during an |
| 1873 | * experiment. Renaming is not allowed with experiments, since it would not |
| 1874 | * allow the user to identify the reports produced by an experiment. The |
| 1875 | * method simply returns without changing the experiment's name, ignoring |
| 1876 | * the given parameter. |
| 1877 | * |
| 1878 | * @param newName |
| 1879 | * java.lang.String : The parameter given is not taken as the new |
| 1880 | * name, method simply returns |
| 1881 | */ |
| 1882 | public void rename(String newName) { |
| 1883 | |
| 1884 | // do nothing since renaming experiments is not allowed |
| 1885 | // would do too much confusion |
| 1886 | |
| 1887 | } |
| 1888 | |
| 1889 | /** |
| 1890 | * Writes a report about the model connected top this experiment, its |
| 1891 | * reportable components and all related submodels into the report output. |
| 1892 | * Note that a report can only be produced, if a valid main model is already |
| 1893 | * connected to the experiment. |
| 1894 | */ |
| 1895 | public void report() { |
| 1896 | |
| 1897 | // just pass on the call with main model as parameter |
| 1898 | report(_client); |
| 1899 | |
| 1900 | } |
| 1901 | |
| 1902 | /** |
| 1903 | * Writes a report about the given model which has to be connected to this |
| 1904 | * experiment as main model or as a submodel. Note that this will report |
| 1905 | * about a branch of the tree of submodels constructed. A report will only |
| 1906 | * be produced, if the model given is connected to this experiment. All |
| 1907 | * reportable components of this model and all related submodels will be |
| 1908 | * sent to the report output configured at the experiment's |
| 1909 | * messagedistributor. Note that a report can only be produced, if a valid |
| 1910 | * main model is already connected to the experiment. |
| 1911 | */ |
| 1912 | public void report(Model m) { |
| 1913 | |
| 1914 | List<Reporter> reporters; |
| 1915 | // buffer for the reportmanager returned by client |
| 1916 | |
| 1917 | if (_status < CONNECTED) { |
| 1918 | sendWarning( |
| 1919 | "Can not produce report! Command ignored.", |
| 1920 | "Experiment: " + getName() |
| 1921 | + " Method: void report(Model m).", |
| 1922 | "The Experiment has not been connected to a model to report about yet.", |
| 1923 | "Connect a model to the experiment first using the model's method " |
| 1924 | + "connectToExperiment(Experiment exp)."); |
| 1925 | return; // no client there to be reported |
| 1926 | } |
| 1927 | |
| 1928 | if (_status >= ABORTED) { |
| 1929 | // do nothing since experiment has already been aborted and all |
| 1930 | // output channels are already shut down |
| 1931 | return; // Experiment aborted |
| 1932 | } |
| 1933 | |
| 1934 | if (m == null) { |
| 1935 | sendWarning("Can not produce report! Command ignored.", |
| 1936 | "Experiment: " + getName() |
| 1937 | + " Method: void report(Model m).", |
| 1938 | "The model parameter given is a null reference.", |
| 1939 | "Always make sure to use valid references."); |
| 1940 | return; // no model there to be reported |
| 1941 | } |
| 1942 | |
| 1943 | if (m.getExperiment() != this) { |
| 1944 | sendWarning( |
| 1945 | "Can not produce report! Command ignored.", |
| 1946 | "Experiment: " + getName() |
| 1947 | + " Method: void report(Model m).", |
| 1948 | "The model parameter given is connected to a different experiment.", |
| 1949 | "Only experiments connected to theat model can produce reports " |
| 1950 | + "about that model."); |
| 1951 | return; // model connected to other experiment |
| 1952 | } |
| 1953 | |
| 1954 | // get the client's reportmanager containing all reporters in sorted |
| 1955 | // order |
| 1956 | reporters = m.report(); |
| 1957 | |
| 1958 | // get all out according to sorted order and send them to the report |
| 1959 | // output |
| 1960 | // registered at the experiment's messagemanager |
| 1961 | for (Reporter r : reporters) { |
| 1962 | |
| 1963 | _messMan.receive(r); |
| 1964 | |
| 1965 | } |
| 1966 | } |
| 1967 | |
| 1968 | /** |
| 1969 | * Creates and sends a debugnote to the messagedistributor. Be sure to have |
| 1970 | * a correct location, since the object and method that the error becomes |
| 1971 | * apparent is not necessary the location it was produced in. The |
| 1972 | * information about the simulation time is extracted from the Experiment |
| 1973 | * and must not be given as a parameter. |
| 1974 | * |
| 1975 | * @param description |
| 1976 | * java.lang.String : The description of the error that occured |
| 1977 | */ |
| 1978 | void sendDebugNote(String component, String description) { |
| 1979 | |
| 1980 | // comnpose the DebugNote and send it in one command |
| 1981 | sendMessage(new DebugNote(clientScheduler.getCurrentModel(), |
| 1982 | clientScheduler.getSimClock().getTime(), component, description)); |
| 1983 | |
| 1984 | } |
| 1985 | |
| 1986 | /** |
| 1987 | * Sends a message to the messagedistributor. Note that there are other |
| 1988 | * shorthands for sending the standard DESMO-J messages. |
| 1989 | * |
| 1990 | * @param m |
| 1991 | * Message : The Message to be transmitted |
| 1992 | * @see ModelComponent#sendTraceNote |
| 1993 | * @see ModelComponent#sendDebugNote |
| 1994 | * @see ModelComponent#sendWarning |
| 1995 | */ |
| 1996 | void sendMessage(Message m) { |
| 1997 | |
| 1998 | if (m == null) { |
| 1999 | sendWarning("Can't send Message!", "Experiment :" + getName() |
| 2000 | + " Method: SendMessage(Message m)", |
| 2001 | "The Message given as parameter is a null reference.", |
| 2002 | "Be sure to have a valid Message reference."); |
| 2003 | return; // no proper parameter |
| 2004 | } |
| 2005 | |
| 2006 | _messMan.receive(m); |
| 2007 | |
| 2008 | } |
| 2009 | |
| 2010 | /** |
| 2011 | * Creates and sends an error message to the messagedistributor to warn the |
| 2012 | * modeller that some conditions required by the framework are not met. Be |
| 2013 | * sure to have a correct location, since the object and method that the |
| 2014 | * error becomes apparent is not necessary the location it was produced in. |
| 2015 | * The information about the simulation time is extracted from the |
| 2016 | * experiment and must not be given as a parameter. |
| 2017 | * |
| 2018 | * @param description |
| 2019 | * java.lang.String : The description of the error that occured |
| 2020 | * @param location |
| 2021 | * java.lang.String : The class and method the error occured in |
| 2022 | * @param reason |
| 2023 | * java.lang.String : The reason most probably responsible for |
| 2024 | * the error to occur |
| 2025 | * @param prevention |
| 2026 | * java.lang.String : The measures a user should take to prevent |
| 2027 | * this warning to be issued again |
| 2028 | */ |
| 2029 | void sendWarning(String description, String location, String reason, |
| 2030 | String prevention) { |
| 2031 | |
| 2032 | // comnpose the WarningMessage and send it in one command |
| 2033 | sendMessage(new ErrorMessage(clientScheduler.getCurrentModel(), |
| 2034 | description, location, reason, prevention, clientScheduler |
| 2035 | .getSimClock().getTime())); |
| 2036 | |
| 2037 | } |
| 2038 | |
| 2039 | /** |
| 2040 | * Sets the TimeFormatter to be used for output of time Strings. |
| 2041 | * |
| 2042 | * @param format |
| 2043 | * TimeFormatter : the formatter to be used for formatting time |
| 2044 | * Strings. |
| 2045 | * |
| 2046 | */ |
| 2047 | public void setTimeFormatter(TimeFormatter format) { |
| 2048 | TimeOperations.setTimeFormatter(format); |
| 2049 | } |
| 2050 | |
| 2051 | /** |
| 2052 | * Determines if the event-list processes concurrent Events in random order |
| 2053 | * or not. Default is not, i.e. when a new experiment is constructed, the |
| 2054 | * event-list is set to "linear" order. Note: If you want the event-list to |
| 2055 | * randomize concurrent Events you should call this method BEFORE scheduling |
| 2056 | * any events. Otherwise any connections between events established via |
| 2057 | * scheduleBefore() or scheduleAfter() are lost. So it's a good idea to call |
| 2058 | * this method only once and right after constructing the experiment. |
| 2059 | * |
| 2060 | * @param randomizing |
| 2061 | * boolean :<code>true</code> forces random order, |
| 2062 | * <code>false</code> forces "linear" order |
| 2063 | * @author Ruth Meyer |
| 2064 | */ |
| 2065 | public void randomizeConcurrentEvents(boolean randomizing) { |
| 2066 | clientScheduler.setRandomizingConcurrentEvents(randomizing); |
| 2067 | } |
| 2068 | |
| 2069 | /** |
| 2070 | * Sets the speed rate for an execution that is proportional to wall-clock |
| 2071 | * time (real time). Set the speed rate to a value bigger than zero for a |
| 2072 | * simulation that will progress proportional to wall-clock time. The |
| 2073 | * following equation applies for speed rates >0 : rate*simulation time = |
| 2074 | * wallclock-time. If the speed rate is 0 or less the simulation will be |
| 2075 | * executed as fast as possible. Default is 0 (as-fast-as-possible). |
| 2076 | * |
| 2077 | * @param rate |
| 2078 | * double : The execution speed rate |
| 2079 | */ |
| 2080 | public void setExecutionSpeedRate(double rate) { |
| 2081 | clientScheduler.setExecutionSpeedRate(rate); |
| 2082 | } |
| 2083 | |
| 2084 | /** |
| 2085 | * Sets the seed of the SeedGenerator to the given value. If the seed is not |
| 2086 | * set here, its default is 979, unless specified different in the |
| 2087 | * ExperimentOptions. |
| 2088 | * |
| 2089 | * @param seed |
| 2090 | * long : The seed for the SeedGenerator |
| 2091 | */ |
| 2092 | public void setSeedGenerator(long seed) { |
| 2093 | |
| 2094 | _distMan.setSeed(seed); |
| 2095 | |
| 2096 | } |
| 2097 | |
| 2098 | /** |
| 2099 | * Sets the underlying pseudo random number generator to be used by all |
| 2100 | * distributions created from now on. The default generator is |
| 2101 | * LinearCongruentialRandomGenerator; any other generator to be used must |
| 2102 | * implement the interface UniformRandomGenerator. |
| 2103 | * |
| 2104 | * @see desmoj.core.dist.LinearCongruentialRandomGenerator |
| 2105 | * @see desmoj.core.dist.UniformRandomGenerator |
| 2106 | * |
| 2107 | * @param randomNumberGenerator |
| 2108 | * Class : The random number generator class to be used |
| 2109 | */ |
| 2110 | public void setRandomNumberGenerator( |
| 2111 | Class<? extends desmoj.core.dist.UniformRandomGenerator> randomNumberGenerator) { |
| 2112 | |
| 2113 | boolean classValid = false; |
| 2114 | // // Verify that a class implementing interface |
| 2115 | // desmoj.desmoj.core.dist.UniformRandomGenerator was passed |
| 2116 | // for (int i = 0; i < randomNumberGenerator.getInterfaces().length; |
| 2117 | // i++) { |
| 2118 | // if |
| 2119 | // (randomNumberGenerator.getInterfaces()[i].equals(desmoj.core.dist.UniformRandomGenerator.class)) |
| 2120 | // { |
| 2121 | // classValid = true; |
| 2122 | // break; |
| 2123 | // } |
| 2124 | // } |
| 2125 | |
| 2126 | // Verify the class provided is not abstract |
| 2127 | if ((randomNumberGenerator.getModifiers() & java.lang.reflect.Modifier.ABSTRACT) > 0 |
| 2128 | || (randomNumberGenerator.getModifiers() & java.lang.reflect.Modifier.INTERFACE) > 0) |
| 2129 | classValid = false; |
| 2130 | |
| 2131 | // Update the random number generator... |
| 2132 | if (classValid) { |
| 2133 | |
| 2134 | this._distMan.setRandomNumberGenerator(randomNumberGenerator); |
| 2135 | |
| 2136 | // ...or otherwise return an error |
| 2137 | } else { |
| 2138 | |
| 2139 | this |
| 2140 | .sendWarning( |
| 2141 | "Invalid random number generator given! Method call ignored!", |
| 2142 | "Experiment '" |
| 2143 | + getName() |
| 2144 | + "', Method 'setRandomNumberGenerator(Class randomNumberGenerator)'", |
| 2145 | "The class provided '" |
| 2146 | + randomNumberGenerator.getSimpleName() |
| 2147 | + "' is abstract or does not implement the interface" |
| 2148 | + " desmoj.desmoj.core.dist.UniformRandomGenerator.", |
| 2149 | "Make sure to use a non-abstract class that implements the interface" |
| 2150 | + " desmoj.desmoj.core.dist.UniformRandomGenerator."); |
| 2151 | } |
| 2152 | } |
| 2153 | |
| 2154 | /** |
| 2155 | * Sets the new value for showing the progress bar for this experiment or |
| 2156 | * not. |
| 2157 | * |
| 2158 | * @param newShowProgressBar |
| 2159 | * boolean : set it to <code>true</code> if a progress bar should |
| 2160 | * be displayed; for not showing the progress bar of this |
| 2161 | * experiment set it to <code>false</code>. |
| 2162 | */ |
| 2163 | public void setShowProgressBar(boolean newShowProgressBar) { |
| 2164 | |
| 2165 | this._showProgressBar = newShowProgressBar; |
| 2166 | } |
| 2167 | |
| 2168 | /** |
| 2169 | * Sets the new value for displaying basic experiment notifications like |
| 2170 | * 'experiment started', 'experiment stopped' oder 'experiment resumed' |
| 2171 | * at the system output. |
| 2172 | * |
| 2173 | * @param silent |
| 2174 | * boolean : set it to <code>true</code> to suppress notifications |
| 2175 | * or <code>false</code> to print them. |
| 2176 | */ |
| 2177 | public void setSilent(boolean silent) { |
| 2178 | |
| 2179 | this._silent = silent; |
| 2180 | } |
| 2181 | |
| 2182 | /** |
| 2183 | * Sets the experiment's status to the given integer value. The value must |
| 2184 | * be in the legal range of [-1,5], otherwise a warning is issued. |
| 2185 | * |
| 2186 | * @param newStatus |
| 2187 | * int : The integer value of the experiments' new status |
| 2188 | */ |
| 2189 | void setStatus(int newStatus) { |
| 2190 | |
| 2191 | if ((newStatus < -1) || (newStatus > 5)) { |
| 2192 | sendWarning( |
| 2193 | "Can not start experiment! Command ignored.", |
| 2194 | "Experiment '" + getName() + "', Method 'start'", |
| 2195 | "No main model's connectToExperiment(Experiment e) method was called.", |
| 2196 | "Make sure to connect a valid main model first before starting " |
| 2197 | + "this experiment."); |
| 2198 | return; |
| 2199 | } else |
| 2200 | _status = newStatus; |
| 2201 | |
| 2202 | } |
| 2203 | |
| 2204 | /** |
| 2205 | * Starts the simulation with default start time 0. This method can only be |
| 2206 | * used once on an experiment. it initializes the connected model and starts |
| 2207 | * the simulation. Note that in order to stop the simulation, the |
| 2208 | * <code>stop(TimeInstant stopTime)</code> method has to be called first! |
| 2209 | */ |
| 2210 | public void start() { |
| 2211 | |
| 2212 | // this allows us to use start() in loops for multiple experiment runs |
| 2213 | // in other words, this is a shortcut for the lazy programmer |
| 2214 | if (_status == STOPPED) |
| 2215 | proceed(); |
| 2216 | |
| 2217 | // here's what start was supposed to be at first |
| 2218 | // a shortcut for startig an Experiment at TimeInstant(0) |
| 2219 | else { |
| 2220 | // now prepare connected model to start simulation |
| 2221 | start(new TimeInstant(0)); |
| 2222 | } |
| 2223 | |
| 2224 | } |
| 2225 | |
| 2226 | /** |
| 2227 | * Starts the experiment with the given simulation time as starting time. |
| 2228 | * The experiment will not start unless a valid model has been connected to |
| 2229 | * it before. Note that in order to stop the simulation at some point of |
| 2230 | * time, the <code>stop</code> method has to be called first. |
| 2231 | * <code>StopCondition</code> s can be given alternatively. |
| 2232 | * |
| 2233 | * @param initTime |
| 2234 | * TimeInstant : The starting time instant |
| 2235 | */ |
| 2236 | public void start(TimeInstant initTime) { |
| 2237 | |
| 2238 | if (_status < CONNECTED) { |
| 2239 | sendWarning( |
| 2240 | "Can not start experiment! Command ignored.", |
| 2241 | "Experiment: " + getName() |
| 2242 | + " Method: void start(SimTime initTime)", |
| 2243 | "The Experiment has not been connected to a model to report about yet.", |
| 2244 | "Connect a model to the experiment first using the model's method " |
| 2245 | + "connectToExperiment(Experiment exp)."); |
| 2246 | return; |
| 2247 | } |
| 2248 | if (_status > CONNECTED) { |
| 2249 | sendWarning( |
| 2250 | "Can not start experiment! Command ignored.", |
| 2251 | "Experiment: " + getName() |
| 2252 | + " Method: void start(SimTime initTime)", |
| 2253 | "The Experiment has already been started before.", |
| 2254 | "An experiment can only be started once. If it has been stopped, " |
| 2255 | + "it can be issued to continue using method proceed()"); |
| 2256 | return; |
| 2257 | } |
| 2258 | |
| 2259 | // check initial TimeInstant parameter |
| 2260 | if (initTime != null) { |
| 2261 | clientScheduler.getSimClock().setInitTime(initTime); |
| 2262 | if(!TimeInstant.isEqual(initTime,new TimeInstant(0))){ |
| 2263 | _client.reset(); |
| 2264 | } |
| 2265 | } else { |
| 2266 | clientScheduler.getSimClock().setTime(new TimeInstant(0)); |
| 2267 | sendWarning( |
| 2268 | "Invalid start time parameter given! Start time set to " |
| 2269 | + clientScheduler.presentTime() + ".", |
| 2270 | "Experiment: '" + getName() |
| 2271 | + "', Method: void start(SimTime initTime)", |
| 2272 | "A null calue or a not initialized TimeInstant reference has been passed.", |
| 2273 | "Make sure to have a valid TimeInstnat object, otherwise use method " |
| 2274 | + "start() without TimeInstant parameter."); |
| 2275 | } |
| 2276 | |
| 2277 | // client.init(); already done in connectToExperiment |
| 2278 | _client.doInitialSchedules(); |
| 2279 | _client.doSubmodelSchedules(); |
| 2280 | TimeOperations.setStartTime(initTime); |
| 2281 | // now everything is set up, go on and process events |
| 2282 | _status = STARTED; |
| 2283 | this._realTimeStartTime = System.nanoTime(); |
| 2284 | |
| 2285 | proceed(); |
| 2286 | |
| 2287 | } |
| 2288 | |
| 2289 | /** |
| 2290 | * @deprecated Use start(TimeInstant initTime). |
| 2291 | * Starts the experiment with the given simulation time as starting time. |
| 2292 | * The experiment will not start unless a valid model has been connected to |
| 2293 | * it before. Note that in order to stop the simulation at some point of |
| 2294 | * time, the <code>stop</code> method has to be called first. |
| 2295 | * <code>StopCondition</code> s can be given alternatively. |
| 2296 | * |
| 2297 | * @param initTime |
| 2298 | * TimeInstant : The starting time instant |
| 2299 | */ |
| 2300 | public void start(SimTime initTime) { |
| 2301 | start(SimTime.toTimeInstant(initTime)); |
| 2302 | } |
| 2303 | |
| 2304 | /** |
| 2305 | * Specifies a ModelCondition to stop the simulation. Note that this methode can |
| 2306 | * be called muliple times, defining alternative conditions to terminate the |
| 2307 | * simulation. Once at least one of the conditions passed using this method |
| 2308 | * returns true, the experiment will stop. |
| 2309 | * Beware that the simulation will run endlessly if none of the conditions |
| 2310 | * are met; thus it is recommended to additionally always use a time limit |
| 2311 | * if none of the conditions in question can be proven to be met during the |
| 2312 | * run of the simulation! |
| 2313 | * |
| 2314 | * @param stopCond |
| 2315 | * ModelCondition : A condition to stop the simulation once |
| 2316 | * it's check() methode returns true. |
| 2317 | */ |
| 2318 | public void stop(ModelCondition stopCond) { |
| 2319 | |
| 2320 | if (stopCond == null) { |
| 2321 | sendWarning("Can not set stop-condition! Command ignored.", |
| 2322 | "Experiment '" + getName() |
| 2323 | + "', Method 'stop(Condition stopCond)'", |
| 2324 | "The parameter passed was either null or a not initialized " |
| 2325 | + "Condition reference.", |
| 2326 | "Make sure to provide a valid stop Condition for " |
| 2327 | + "this experiment."); |
| 2328 | } else { |
| 2329 | this._stopConditions.add(stopCond); |
| 2330 | } |
| 2331 | |
| 2332 | } |
| 2333 | |
| 2334 | @Deprecated |
| 2335 | /** |
| 2336 | * @deprecated Replaced by <code>stop(ModelCondition stopCond)</code> |
| 2337 | * |
| 2338 | * Specifies a Condition to stop the simulation. |
| 2339 | * |
| 2340 | * @param stopCond |
| 2341 | * Condition<?> : A condition to stop the simulation once |
| 2342 | * it's check() methode returns true. |
| 2343 | */ |
| 2344 | public void stop(Condition<?> stopCond) { |
| 2345 | |
| 2346 | if (stopCond == null) { |
| 2347 | sendWarning("Can not set stop-condition! Command ignored.", |
| 2348 | "Experiment '" + getName() |
| 2349 | + "', Method 'stop(Condition stopCond)'", |
| 2350 | "The parameter passed was either null or a not initialized " |
| 2351 | + "Condition reference.", |
| 2352 | "Make sure to provide a valid stop Condition for " |
| 2353 | + "this experiment."); |
| 2354 | } else { |
| 2355 | this.stop(new ModelCondition.ConditionWrapper(this.getModel(), stopCond)); |
| 2356 | } |
| 2357 | |
| 2358 | } |
| 2359 | |
| 2360 | /** |
| 2361 | * Stops the simulation at the given point of simulation time. If no valid |
| 2362 | * simulation time is given, the default is 0 which would not |
| 2363 | * let the simulation run past that time. Repeatedly calling this method |
| 2364 | * will override stop times specified before. |
| 2365 | * |
| 2366 | * @param stopTime |
| 2367 | * desmoj.TimeInstant : The point of simulation time to stop the |
| 2368 | * simulation |
| 2369 | */ |
| 2370 | public void stop(TimeInstant stopTime) { |
| 2371 | if (stopTime == null) { |
| 2372 | sendWarning( |
| 2373 | "Can not set stop-time! The stop-time will be set to 0", |
| 2374 | "Experiment '" + getName() |
| 2375 | + "', Method: 'stop(TimeInstant stopTime)'", |
| 2376 | "The parameter passed was either null or a not initialized " |
| 2377 | + "TimeInstance reference.", |
| 2378 | "Pass an initialized TimeInstant object as stop time."); |
| 2379 | |
| 2380 | ExternalEventStop stopper = new ExternalEventStop(_client, |
| 2381 | "Simulation stopped", true); |
| 2382 | stopper.schedule(new TimeInstant(0)); |
| 2383 | |
| 2384 | } else { |
| 2385 | |
| 2386 | this._stopTime = stopTime; |
| 2387 | if (this._stopTimeEvent != null) this._stopTimeEvent.cancel(); |
| 2388 | |
| 2389 | this._stopTimeEvent = new ExternalEventStop(_client, "Simulation stopped", true); |
| 2390 | _stopTimeEvent.schedule(stopTime); |
| 2391 | } |
| 2392 | } |
| 2393 | |
| 2394 | /** |
| 2395 | * @deprecated Stops the simulation at the given point of simulation time. |
| 2396 | * If no valid simulation time is given, the default is 0.0 |
| 2397 | * which would not let the simulation run past that time. |
| 2398 | * |
| 2399 | * @param stopTime |
| 2400 | * desmoj.SimTime : The point of simulation time to stop the |
| 2401 | * simulation |
| 2402 | */ |
| 2403 | @Deprecated |
| 2404 | public void stop(SimTime stopTime) { |
| 2405 | stop(SimTime.toTimeInstant(stopTime)); |
| 2406 | } |
| 2407 | |
| 2408 | /** |
| 2409 | * Stops the simulation at the current simulation time (immediately). A |
| 2410 | * stopped Simulation run can be resumed by calling proceed(). |
| 2411 | */ |
| 2412 | public void stop() { |
| 2413 | setStatus(STOPPED); |
| 2414 | clientScheduler.signalStop(); |
| 2415 | } |
| 2416 | |
| 2417 | /** |
| 2418 | * Returns a boolean indicating whether trace notes are forwarded to the |
| 2419 | * trace ouput or not. Trace ouput can be switched on and off using the |
| 2420 | * methods <code>traceOn(TimeInstant startTime)</code> and |
| 2421 | * <code>traceOff(TimeInstant stopTime)</code> |
| 2422 | * |
| 2423 | * @return boolean : Is <code>true</code> |
| 2424 | */ |
| 2425 | public boolean traceIsOn() { |
| 2426 | |
| 2427 | return _messMan.isOn(tracenote); |
| 2428 | |
| 2429 | } |
| 2430 | |
| 2431 | /** |
| 2432 | * Switches the trace output off at the given point of simulation time. |
| 2433 | * |
| 2434 | * @param stopTime |
| 2435 | * TimeInstant : The point in simulation time to switch trace off |
| 2436 | */ |
| 2437 | public void traceOff(TimeInstant stopTime) { |
| 2438 | |
| 2439 | // check initial TimeInstant parameter |
| 2440 | if (stopTime == null) { |
| 2441 | sendWarning( |
| 2442 | "Invalid start time parameter for trace output given! " |
| 2443 | + "Trace output is set to start immediately.", |
| 2444 | "Experiment '" + getName() |
| 2445 | + "', Method 'traceOn(TimeInstant startTime)'", |
| 2446 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 2447 | "Make sure to have a valid TimeInstant object, otherwise use method " |
| 2448 | + "start() without TimeInstant parameter."); |
| 2449 | stopTime = clientScheduler.presentTime(); |
| 2450 | } |
| 2451 | |
| 2452 | // check if parameter is in future |
| 2453 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
| 2454 | sendWarning("Invalid start time parameter for trace output given! " |
| 2455 | + "Trace output is set to start immediately.", |
| 2456 | "Experiment '" + getName() |
| 2457 | + "', Method 'traceOn(TimeInstant stopTime)'", |
| 2458 | "The stopTime given is in the past.", |
| 2459 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 2460 | stopTime = clientScheduler.presentTime(); |
| 2461 | } |
| 2462 | |
| 2463 | ExternalEvent traceOff = new ExternalEventTraceOff(_client, true); |
| 2464 | traceOff.schedule(stopTime); |
| 2465 | } |
| 2466 | |
| 2467 | /** |
| 2468 | * @deprecated Use traceOff(TimeInstant startTime). Switches the trace output off at the given point of simulation time. |
| 2469 | * |
| 2470 | * @param stopTime |
| 2471 | * SimTime : The point in simulation time to switch trace off |
| 2472 | */ |
| 2473 | public void traceOff(SimTime stopTime) { |
| 2474 | this.traceOff(SimTime.toTimeInstant(stopTime)); |
| 2475 | } |
| 2476 | |
| 2477 | /** |
| 2478 | * Switches the trace output on at the given point of simulation time. |
| 2479 | * |
| 2480 | * @param startTime |
| 2481 | * TimeInstant : The point in simulation time to switch trace on |
| 2482 | */ |
| 2483 | public void traceOn(TimeInstant startTime) { |
| 2484 | |
| 2485 | // check initial TimeInstant parameter |
| 2486 | if (startTime == null) { |
| 2487 | sendWarning( |
| 2488 | "Invalid start time parameter for trace output given! " |
| 2489 | + "Trace output is set to start immediately.", |
| 2490 | "Experiment '" + getName() |
| 2491 | + "', Method 'traceOn(TimeInstant startTime)'", |
| 2492 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 2493 | "Make sure to have a valid TimeInstant object, otherwise use method " |
| 2494 | + "start() without TimeInstant parameter."); |
| 2495 | startTime = clientScheduler.presentTime(); |
| 2496 | } |
| 2497 | |
| 2498 | // check if parameter is in future |
| 2499 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
| 2500 | sendWarning("Invalid start time parameter for trace output given! " |
| 2501 | + "Trace output is set to start immediately.", |
| 2502 | "Experiment '" + getName() |
| 2503 | + "', Method 'traceOn(TimeInstant startTime)'", |
| 2504 | "The startTime given is in the past.", |
| 2505 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 2506 | startTime = clientScheduler.presentTime(); |
| 2507 | } |
| 2508 | |
| 2509 | // if parameter equals current time, set trace on immediately, e.g. |
| 2510 | // to include initial scheduling |
| 2511 | if (TimeInstant.isEqual(clientScheduler.presentTime(), startTime)) { |
| 2512 | this.getMessageManager().switchOn(Experiment.tracenote); |
| 2513 | _client.sendTraceNote("Trace switched on"); |
| 2514 | // Otherwise schedule an appropriate event |
| 2515 | } else { |
| 2516 | ExternalEvent traceOn = new ExternalEventTraceOn(_client, true); |
| 2517 | traceOn.schedule(startTime); |
| 2518 | } |
| 2519 | |
| 2520 | } |
| 2521 | |
| 2522 | /** |
| 2523 | * @deprecated Use traceOn(TimeInstant startTime). Switches the trace output on at the given point of simulation time. |
| 2524 | * |
| 2525 | * @param startTime |
| 2526 | * SimTime : The point in simulation time to switch trace on |
| 2527 | */ |
| 2528 | public void traceOn(SimTime startTime) { |
| 2529 | this.traceOn(SimTime.toTimeInstant(startTime)); |
| 2530 | } |
| 2531 | |
| 2532 | /** |
| 2533 | * Switches the trace output on for the given period of simulation time. If |
| 2534 | * the second parameter (off) is "sooner" then the first parameter (on), |
| 2535 | * they will be swapped automatically. Same parameters will result in no |
| 2536 | * trace output at all. |
| 2537 | * |
| 2538 | * @param startTime |
| 2539 | * TimeInstant : The point in simulation time to switch trace on |
| 2540 | * @param stopTime |
| 2541 | * TimeInstant : The point in simulation time to switch trace off |
| 2542 | */ |
| 2543 | public void tracePeriod(TimeInstant startTime, TimeInstant stopTime) { |
| 2544 | if (startTime == null) { |
| 2545 | sendWarning( |
| 2546 | "Invalid start time parameter for trace output given! Command ignored", |
| 2547 | "Experiment '" + getName() |
| 2548 | + "', Method 'tracePeriod(TimeInstant startTime, " |
| 2549 | + "TimeInstant stopTime)'", |
| 2550 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 2551 | "Make sure to have a valid TimeInstant object."); |
| 2552 | return; |
| 2553 | } |
| 2554 | |
| 2555 | // check initial TimeInstant parameter |
| 2556 | if (stopTime == null) { |
| 2557 | sendWarning( |
| 2558 | "Invalid stop time parameter for trace output given! Command ignored.", |
| 2559 | "Experiment '" + getName() |
| 2560 | + "', Method 'tracePeriod(TimeInstant startTime, " |
| 2561 | + "TimeInstant stopTime)'", |
| 2562 | "A null value or a not initialized TimeInstant reference has been passed.", |
| 2563 | "Make sure to have a valid TimeInstant object."); |
| 2564 | return; |
| 2565 | } |
| 2566 | |
| 2567 | // check for correct order in parameters |
| 2568 | if (TimeInstant.isAfter(startTime, stopTime)) { |
| 2569 | |
| 2570 | // swap parameters |
| 2571 | TimeInstant buffer = stopTime; |
| 2572 | stopTime = startTime; |
| 2573 | startTime = buffer; |
| 2574 | |
| 2575 | } |
| 2576 | |
| 2577 | // check if stop parameter is in future |
| 2578 | if (TimeInstant.isAfter(clientScheduler.presentTime(), stopTime)) { |
| 2579 | sendWarning( |
| 2580 | "Invalid stop time parameter for trace output given! Command ignored.", |
| 2581 | "Experiment '" + getName() |
| 2582 | + "', Method 'tracePeriod(TimeInstant startTime, " |
| 2583 | + "TimeInstant stopTime)'", |
| 2584 | "The stopTime given is in the past.", |
| 2585 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 2586 | return; |
| 2587 | } |
| 2588 | |
| 2589 | // check if start parameter is in past |
| 2590 | if (TimeInstant.isAfter(clientScheduler.presentTime(), startTime)) { |
| 2591 | sendWarning("Invalid start time parameter for trace output given! " |
| 2592 | + "Trace output has been set to start immediately.", |
| 2593 | "Experiment '" + getName() |
| 2594 | + "', Method 'tracePeriod(TimeInstant startTime, " |
| 2595 | + "TimeInstant startTime)'", |
| 2596 | "The startTime given is in the past.", |
| 2597 | "Make sure to give a TimeInstant parameter larger than the current time."); |
| 2598 | startTime = clientScheduler.presentTime(); |
| 2599 | } |
| 2600 | |
| 2601 | // set trace to switch on |
| 2602 | traceOn(startTime); |
| 2603 | |
| 2604 | // set trace to switch off |
| 2605 | traceOff(stopTime); |
| 2606 | } |
| 2607 | |
| 2608 | /** |
| 2609 | * @deprecated Replaced by tracePeriod(TimeInstant startTime, TimeInstant |
| 2610 | * stopTime). Switches the trace output on for the given period |
| 2611 | * of simulation time. If the second parameter (off) is "sooner" |
| 2612 | * then the first parameter (on), they will be swapped |
| 2613 | * automatically. Same parameters will result in no trace output |
| 2614 | * at all. |
| 2615 | * |
| 2616 | * @param startTime |
| 2617 | * SimTime : The point in simulation time to switch trace on |
| 2618 | * @param stopTime |
| 2619 | * SimTime : The point in simulation time to switch trace off |
| 2620 | */ |
| 2621 | @Deprecated |
| 2622 | public void tracePeriod(SimTime startTime, SimTime stopTime) { |
| 2623 | tracePeriod(SimTime.toTimeInstant(startTime), SimTime |
| 2624 | .toTimeInstant(stopTime)); |
| 2625 | } |
| 2626 | |
| 2627 | /** |
| 2628 | * Triggers the reporters of the given model or submodel to write their |
| 2629 | * report data into the report output registered at the experiment's |
| 2630 | * messagemanager. The string given will be added as a suffix to the report |
| 2631 | * filename to help identify teh report when more than one report is |
| 2632 | * produced by one Experiment at differnet points of simulation time. |
| 2633 | * |
| 2634 | * @param m |
| 2635 | * desmoj.Model |
| 2636 | * @param suffix |
| 2637 | * java.lang.String : Suffix for report filename if multiple |
| 2638 | * reports are drawn |
| 2639 | */ |
| 2640 | public void writeReport(Model m, String suffix) { |
| 2641 | |
| 2642 | if (suffix == null) |
| 2643 | suffix = ""; |
| 2644 | |
| 2645 | // buffer used for storing the filename in |
| 2646 | String nameBuffer = null; |
| 2647 | |
| 2648 | // now flush and close all files and reopen with new names |
| 2649 | for (FileOutput f : _registryFileOutput) { |
| 2650 | |
| 2651 | // remember the name the file had |
| 2652 | nameBuffer = f.getFileName(); |
| 2653 | |
| 2654 | // flush buffer and close file |
| 2655 | f.close(); |
| 2656 | |
| 2657 | // open new file with old name stripping off old suffix and |
| 2658 | // adding new suffix |
| 2659 | nameBuffer = nameBuffer.substring(0, nameBuffer.lastIndexOf(".")); |
| 2660 | f.open(nameBuffer.substring(0, (nameBuffer.length() - lastSuffix)) |
| 2661 | + suffix + "html"); |
| 2662 | } |
| 2663 | lastSuffix = suffix.length(); // remember last suffix length |
| 2664 | report(m); |
| 2665 | } |
| 2666 | |
| 2667 | /** |
| 2668 | * Triggers the reporters to write their data into the report output |
| 2669 | * registered at the experiment's messagemanager. The string given will be |
| 2670 | * added as a suffix to the report filename to help identification when more |
| 2671 | * than one report is produced by one Experiment at differnet points of |
| 2672 | * simulation time. |
| 2673 | * |
| 2674 | * @param suffix |
| 2675 | * java.lang.String : Suffix for report filename if multiple |
| 2676 | * reports are drawn |
| 2677 | */ |
| 2678 | public void writeReport(String suffix) { |
| 2679 | |
| 2680 | if (suffix == null) |
| 2681 | suffix = ""; |
| 2682 | |
| 2683 | // write report data about main model |
| 2684 | report(_client); |
| 2685 | |
| 2686 | // buffer used for storing the filename in |
| 2687 | String nameBuffer = null; |
| 2688 | |
| 2689 | // now flush and close all files and reopen with new names |
| 2690 | for (FileOutput f : _registryFileOutput) { |
| 2691 | |
| 2692 | // remember the name the file had |
| 2693 | nameBuffer = f.getFileName(); |
| 2694 | |
| 2695 | // flush buffer and close file |
| 2696 | f.close(); |
| 2697 | |
| 2698 | // open new file with old name stripping off old suffix and |
| 2699 | // adding new suffix |
| 2700 | // strip the _debug / _error / _trace / _report part |
| 2701 | nameBuffer = nameBuffer.substring(0, nameBuffer.lastIndexOf("_")); |
| 2702 | // strip the previous suffix |
| 2703 | nameBuffer = nameBuffer.substring(0, nameBuffer.length() |
| 2704 | - lastSuffix); |
| 2705 | // add new suffix |
| 2706 | nameBuffer = nameBuffer + suffix; |
| 2707 | // now open file with new name |
| 2708 | f.open(nameBuffer); |
| 2709 | } |
| 2710 | lastSuffix = suffix.length(); // remember last suffix length |
| 2711 | } |
| 2712 | |
| 2713 | /** |
| 2714 | * Returns the current DESMO-J version |
| 2715 | * |
| 2716 | * @return The string "2.3.3". |
| 2717 | */ |
| 2718 | public static String getDesmoJVersion() { |
| 2719 | return "2.3.3"; |
| 2720 | } |
| 2721 | |
| 2722 | /** |
| 2723 | * Returns the DESMO-J license |
| 2724 | * |
| 2725 | * @param html |
| 2726 | * boolean: Include link (HTML, true) or not (plain text, false) |
| 2727 | * |
| 2728 | * @return The string "Apache License, Version 2.0", embedded in a HTML link |
| 2729 | * tag (currently http://www.apache.org/licenses/LICENSE-2.0) if |
| 2730 | * <code>html</code> is set true. |
| 2731 | */ |
| 2732 | public static String getDesmoJLicense(boolean html) { |
| 2733 | return html ? "<A HREF=http://www.apache.org/licenses/LICENSE-2.0>Apache License, Version 2.0</A>" |
| 2734 | : "Apache License, Version 2.0"; |
| 2735 | } |
| 2736 | |
| 2737 | public void setDescription(String description) { |
| 2738 | this._description = description; |
| 2739 | } |
| 2740 | |
| 2741 | public String getDescription() { |
| 2742 | return _description; |
| 2743 | } |
| 2744 | } |