1 | package desmoj.core.simulator; |
2 | |
3 | /** |
4 | * Provides the class for user defined events to change <b>two</b> entities' |
5 | * internal states. The state of a discrete model is changed by events that occur |
6 | * at distinct points of simulation time.<p> |
7 | * For events changing the state of <b>one</b> or <b>three</b> entities, |
8 | * refer to <code>Event</code> and <code>EventOf3Entities</code>. |
9 | * Events not associated to a specific entity are based on <code>ExternalEvent</code>. |
10 | * <p> |
11 | * For type safety it is recommended to generically assign the entity types an |
12 | * <code>EventOf2Entities</code> operates on by using the generic type |
13 | * <code>EventOf2Entities<E,F></code> where |
14 | * <code>E</code> and <code>F</code> are derived from <code>Entity</code>. |
15 | * <p> |
16 | * All event object should be used only once. Implement the changes of state for the |
17 | * specific entities associated with this event by overriding the abstract method |
18 | * <code>eventRoutine(E who1, F who2)</code>. |
19 | * |
20 | * @see Entity |
21 | * @see ExternalEvent |
22 | * @see Event |
23 | * @see EventOf3Entities |
24 | * @see TimeInstant |
25 | * @see TimeSpan |
26 | * |
27 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
28 | * @author Tim Lechler |
29 | * @author modified by Justin Neumann |
30 | * |
31 | * Licensed under the Apache License, Version 2.0 (the "License"); |
32 | * you may not use this file except in compliance with the License. You |
33 | * may obtain a copy of the License at |
34 | * http://www.apache.org/licenses/LICENSE-2.0 |
35 | * |
36 | * Unless required by applicable law or agreed to in writing, software |
37 | * distributed under the License is distributed on an "AS IS" |
38 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
39 | * or implied. See the License for the specific language governing |
40 | * permissions and limitations under the License. |
41 | * |
42 | */ |
43 | public abstract class EventOf2Entities<E extends Entity, F extends Entity> extends EventAbstract { |
44 | |
45 | /** |
46 | * Creates a new Event of the given model, with the given name and trace |
47 | * option. |
48 | * |
49 | * @param name |
50 | * java.lang.String : The name of this event |
51 | * @param owner |
52 | * Model : The model this event is associated to |
53 | * @param showInTrace |
54 | * boolean : Flag for showing Event in trace-files. Set it to |
55 | * <code>true</code> if Event should show up in trace. Set it to |
56 | * <code>false</code> if Event should not be shown in trace. |
57 | */ |
58 | public EventOf2Entities(Model owner, String name, boolean showInTrace) { |
59 | |
60 | super(owner, name, showInTrace); |
61 | this.numberOfEntities = 2; |
62 | |
63 | } |
64 | |
65 | /** |
66 | * Implement this abstract method to express the changes of state this event |
67 | * does to two entities (as <code>SimProcess</code> is a subclass of |
68 | * <code>Entity</code>, processes can be passed as well). |
69 | * <p> |
70 | * For type safety, it is recommended to derive your events from the generic |
71 | * type <code>EventOf2Entities<EntityType1,EntityType2></code> where |
72 | * <code>EntityType1</code> and <code>EntityType2</code> (which are derived from class |
73 | * <code>Entity</code>) represent the entity types your event is supposed to |
74 | * operate on. |
75 | * <p> |
76 | * Should you decide to derive your event from the raw type |
77 | * <code>EventOf2Entities</code> (which is not recommended), please take extra care in |
78 | * checking the given Entity parameters to your special eventRoutine since |
79 | * any subtype of Entity will be accepted! If your model uses several |
80 | * different entity types, chances are that while developing the model, |
81 | * wrong entity types might be passed. |
82 | * |
83 | * @param who1 |
84 | * E : The first entity associated to this event. |
85 | * @param who2 |
86 | * F : The second entity associated to this event. |
87 | */ |
88 | public abstract void eventRoutine(E who1, F who2); |
89 | |
90 | /** |
91 | * Schedules this event to act on the given entities at a certain point in |
92 | * simulation time. |
93 | * |
94 | * @param who1 |
95 | * E : The first entity to be manipulated by this event |
96 | * @param who2 |
97 | * F : The second entity to be manipulated by this event |
98 | * @param instant |
99 | * TimeInstant : The point in simulation time this event is |
100 | * scheduled to happen. |
101 | */ |
102 | public void schedule(E who1, F who2, TimeInstant instant) { |
103 | |
104 | if ((instant == null)) { |
105 | sendWarning("Can't schedule Event!", "Event : " + getName() |
106 | + " Method: eventRoutine(E who1, F who2)", |
107 | "The TimeInstant given as parameter is a null reference.", |
108 | "Be sure to have a valid TimeInstant reference before calling " |
109 | + "this method."); |
110 | return; // no proper parameter |
111 | } |
112 | |
113 | if ((who1 == null)) { |
114 | sendWarning("Can't schedule Event!", "Event : " + getName() |
115 | + " Method: eventRoutine(E who1, F who2)", |
116 | "The first entity given as parameter is a null reference.", |
117 | "Be sure to have a valid Entity reference for this event to " |
118 | + "be scheduled with."); |
119 | return; // no proper parameter |
120 | } |
121 | |
122 | if ((who2 == null)) { |
123 | sendWarning("Can't schedule Event!", "Event : " + getName() |
124 | + " Method: eventRoutine(E who1, F who2)", |
125 | "The second entity given as parameter is a null reference.", |
126 | "Be sure to have a valid Entity reference for this event to " |
127 | + "be scheduled with."); |
128 | return; // no proper parameter |
129 | } |
130 | |
131 | if (isScheduled()) { |
132 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
133 | + getName() |
134 | + " Method: eventRoutine(E who1, F who2)", |
135 | "The event to be scheduled is already scheduled.", |
136 | "Use method events only once, do not use them multiple " |
137 | + "times."); |
138 | return; // was already scheduled |
139 | } |
140 | |
141 | if (!isModelCompatible(who1)) { |
142 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
143 | + getName() |
144 | + " Method: eventRoutine(E who1, F who2)", |
145 | "The first entity to be scheduled with this event is not " |
146 | + "modelcompatible.", |
147 | "Make sure to use compatible model components only."); |
148 | return; // is not compatible |
149 | } |
150 | |
151 | if (!isModelCompatible(who2)) { |
152 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
153 | + getName() |
154 | + " Method: eventRoutine(E who1, F who2)", |
155 | "The second entity to be scheduled with this event is not " |
156 | + "modelcompatible.", |
157 | "Make sure to use compatible model components only."); |
158 | return; // is not compatible |
159 | } |
160 | |
161 | // generate trace |
162 | this.generateTraceForScheduling(who1, who2, null, null, null, instant); |
163 | |
164 | // schedule Event |
165 | getModel().getExperiment().getScheduler().schedule(who1, who2, this, instant); |
166 | |
167 | if (currentlySendDebugNotes()) { |
168 | sendDebugNote("schedules on EventList<br>" |
169 | + getModel().getExperiment().getScheduler().toString()); |
170 | } |
171 | |
172 | } |
173 | |
174 | /** |
175 | * Schedules this event to act on the given Entity at the specified point in |
176 | * simulation time. The point of time is given as an offset to the current |
177 | * simulation time as displayed by the simulation clock. |
178 | * |
179 | * @param who1 |
180 | * E : The first entity this event happens to |
181 | * @param who2 |
182 | * F : The second entity this event happens to |
183 | * @param dt |
184 | * TimeSpan : The offset to the current simulation time this |
185 | * Event is to happen |
186 | * @see SimClock |
187 | */ |
188 | public void schedule(E who1, F who2, TimeSpan dt) { |
189 | if ((dt == null)) { |
190 | sendWarning("Can't schedule Event!", "Event : " + getName() |
191 | + " Method: schedule(E who1, F who2, TimeSpan dt)", |
192 | "The TimeSpan given as parameter is a null reference.", |
193 | "Be sure to have a valid TimeSpan reference before calling " |
194 | + "this method."); |
195 | return; // no proper parameter |
196 | } |
197 | |
198 | if ((who1 == null)) { |
199 | sendWarning("Can't schedule Event!", "Event : " + getName() |
200 | + " Method: schedule(E who1, F who2, TimeSpan dt)", |
201 | "The first entity given as parameter is a null reference.", |
202 | "Be sure to have a valid Entity reference for this event to " |
203 | + "be scheduled with."); |
204 | return; // no proper parameter |
205 | } |
206 | |
207 | if ((who2 == null)) { |
208 | sendWarning("Can't schedule Event!", "Event : " + getName() |
209 | + " Method: schedule(E who1, F who2, TimeSpan dt)", |
210 | "The second entity given as parameter is a null reference.", |
211 | "Be sure to have a valid Entity reference for this event to " |
212 | + "be scheduled with."); |
213 | return; // no proper parameter |
214 | } |
215 | |
216 | if (isScheduled()) { |
217 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
218 | + getName() + " Method: schedule(E who1, F who2, TimeSpan dt)", |
219 | "The event to be scheduled is already scheduled.", |
220 | "Use method events only once, do not use them multiple " |
221 | + "times."); |
222 | return; // was already scheduled |
223 | } |
224 | |
225 | if (!isModelCompatible(who1)) { |
226 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
227 | + getName() + " Method: schedule(E who1, F who2, TimeSpan dt)", |
228 | "The first entity to be scheduled with this event is not " |
229 | + "modelcompatible.", |
230 | "Make sure to use compatible model components only."); |
231 | return; // is not compatible |
232 | } |
233 | |
234 | if (!isModelCompatible(who2)) { |
235 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
236 | + getName() + " Method: schedule(E who1, F who2, TimeSpan dt)", |
237 | "The second entity to be scheduled with this event is not " |
238 | + "modelcompatible.", |
239 | "Make sure to use compatible model components only."); |
240 | return; // is not compatible |
241 | } |
242 | |
243 | // generate trace |
244 | this.generateTraceForScheduling(who1, who2, null, null, null, TimeOperations.add(presentTime(), dt)); |
245 | |
246 | // schedule Event |
247 | getModel().getExperiment().getScheduler().schedule(who1, who2, this, dt); |
248 | |
249 | if (currentlySendDebugNotes()) { |
250 | sendDebugNote("schedules on EventList<br>" |
251 | + getModel().getExperiment().getScheduler().toString()); |
252 | } |
253 | |
254 | } |
255 | |
256 | /** |
257 | * Schedules this event to act on the given Entity directly after the given |
258 | * Schedulable is already set to be activated. Note that this event's point |
259 | * of simulation time will be set to be the same as the Schedulable's time. |
260 | * Thus this event will occur directly after the given Schedulable but the |
261 | * simulation clock will not change. Make sure that the Schedulable given as |
262 | * parameter is actually scheduled. |
263 | * |
264 | * @param after |
265 | * Schedulable : The Schedulable this entity should be scheduled |
266 | * after |
267 | * @param who1 |
268 | * E : The first entity to be manipulated by this event |
269 | * @param who2 |
270 | * F : The second entity to be manipulated by this event |
271 | */ |
272 | public void scheduleAfter(Schedulable after, E who1, F who2) { |
273 | |
274 | if (who1 == null) { |
275 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
276 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
277 | "The Entity 'who1' given as parameter is a null reference.", |
278 | "Be sure to have a valid Entity reference before calling " |
279 | + "this method."); |
280 | return; // no proper parameter |
281 | } |
282 | |
283 | if (who2 == null) { |
284 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
285 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
286 | "The second entity 'who' given as parameter is a null reference.", |
287 | "Be sure to have a valid Entity reference before calling " |
288 | + "this method."); |
289 | return; // no proper parameter |
290 | } |
291 | |
292 | if (after == null) { |
293 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
294 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
295 | "The Schedulable given as parameter is a null reference.", |
296 | "Be sure to have a valid Schedulable reference for this " |
297 | + "Event to be scheduled with."); |
298 | return; // no proper parameter |
299 | } |
300 | |
301 | if (isScheduled()) { |
302 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
303 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
304 | "The event to be scheduled is already scheduled.", |
305 | "Use method events only once, do not use them multiple " |
306 | + "times."); |
307 | return; // was already scheduled |
308 | } |
309 | |
310 | if (!after.isScheduled()) { |
311 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
312 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)" |
313 | , "The Schedulable '" + after.getName() |
314 | + "' given as a positioning " |
315 | + "reference has to be already scheduled but is not.", |
316 | "Use method isScheduled() of any Schedulable to find out " |
317 | + "if it is already scheduled."); |
318 | return; // was not scheduled |
319 | } |
320 | |
321 | if (!isModelCompatible(who1)) { |
322 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
323 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
324 | "The first entity to be scheduled with this event is not " |
325 | + "modelcompatible.", |
326 | "Make sure to use compatible model components only."); |
327 | return; // is not compatible |
328 | } |
329 | |
330 | if (!isModelCompatible(who2)) { |
331 | sendWarning("Can't schedule Event! Command ignored", "Entity : " |
332 | + getName() + " Method: scheduleAfter(Schedulable after, E who1, F who2)", |
333 | "The second entity to be scheduled with this event is not " |
334 | + "modelcompatible.", |
335 | "Make sure to use compatible model components only."); |
336 | return; // is not compatible |
337 | } |
338 | |
339 | // generate trace |
340 | this.generateTraceForScheduling(who1, who2, null, after, null, after.getEventNotes().get(after.getEventNotes().size()-1).getTime()); |
341 | |
342 | // schedule Event |
343 | getModel().getExperiment().getScheduler().scheduleAfter(after, who1, who2, |
344 | this); |
345 | |
346 | if (currentlySendDebugNotes()) { |
347 | sendDebugNote("scheduleAfter " + after.getQuotedName() |
348 | + " on EventList<br>" |
349 | + getModel().getExperiment().getScheduler().toString()); |
350 | } |
351 | |
352 | } |
353 | |
354 | /** |
355 | * Schedules this event to act on the given Entity directly before the given |
356 | * Schedulable is already set to be activated. Note that this event's point |
357 | * of simulation time will be set to be the same as the Schedulable's time. |
358 | * Thus this event will occur directly before the given Schedulable but the |
359 | * simulation clock will not change. Make sure that the Schedulable given as |
360 | * parameter is actually scheduled. |
361 | * |
362 | * @param before |
363 | * Schedulable : The Schedulable this entity should be scheduled |
364 | * before |
365 | * @param who1 |
366 | * E : The first entity to be manipulated by this event |
367 | * @param who2 |
368 | * F : The second entity to be manipulated by this event |
369 | */ |
370 | public void scheduleBefore(Schedulable before, E who1, F who2) { |
371 | |
372 | if ((who1 == null)) { |
373 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
374 | + getName() |
375 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
376 | "The Entity 'who1' given as parameter is a null reference.", |
377 | "Be sure to have a valid Entity reference before calling " |
378 | + "this method."); |
379 | return; // no proper parameter |
380 | } |
381 | |
382 | if ((who2 == null)) { |
383 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
384 | + getName() |
385 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
386 | "The Entity 'who2' given as parameter is a null reference.", |
387 | "Be sure to have a valid Entity reference before calling " |
388 | + "this method."); |
389 | return; // no proper parameter |
390 | } |
391 | |
392 | if ((before == null)) { |
393 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
394 | + getName() |
395 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
396 | "The Schedulable given as parameter is a null reference.", |
397 | "Be sure to have a valid Schedulable reference for this " |
398 | + "Event to be scheduled with."); |
399 | return; // no proper parameter |
400 | } |
401 | |
402 | if (isScheduled()) { |
403 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
404 | + getName() |
405 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
406 | "The event to be scheduled is already scheduled.", |
407 | "Use method events only once, do not use them multiple " |
408 | + "times."); |
409 | return; // was already scheduled |
410 | } |
411 | |
412 | if (!before.isScheduled()) { |
413 | sendWarning("Can't schedule Event! Command ignored.", "Event : " |
414 | + getName() + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
415 | "The Schedulable '" + before.getName() |
416 | + "' given as a " |
417 | + "positioning reference has to be already scheduled but " |
418 | + "is not.", |
419 | "Use method isScheduled() of any Schedulable to find out " |
420 | + "if it is already scheduled."); |
421 | return; // was not scheduled |
422 | } |
423 | |
424 | if (!isModelCompatible(who1)) { |
425 | sendWarning("Can't schedule Event! Command ignored", "Event : " |
426 | + getName() |
427 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
428 | "The first entity to be scheduled with this event is not " |
429 | + "modelcompatible.", |
430 | "Make sure to use compatible model components only."); |
431 | return; // is not compatible |
432 | } |
433 | |
434 | if (!isModelCompatible(who2)) { |
435 | sendWarning("Can't schedule Event! Command ignored", "Event : " |
436 | + getName() |
437 | + " Method: scheduleBefore(Schedulable before, E who1, F who2)", |
438 | "The second entity to be scheduled with this event is not " |
439 | + "modelcompatible.", |
440 | "Make sure to use compatible model components only."); |
441 | return; // is not compatible |
442 | } |
443 | |
444 | // generate trace |
445 | this.generateTraceForScheduling(who1, who2, null, null, before, before.getEventNotes().get(0).getTime()); |
446 | |
447 | // schedule Event |
448 | getModel().getExperiment().getScheduler().scheduleBefore(before, who1, who2, |
449 | this); |
450 | |
451 | if (currentlySendDebugNotes()) { |
452 | sendDebugNote("scheduleBefore " + before.getQuotedName() |
453 | + " on EventList<br>" |
454 | + getModel().getExperiment().getScheduler().toString()); |
455 | } |
456 | |
457 | } |
458 | |
459 | /** |
460 | * Creates and returns a copy of this event. |
461 | * Note that subclasses have to implement the interface |
462 | * </code>java.lang.Cloneable</code> to actually use this method as |
463 | * otherwise, a </code>CloneNotSupportedException</code> will be thrown. |
464 | * |
465 | * @return EventOf2Entities<E,F> : A copy of this event. |
466 | */ |
467 | protected EventOf2Entities<E,F> clone() throws CloneNotSupportedException { |
468 | return (EventOf2Entities<E,F>) super.clone(); |
469 | } |
470 | } |