1 | package desmoj.core.simulator; |
2 | |
3 | import java.util.LinkedList; |
4 | import java.util.List; |
5 | |
6 | /** |
7 | * All objects that want to be handled by the scheduler must extend this class. |
8 | * These are events (including external events), entities and SimProcesses. All |
9 | * functionality common to Schedulable objects are encapsulated here. |
10 | * |
11 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
12 | * @author Tim Lechler |
13 | * |
14 | * Licensed under the Apache License, Version 2.0 (the "License"); you |
15 | * may not use this file except in compliance with the License. You may |
16 | * obtain a copy of the License at |
17 | * http://www.apache.org/licenses/LICENSE-2.0 |
18 | * |
19 | * Unless required by applicable law or agreed to in writing, software |
20 | * distributed under the License is distributed on an "AS IS" BASIS, |
21 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
22 | * implied. See the License for the specific language governing |
23 | * permissions and limitations under the License. |
24 | * |
25 | */ |
26 | public class Schedulable extends ModelComponent { |
27 | |
28 | /** |
29 | * A list containing all scheduled entries for this Schedulable in future. |
30 | */ |
31 | protected List<EventNote> _schedule; |
32 | |
33 | /** |
34 | * Constructs a Schedulable object with the given name. Note that to |
35 | * identify the multiple objects that can be created of one type of |
36 | * Schedulable, each has a unique number added to its name as a suffix. The |
37 | * numbers represent the amount of objects being created with the same name. |
38 | * |
39 | * @param name |
40 | * java.lang.String : The name of the new Schedulable object |
41 | * @param owner |
42 | * Model : The owner of this Schedulable object |
43 | */ |
44 | public Schedulable(Model owner, String name, boolean showInTrace) { |
45 | |
46 | // create modelcomponent with the checked and registered name |
47 | super(owner, owner.getExperiment().getNameCatalog() |
48 | .registeredName(name), showInTrace); |
49 | this._schedule = new LinkedList<EventNote>(); |
50 | } |
51 | |
52 | |
53 | /** |
54 | * Removes all events scheduled for this entity from the event-list. |
55 | * The Entity will not become active until scheduled again. |
56 | */ |
57 | public void cancel() |
58 | { |
59 | if (!isScheduled()) { |
60 | sendWarning("Can't cancel Schedulable! Command ignored.", |
61 | "Schedulable : " + getName() + " Method: void cancel()", |
62 | "The Schedulable to be canceled is not scheduled.", |
63 | "Use method isSchedule() to test if the Schedulable " |
64 | + "is scheduled and thus can be canceled or not."); |
65 | return; // was already scheduled |
66 | } |
67 | |
68 | // removes all scheduled events for this entity by using global event-list |
69 | while(!_schedule.isEmpty()) |
70 | { |
71 | //EventNote firstNote = this.getModel().getExperiment().getScheduler().evList.firstNote(); |
72 | EventNote firstNote = _schedule.get(0); |
73 | |
74 | if (currentlySendTraceNotes()) { |
75 | TimeInstant time = firstNote.getTime(); |
76 | if (this == current()) { |
77 | if (time == presentTime()) |
78 | sendTraceNote("cancels scheduled Event " + firstNote.getEvent() + " for itself, which was scheduled now"); |
79 | else |
80 | sendTraceNote("cancels scheduled Event " + firstNote.getEvent() + " for itself, which was scheduled at " + time); |
81 | } else { |
82 | if (time == presentTime()) |
83 | sendTraceNote("cancels scheduled Event " + firstNote.getEvent() + " for " + this.getName() + ", which was scheduled now"); |
84 | else |
85 | sendTraceNote("cancels scheduled Event " + firstNote.getEvent() + " for " + this.getName() + ", which was scheduled at " + time); |
86 | } |
87 | } |
88 | this.getModel().getExperiment().getScheduler().evList.remove(firstNote); |
89 | } |
90 | } |
91 | |
92 | |
93 | /** |
94 | * Returns a list of EventNote associated to this Entity object. If the |
95 | * Entity object is not currently scheduled, <code>null</code> will be |
96 | * returned. Remind that all different Event classes can be included. |
97 | * |
98 | * @return List<EventNote> : The event-notes associated to the entity or |
99 | * <code>null</code> if Entity is not currently scheduled |
100 | */ |
101 | List<EventNote> getEventNotes() |
102 | { |
103 | return _schedule; |
104 | |
105 | } |
106 | |
107 | /** |
108 | * Shows if this Schedulable is the currently active object. |
109 | * |
110 | * @return boolean :<code>true</code> if this Schedulable is the currently |
111 | * active, <code>false</code> otherwise |
112 | */ |
113 | public boolean isCurrent() { |
114 | |
115 | return this.equals(getModel().getExperiment().getScheduler() |
116 | .getCurrentSchedulable()); |
117 | |
118 | } |
119 | |
120 | /** |
121 | * Tests if this entity has already been scheduled. |
122 | * |
123 | * @return boolean :<code>true</code> if already scheduled, |
124 | * <code>false</code> otherwise |
125 | */ |
126 | public boolean isScheduled() { |
127 | |
128 | // Not associated to EventNote if not scheduled |
129 | return (!_schedule.isEmpty()); |
130 | |
131 | } |
132 | |
133 | /** |
134 | * Removes an event-note from the internal list |
135 | * |
136 | * * @param note |
137 | * EventNote : The <code>EventNote to be removed</code> |
138 | */ |
139 | void removeEventNote(EventNote note) |
140 | { |
141 | _schedule.remove(note); // only removes Event in local list |
142 | |
143 | } |
144 | |
145 | /** |
146 | * Allows to rename a Schedulable object while keeping its internally added |
147 | * serial number to keep track of the individual object. Note that invalid |
148 | * string parameters will result in renaming the Schedulable to 'unnamed'. |
149 | * |
150 | * @param newName |
151 | * java.lang.String : The Schedulable's new name |
152 | */ |
153 | public void rename(String newName) { |
154 | |
155 | super.rename(getModel().getExperiment().getNameCatalog() |
156 | .registeredName(newName)); |
157 | |
158 | } |
159 | |
160 | /** |
161 | * Re-schedules the Schedulable by shifting all EventNote by a specified <code> |
162 | * TimeSpan</code>. |
163 | * |
164 | * @param dt |
165 | * TimeSpan : The offset to the current simulation time at which |
166 | * this Schedulable is to be re-scheduled |
167 | */ |
168 | public void reSchedule(TimeSpan dt) |
169 | { |
170 | if (dt == null) { |
171 | sendWarning("Can't reSchedule Schedulable! Command ingnored.", |
172 | "Schedulable : " + getName() |
173 | + " Method: reSchedule(TimeSpan dt)", |
174 | "The simulation time given as parameter is a null " |
175 | + "reference.", |
176 | "Be sure to have a valid TimeSpan reference before calling " |
177 | + "this method."); |
178 | return; // no proper parameter |
179 | } |
180 | |
181 | if (!isScheduled()) { |
182 | sendWarning("Can't reSchedule Schedulable! Command ingnored.", |
183 | "Schedulable : " + getName() |
184 | + " Method: reSchedule(TimeSpan dt)", |
185 | "The Schedulable is not scheduled, thus unable to be " |
186 | + "reScheduled..", |
187 | "Be sure that the Schedulable is currently scheduled " |
188 | + "before calling this method."); |
189 | return; // no proper parameter |
190 | } |
191 | |
192 | // create list with new events and remove old events |
193 | EventNote newNote = null; |
194 | List<EventNote> oldNotes = new LinkedList<EventNote>(_schedule); |
195 | List<EventNote> newNotes = new LinkedList<EventNote>(); |
196 | for (EventNote oldNote : oldNotes) |
197 | { |
198 | newNote = oldNote.copy(); // copy EventNote |
199 | newNote.setTime(TimeOperations.add(oldNote.getTime(), dt)); // shift it |
200 | newNotes.add(newNote); // save it to new list |
201 | this.getModel().getExperiment().getScheduler().evList.remove(oldNote); // remove original event-note local and global |
202 | |
203 | if (currentlySendTraceNotes()) { |
204 | TimeInstant timeOld = oldNote.getTime(); |
205 | TimeInstant timeNew = newNote.getTime(); |
206 | if (this == current()) { |
207 | if (timeOld == presentTime()) |
208 | sendTraceNote("reschedules " + newNote.getEvent() + " for itself, which was scheduled now, to " + timeNew); |
209 | else |
210 | sendTraceNote("reschedules " + newNote.getEvent() + " for itself, which was scheduled at " + timeOld + ", to " + timeNew); |
211 | } else { |
212 | if (timeOld == presentTime()) |
213 | sendTraceNote("reschedules " + newNote.getEvent() + " for " + this.getName() + ", which was scheduled now, to " + timeNew); |
214 | else |
215 | sendTraceNote("reschedules " + newNote.getEvent() + " for " + this.getName() + ", which was scheduled at " + timeOld + ", to " + timeNew); |
216 | } |
217 | } |
218 | |
219 | } |
220 | |
221 | //insert temp to schedule |
222 | for (EventNote ev : newNotes) |
223 | { |
224 | // insert to GLOBAL list, which inserts to local one |
225 | this.getModel().getExperiment().getScheduler().evList.insert(ev); |
226 | } |
227 | |
228 | } |
229 | |
230 | /** |
231 | * Re-schedules the Schedulable to some other point in simulation time |
232 | * (which should be different form the instant at which is a scheduled |
233 | * at the moment). |
234 | * |
235 | * @param time |
236 | * TimeInstant : The simulation time at which |
237 | * this entity is to be re-scheduled |
238 | */ |
239 | public void reSchedule(TimeInstant time) { |
240 | |
241 | if (time == null) { |
242 | sendWarning("Can't reSchedule enitty! Command ingnored.", |
243 | "Entity : " + getName() |
244 | + " Method: reSchedule(TimeInstant time)", |
245 | "The simulation time given as parameter is a null " |
246 | + "reference.", |
247 | "Be sure to have a valid TimeSpan reference before calling " |
248 | + "this method."); |
249 | return; // no proper parameter |
250 | } |
251 | |
252 | if (!isScheduled()) { |
253 | sendWarning("Can't reSchedule Schedulable! Command ingnored.", |
254 | "Entity : " + getName() |
255 | + " Method: reSchedule(TimeInstant time)", |
256 | "The Entity is not scheduled, thus unable to be " |
257 | + "reScheduled.", |
258 | "Be sure that the entity is currently scheduled " |
259 | + "before calling this method."); |
260 | return; // no proper parameter |
261 | } |
262 | |
263 | if (_schedule.size()>1) { |
264 | sendWarning("Can't reSchedule Entity! Command ingnored.", |
265 | "Entity : " + getName() |
266 | + " Method: reSchedule(TimeInstant time)", |
267 | "The Entity is scheduled more then once, thus unable to be " |
268 | + "reScheduled.", |
269 | "Be sure that the entity is only scheduled once" |
270 | + "before calling this method."); |
271 | return; // no proper parameter |
272 | } |
273 | |
274 | if (TimeInstant.isBefore(time, this.presentTime())) { |
275 | sendWarning( |
276 | "Can't reschedule Entity at given time! " |
277 | + "Command ignored.", |
278 | "Entity : " |
279 | + getName() |
280 | + " Method: reSchedule(TimeInstant time)", |
281 | "The instant given is in the past.", |
282 | "To reschedule an entity, use a TimeInstant no earlier than the present time. " |
283 | + "The present time can be obtained using the " |
284 | + "presentTime() method"); |
285 | return; |
286 | // I can't be rescheduled, TimeInstant has already passed. |
287 | } |
288 | |
289 | if (currentlySendTraceNotes()) { |
290 | if (this == current()) { |
291 | if (time == presentTime()) |
292 | sendTraceNote("reschedules itself now"); |
293 | else |
294 | sendTraceNote("reschedules itself at " |
295 | + time); |
296 | } else { |
297 | if (time == presentTime()) |
298 | sendTraceNote("reschedules '" + getName() + "' now"); |
299 | else |
300 | sendTraceNote("reschedules '" + getName() + "' at " |
301 | + time); |
302 | } |
303 | } |
304 | |
305 | getModel().getExperiment().getScheduler().reSchedule(this, time); |
306 | |
307 | if (currentlySendDebugNotes()) { |
308 | sendDebugNote("reschedules on EventList<br>" |
309 | + getModel().getExperiment().getScheduler().toString()); |
310 | } |
311 | |
312 | } |
313 | |
314 | /** |
315 | * @deprecated Use reSchedule(TimeSpan dt). |
316 | * Re-schedules the Schedulable at some other point in simulation time than |
317 | * it already had been scheduled before. |
318 | * |
319 | * @param dt |
320 | * TimeSpan : The offset to the current simulation time at which |
321 | * this Schedulable is to be re-scheduled |
322 | */ |
323 | public void reSchedule(SimTime dt) { |
324 | |
325 | reSchedule(SimTime.toTimeSpan(dt)); |
326 | |
327 | } |
328 | |
329 | /** |
330 | * @deprecated Returns the point of simulation time this Schedulable is scheduled at. |
331 | * Returns null, if the entity has not been scheduled and thus can not return an |
332 | * appropriate point of simulation time. |
333 | * |
334 | * Use scheduleNext() for next TimeInstant where an event-note lists this entity. |
335 | * |
336 | * @return TimeInstant : The point of simulation time this Schedulable is |
337 | * scheduled at or <code>null</code> otherwise |
338 | */ |
339 | public TimeInstant scheduledAt() { |
340 | |
341 | return scheduledNext(); //use scheduleNext() |
342 | |
343 | } |
344 | |
345 | /** |
346 | * Returns the next point of time this entity is scheduled. |
347 | * |
348 | * @return TimeInstant : The point of simulation time the next Entity |
349 | * is schedule or <code>null</code> otherwise |
350 | */ |
351 | public TimeInstant scheduledNext() |
352 | { |
353 | if (!isScheduled()) |
354 | { |
355 | return null; // if not scheduled, there is no point of time |
356 | } |
357 | else |
358 | { |
359 | return _schedule.get(0).getTime(); |
360 | } |
361 | } |
362 | |
363 | |
364 | /** |
365 | * Adds an event-note to the Schedulable. |
366 | */ |
367 | void addEventNote(EventNote note) |
368 | { |
369 | if (!_schedule.contains(note)) { |
370 | _schedule.add(note); |
371 | java.util.Collections.sort(_schedule); |
372 | } |
373 | } |
374 | |
375 | /** |
376 | * Creates and returns a copy of this Schedulable. |
377 | * Note that subclasses have to implement the interface |
378 | * </code>java.lang.Cloneable</code> to actually use this method as |
379 | * otherwise, a </code>CloneNotSupportedException</code> will be thrown. |
380 | * |
381 | * @return Schedulable : A copy of this Schedulable. |
382 | */ |
383 | protected Schedulable clone() throws CloneNotSupportedException { |
384 | Schedulable c = (Schedulable) super.clone(); |
385 | NameCatalog nc = this.getModel().getExperiment().getNameCatalog(); |
386 | c.rename(nc.getNameWithoutSuffix(this.getName())); |
387 | c._schedule = new LinkedList<EventNote>(); |
388 | return c; |
389 | } |
390 | } |