1 | package desmoj.core.simulator; |
2 | |
3 | import java.util.Iterator; |
4 | |
5 | /** |
6 | * Queue provides models with a ready-to-use modelling element to enqueue |
7 | * entities in. The sort order of the queue is determined first |
8 | * by the priorities of the enqueued entities and second by the given sort |
9 | * order. The default sort order is FIFO (first in, first out) but others like |
10 | * LIFO (last in, first out) can be chosen, too. See the constants in class |
11 | * <code>QueueBased</code> and the derived classes from <code>QueueList</code>. |
12 | * The capacity of the Queue, that is the maximum number of entities enqueued, |
13 | * can be chosen, too. |
14 | * <p> |
15 | * For queueing <code>SimProcess</code>es the usage of class |
16 | * <code>ProcessQueue</code> is recommended. |
17 | * |
18 | * |
19 | * @see QueueBased |
20 | * @see QueueList |
21 | * @see QueueListFifo |
22 | * @see QueueListLifo |
23 | * @see ProcessQueue |
24 | * |
25 | * @version DESMO-J, Ver. 2.3.3 copyright (c) 2011 |
26 | * @author Tim Lechler |
27 | * @author modified by Soenke Claassen |
28 | * |
29 | * Licensed under the Apache License, Version 2.0 (the "License"); |
30 | * you may not use this file except in compliance with the License. You |
31 | * may obtain a copy of the License at |
32 | * http://www.apache.org/licenses/LICENSE-2.0 |
33 | * |
34 | * Unless required by applicable law or agreed to in writing, software |
35 | * distributed under the License is distributed on an "AS IS" |
36 | * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
37 | * or implied. See the License for the specific language governing |
38 | * permissions and limitations under the License. |
39 | * |
40 | */ |
41 | public class Queue<E extends Entity> extends QueueBased implements Iterable<E>{ |
42 | |
43 | /** |
44 | * The queue implementation (data structure) that actually stores the |
45 | * entities |
46 | */ |
47 | private QueueList<E> _ql; |
48 | |
49 | /** |
50 | * Counter for the entities which are refused to be enqueued, because the |
51 | * queue capacity is full. |
52 | */ |
53 | private long _refused; |
54 | |
55 | /** |
56 | * Constructs a simple priority based waiting-queue for entities, the kind |
57 | * of queue sort order and the capacity of the queue can be chosen. |
58 | * Note that since SimProcesses are derived from Entities, they can be |
59 | * queued inside this queue, too. |
60 | * <p> |
61 | * Queues can be sorted as follows:<ul> |
62 | * <li><code>QueueBased.FIFO</code> sorts entities by their priority, |
63 | * highest priority first. Entities with the same priority are |
64 | * enqueued based on "first in, first out".</li> |
65 | * <li><code>QueueBased.LIFO</code> also sorts entities by their priority, |
66 | * highest priority first. However, entities with the same priority are |
67 | * enqueued based on "last in, first out".</li> |
68 | * <li><code>QueueBased.Random</code> assigns a random position to each |
69 | * entity entering the queue, disregarding priority.</li> |
70 | * </ul> |
71 | * <p> |
72 | * The usage of the generic version <code>Queue<Type></code> where |
73 | * <code>Type</code> is derived from <code>Entity</code> is recommended |
74 | * for type safety. Using the raw type <code>Queue</code> yields a queue |
75 | * in which any <code>Entity</code> can be enqueued, typically requiring |
76 | * type casting on accessing entities enqueued. |
77 | * |
78 | * @param owner |
79 | * Model : The model this queue is associated to |
80 | * @param name |
81 | * java.lang.String : The queue's name |
82 | * @param sortOrder |
83 | * int : determines the sort order of the underlying queue |
84 | * implementation. Choose a constant from <code>QueueBased</code>: |
85 | * <code>QueueBased.FIFO</code>, <code>QueueBased.LIFO</code> or |
86 | * QueueBased.Random. |
87 | * @param qCapacity |
88 | * int : The capacity of the Queue, that is how many entities can |
89 | * be enqueued. Zero (0) means unlimited capacity. |
90 | * @param showInReport |
91 | * boolean : Flag if queue should produce a report |
92 | * @param showInTrace |
93 | * boolean : Flag for queue to produce trace messages |
94 | */ |
95 | public Queue(Model owner, String name, int sortOrder, int qCapacity, |
96 | boolean showInReport, boolean showInTrace) { |
97 | |
98 | super(owner, name, showInReport, showInTrace); // create the QBased |
99 | // object |
100 | reset(); |
101 | |
102 | // determine the queueing strategy |
103 | switch (sortOrder) { |
104 | case QueueBased.FIFO : |
105 | _ql = new QueueListFifo<E>(); break; |
106 | case QueueBased.LIFO : |
107 | _ql = new QueueListLifo<E>(); break; |
108 | case QueueBased.RANDOM : |
109 | _ql = new QueueListRandom<E>(); break; |
110 | default : |
111 | sendWarning( |
112 | "The given sortOrder parameter " + sortOrder + " is not valid! " |
113 | + "A queue with Fifo sort order will be created.", |
114 | "Queue : " |
115 | + getName() |
116 | + " Constructor: Queue(Model owner, String name, " |
117 | + "int sortOrder, long qCapacity, boolean showInReport, " |
118 | + "boolean showInTrace)", |
119 | "A valid positive integer number must be provided to " |
120 | + "determine the sort order of the queue.", |
121 | "Make sure to provide a valid positive integer number " |
122 | + "by using the constants in the class QueueBased, like " |
123 | + "QueueBased.FIFO, QueueBased.LIFO or QueueBased.RANDOM."); |
124 | _ql = new QueueListFifo<E>(); |
125 | } |
126 | |
127 | // give the QueueList a reference to this QueueBased |
128 | _ql.setQueueBased(this); |
129 | |
130 | // set the capacity of the queue |
131 | queueLimit = qCapacity; |
132 | |
133 | // check if it the capacity does make sense |
134 | if (qCapacity < 0) { |
135 | sendWarning( |
136 | "The given capacity of the queue is negative! " |
137 | + "A queue with unlimited capacity will be created instead.", |
138 | "Queue : " |
139 | + getName() |
140 | + " Constructor: Queue(Model owner, String name, " |
141 | + "int sortOrder, long qCapacity, boolean showInReport, " |
142 | + "boolean showInTrace)", |
143 | "A negative capacity for a queue does not make sense.", |
144 | "Make sure to provide a valid positive capacity " |
145 | + "for the queue."); |
146 | // set the capacity to the maximum value |
147 | queueLimit = Integer.MAX_VALUE; |
148 | } |
149 | |
150 | // check if qCapacity is zero (that means unlimited capacity) |
151 | if (qCapacity == 0) { |
152 | // set the capacity to the maximum value |
153 | queueLimit = Integer.MAX_VALUE; |
154 | } |
155 | |
156 | } |
157 | |
158 | /** |
159 | * Constructs a simple priority and FIFO based waiting-queue for entities |
160 | * with unlimited capacity of the queue. Note that since SimProcesses are |
161 | * derived from Entities, they can be queued inside this queue, too. |
162 | * <p> |
163 | * The usage of the generic version <code>Queue<Type></code> where |
164 | * <code>Type</code> is derived from <code>Entity</code> is recommended |
165 | * for type safety. Using the raw type <code>Queue</code> yields a queue |
166 | * in which any <code>Entity</code> can be enqueued, typically requiring |
167 | * type casting on accessing entities enqueued. |
168 | * |
169 | * @param owner |
170 | * Model : The model this queue is associated to |
171 | * @param name |
172 | * java.lang.String : The queue's name |
173 | * @param showInReport |
174 | * boolean : Flag if queue should produce a report |
175 | * @param showInTrace |
176 | * boolean : Flag for queue to produce trace messages |
177 | */ |
178 | public Queue(Model owner, String name, boolean showInReport, |
179 | boolean showInTrace) { |
180 | |
181 | super(owner, name, showInReport, showInTrace); // create the QBased |
182 | // object |
183 | reset(); |
184 | |
185 | // make the queue with Fifo queueing discipline and unlimited capacity |
186 | _ql = new QueueListFifo<E>(); |
187 | _ql.setQueueBased(this); |
188 | |
189 | } |
190 | |
191 | /** |
192 | * Returns a special queue reporter to produce a report about this queue. |
193 | * |
194 | * @return desmoj.core.report.Reporter : The reporter for this queue |
195 | */ |
196 | public desmoj.core.report.Reporter createReporter() { |
197 | |
198 | return new desmoj.core.report.QueueReporter(this); |
199 | |
200 | } |
201 | |
202 | /** |
203 | * Returns the first entity queued in this queue or <code>null</code> in |
204 | * case the queue is empty. |
205 | * |
206 | * @return desmoj.core.Entity : The first entity in the queue or |
207 | * <code>null</code> if the queue is empty |
208 | */ |
209 | public E first() { |
210 | |
211 | return _ql.first(); // straight design |
212 | |
213 | } |
214 | |
215 | /** |
216 | * Returns the first entity queued in this queue that applies to the given |
217 | * condition. The queue is searched from front to end and the first entity |
218 | * that returns <code>true</code> when the condition is applied to it is |
219 | * returned by this method. If no Entity apply to the given condition or the |
220 | * queue is empty, <code>null</code> will be returned. |
221 | * |
222 | * @return desmoj.core.Entity : The first entity queued in this queue applying to |
223 | * the given condition or <code>null</code> |
224 | * @param c |
225 | * Condition : The condition that the entity returned must comply |
226 | * to |
227 | */ |
228 | public E first(Condition<E> c) { |
229 | |
230 | if (c == null) { |
231 | sendWarning( |
232 | "Can not return first entity complying to condition!", |
233 | "Queue : " + getName() + " Method: void first(Condition c)", |
234 | "The Condition 'c' given as parameter is a null reference!", |
235 | "Check to always have valid references when querying Queues."); |
236 | return null; // no proper parameter |
237 | } |
238 | if (_ql.isEmpty()) |
239 | return null; // nobody home to be checked |
240 | for (E tmp = _ql.first(); tmp != null; tmp = _ql.succ(tmp)) { |
241 | if (c.check(tmp)) |
242 | return tmp; |
243 | } |
244 | // if no Entity complies to the condition just return null |
245 | return null; |
246 | |
247 | } |
248 | |
249 | /** |
250 | * Returns the <code>Entity</code> queued at the named position. |
251 | * The first position is 0, the last one size()-1. |
252 | * |
253 | * @return int :The position of the entity as an <code>int</code>. |
254 | * Returns -1 if no such position exists. |
255 | */ |
256 | public int get(E e) |
257 | { |
258 | |
259 | return _ql.get(e); |
260 | |
261 | } |
262 | |
263 | /** |
264 | * Returns the <code>Entity</code> queued at the named position. |
265 | * The first position is 0, the last one size()-1. |
266 | * |
267 | * @return desmoj.core.Entity : The <code>Entity</code> at the position of |
268 | * <code>int</code> or <code>null</code> if no such position exists. |
269 | */ |
270 | public E get(int index) |
271 | { |
272 | |
273 | return _ql.get(index); |
274 | |
275 | } |
276 | |
277 | |
278 | /** |
279 | * Returns the implemented queueing discipline of the underlying queue as a |
280 | * String, so it can be displayed in the report. |
281 | * |
282 | * @return String : The String indicating the queueing discipline. |
283 | */ |
284 | public String getQueueStrategy() { |
285 | |
286 | return _ql.getAbbreviation(); // that's it |
287 | |
288 | } |
289 | |
290 | /** |
291 | * Returns the number of entities refused to be enqueued in the queue. |
292 | * |
293 | * @return long : The number of entities refused to be enqueued in the |
294 | * queue. |
295 | */ |
296 | public long getRefused() { |
297 | |
298 | return _refused; // that's it |
299 | } |
300 | |
301 | /** |
302 | * Enters a new Entity into the queue. If the capacity of the queue is full, |
303 | * the entity will not be enqueued and <code>false</code> will be |
304 | * returned. The Entity will be stored in the queue until method |
305 | * <code>remove(Entity e)</code> is called with this specific Entity. |
306 | * Entities inside the queue are ordered according to their priority. Higher |
307 | * priorities are sorted in front of lower priorities. Entities with same |
308 | * priority are orderer according to the specified strategy. The first |
309 | * Entity inside the queue will always be the one with the highest priority. |
310 | * |
311 | * @return boolean : Is <code>true</code> if insertion was successful, |
312 | * <code>false</code> otherwise (i.e. capacity limit is reached). |
313 | * @param e |
314 | * Entity : The Entity to be added to the queue. |
315 | */ |
316 | public boolean insert(E e) { |
317 | |
318 | if (e == null) { // null returns with warning |
319 | sendWarning("Can not insert entity into Queue! Command ignored.", |
320 | "Queue : " + getName() |
321 | + " Method: boolean insert(Entity e)", |
322 | "The Entity given as parameter is a null reference!", |
323 | "Check to always have valid references when enqueueing Entities"); |
324 | return false; // no proper parameter |
325 | } |
326 | |
327 | if (!isModelCompatible(e)) { |
328 | sendWarning("Can not insert entity into Queue! Command ignored.", |
329 | "Queue : " + getName() + " Method: boolean insert" |
330 | + "(Entity e)", |
331 | "The Entity given as parameter is not compatible to " |
332 | + "the model this queue belongs to!", |
333 | "Check if your submodels are allowed to mingle with other " |
334 | + "model's components."); |
335 | return false; // not of my model type!!! |
336 | } |
337 | |
338 | if (queueLimit <= length()) { |
339 | |
340 | if (currentlySendDebugNotes()) { |
341 | sendDebugNote("refuses to insert " + e.getQuotedName() |
342 | + " because the " + "capacity limit is reached. Queue:<br>" |
343 | + _ql.toString()); |
344 | } |
345 | |
346 | if (currentlySendTraceNotes()) { |
347 | sendTraceNote("is refused to be enqueued in " |
348 | + this.getQuotedName() + "because the capacity limit (" |
349 | + getQueueLimit() + ") of this queue is " + "reached"); |
350 | } |
351 | |
352 | _refused++; // count the refused ones |
353 | |
354 | return false; // capacity limit is reached |
355 | } |
356 | |
357 | _ql.insert(e); // that's it |
358 | |
359 | if (currentlySendDebugNotes()) { |
360 | sendDebugNote("inserts " + e.getQuotedName() + " in the queue:<br>" |
361 | + _ql.toString()); |
362 | } |
363 | |
364 | // produce trace output |
365 | if (currentlySendTraceNotes()) { |
366 | if (e == currentEntity() && currentEntityAll().size() == 1) { |
367 | sendTraceNote("inserts itself into " + this.getQuotedName()); |
368 | } else { |
369 | sendTraceNote("inserts " + e.getName() + " into " |
370 | + this.getQuotedName()); |
371 | } |
372 | } |
373 | |
374 | return true; |
375 | } |
376 | |
377 | /** |
378 | * Enters a new Entity into the queue and places it after the given Entity. |
379 | * If the capacity of the queue is full, the entity will not be enqueued and |
380 | * <code>false</code> will be returned. Make sure that the entity given as |
381 | * reference is already queued inside the queue, else the entity will not be |
382 | * enqueued and <code>false</code> will be returned. The Entity will be |
383 | * stored in the queue until method <code>remove(Entity e)</code> is |
384 | * called with this specific Entity. |
385 | * |
386 | * @return boolean : Is <code>true</code> if insertion was successful, |
387 | * <code>false</code> otherwise (i.e. capacity limit is reached). |
388 | * @param e |
389 | * Entity : The Entity to be added to the queue |
390 | * @param after |
391 | * Entity : The Entity after which the entity e is to be inserted |
392 | */ |
393 | public boolean insertAfter(E e, E after) { |
394 | |
395 | if (e == null) { |
396 | sendWarning( |
397 | "Can not insert entity into Queue! Command ignored.", |
398 | "Queue : " |
399 | + getName() |
400 | + " Method: boolean insertAfter(Entity e, Entity after)", |
401 | "The Entity -e- given as parameter is a null reference!", |
402 | "Check to always have valid references when enqueueing Entities"); |
403 | return false; // no proper parameter |
404 | } |
405 | |
406 | if (after == null) { |
407 | sendWarning( |
408 | "Can not insert entity into Queue! Command ignored.", |
409 | "Queue : " |
410 | + getName() |
411 | + " Method: boolean insertAfter(Entity e, Entity after)", |
412 | "The Entity -after- given as parameter is a null reference!", |
413 | "Check to always have valid references when enqueueing Entities"); |
414 | return false; // no proper parameter |
415 | } |
416 | |
417 | if (!isModelCompatible(e)) { |
418 | sendWarning("Can not insert entity into Queue! Command ignored.", |
419 | "Queue : " + getName() + " Method: boolean insertAfter" |
420 | + "(Entity e, Entity after)", |
421 | "The Entity given as parameter is not compatible to " |
422 | + "the model this queue belongs to!", |
423 | "Check if your submodels are allowed to mingle with other " |
424 | + "model's components."); |
425 | return false; // not of my model type!!! |
426 | } |
427 | |
428 | if (queueLimit <= length()) { |
429 | |
430 | if (currentlySendDebugNotes()) { |
431 | sendDebugNote("refuses to insert " + e.getQuotedName() |
432 | + " because the " + "capacity limit is reached. Queue:<br>" |
433 | + _ql.toString()); |
434 | } |
435 | |
436 | if (currentlySendTraceNotes()) { |
437 | sendTraceNote("is refused to be enqueued in " |
438 | + this.getQuotedName() + "because the capacity limit (" |
439 | + getQueueLimit() + ") of this queue is " + "reached"); |
440 | } |
441 | |
442 | _refused++; // count the refused ones |
443 | |
444 | return false; // capacity limit is reached |
445 | } |
446 | |
447 | boolean successful = _ql.insertAfter(e, after); // that's the point |
448 | |
449 | if (currentlySendDebugNotes()) { |
450 | sendDebugNote("inserts " + e.getQuotedName() + " after " |
451 | + after.getQuotedName() + "<br>" + _ql.toString()); |
452 | } |
453 | |
454 | // produce trace output |
455 | if (currentlySendTraceNotes()) { |
456 | if (e == currentEntity() && currentEntityAll().size() == 1) { |
457 | sendTraceNote("inserts itself into " + this.getQuotedName() |
458 | + " after " + after.getName()); |
459 | } else { |
460 | sendTraceNote("inserts " + e.getName() + " into " |
461 | + this.getQuotedName() + " after " + after.getName()); |
462 | } |
463 | } |
464 | |
465 | return successful; |
466 | |
467 | } |
468 | |
469 | /** |
470 | * Enters a new Entity into the queue and places it in front of the given |
471 | * Entity. If the capacity of the queue is full, the entity will not be |
472 | * enqueued and <code>false</code> will be returned. Make sure that the |
473 | * Entity given as reference is already queued inside the queue, else the |
474 | * Entity will not be queued and <code>false</code> will be returned. The |
475 | * Entity will be stored in the queue until method |
476 | * <code>remove(Entity e)</code> is called with this specific Entity. |
477 | * |
478 | * @return boolean : Is <code>true</code> if insertion was successful, |
479 | * <code>false</code> otherwise (i.e. capacity limit is reached). |
480 | * @param e |
481 | * Entity : The Entity to be added to the queue |
482 | * @param before |
483 | * Entity : The Entity before which the entity e is to be |
484 | * inserted |
485 | */ |
486 | public boolean insertBefore(E e, E before) { |
487 | |
488 | if (e == null) { |
489 | sendWarning("Can not insert entity into Queue! Command ignored.", |
490 | "Queue : " + getName() |
491 | + " Method: boolean insertBefore(Entity e, " |
492 | + "Entity before)", |
493 | "The Entity -e- given as parameter is a null reference!", |
494 | "Check to always have valid references when enqueueing Entities"); |
495 | return false; // no proper parameter |
496 | } |
497 | if (before == null) { |
498 | sendWarning( |
499 | "Can not insert entity into Queue! Command ignored.", |
500 | "Queue : " + getName() |
501 | + " Method: boolean insertBefore(Entity e, " |
502 | + "Entity before)", |
503 | "The Entity -before- given as parameter is a null reference!", |
504 | "Check to always have valid references when enqueueing Entities"); |
505 | return false; // no proper parameter |
506 | } |
507 | |
508 | if (!isModelCompatible(e)) { |
509 | sendWarning("Can not insert entity into Queue! Command ignored.", |
510 | "Queue : " + getName() + " Method: boolean insertBefore" |
511 | + "(Entity e, Entity before)", |
512 | "The Entity given as parameter is not compatible to " |
513 | + "the model this queue belongs to!", |
514 | "Check if your submodels are allowed to mingle with other " |
515 | + "model's components."); |
516 | return false; // not of my model type!!! |
517 | } |
518 | |
519 | if (queueLimit <= length()) { |
520 | |
521 | if (currentlySendDebugNotes()) { |
522 | sendDebugNote("refuses to insert " + e.getQuotedName() |
523 | + " because the " + "capacity limit is reached. Queue:<br>" |
524 | + _ql.toString()); |
525 | } |
526 | |
527 | if (currentlySendTraceNotes()) { |
528 | sendTraceNote("is refused to be enqueued in " |
529 | + this.getQuotedName() + "because the capacity limit (" |
530 | + getQueueLimit() + ") of this queue is " + "reached"); |
531 | } |
532 | |
533 | _refused++; // count the refused ones |
534 | |
535 | return false; // capacity limit is reached |
536 | } |
537 | |
538 | boolean successful = _ql.insertBefore(e, before); // that's the point |
539 | |
540 | if (currentlySendDebugNotes()) { |
541 | sendDebugNote("inserts " + e.getQuotedName() + " before " |
542 | + before.getQuotedName() + "<br>" + _ql.toString()); |
543 | } |
544 | |
545 | // produce trace output |
546 | if (currentlySendTraceNotes()) { |
547 | if (e == currentEntity() && currentEntityAll().size() == 1) { |
548 | sendTraceNote("inserts itself into " + this.getQuotedName() |
549 | + " before " + before.getName()); |
550 | } else { |
551 | sendTraceNote("inserts " + e.getName() + " into " |
552 | + this.getQuotedName() + " before " + before.getName()); |
553 | } |
554 | } |
555 | |
556 | return successful; |
557 | |
558 | } |
559 | |
560 | /** |
561 | * Returns a boolean value indicating if the queue is empty or if any number |
562 | * of entities is currently enqueued in it. |
563 | * |
564 | * @return boolean : Is <code>true</code> if the Queue is empty, |
565 | * <code>false</code> otherwise |
566 | */ |
567 | public boolean isEmpty() { |
568 | |
569 | return _ql.isEmpty(); |
570 | |
571 | } |
572 | |
573 | /** |
574 | * Returns the last Entity queued in this queue or <code>null</code> in |
575 | * case the queue is empty. |
576 | * |
577 | * @return Entity : The last Entity in the queue or <code>null</code> |
578 | * if the queue is empty |
579 | */ |
580 | public E last() { |
581 | |
582 | return _ql.last(); // straight design again |
583 | |
584 | } |
585 | |
586 | /** |
587 | * Returns the last Entity queued in this queue that applies to the given |
588 | * condition. The queue is searched from end to front and the first entity |
589 | * that returns <code>true</code> when the condition is applied to it is |
590 | * returned. If no Entity applies to the given condition or the queue is |
591 | * empty, <code>null</code> will be returned. |
592 | * |
593 | * @return Entity : The last Entity queued in this queue applying to |
594 | * the given condition or <code>null</code> |
595 | * @param c |
596 | * Condition : The condition that the entity returned must comply |
597 | * to |
598 | */ |
599 | public E last(Condition<Entity> c) { |
600 | |
601 | if (c == null) { |
602 | sendWarning( |
603 | "Can not insert entity!", |
604 | "Queue : " + getName() |
605 | + " Method: Entity last(Condition c)", |
606 | "The Condition -c- given as parameter is a null reference!", |
607 | "Check to always have valid references when querying Queues."); |
608 | return null; // no proper parameter |
609 | } |
610 | |
611 | if (_ql.isEmpty()) |
612 | return null; // nobody home to be checked |
613 | for (E tmp = _ql.last(); tmp != null; tmp = _ql.pred(tmp)) { |
614 | if (c.check(tmp)) |
615 | return tmp; |
616 | } |
617 | |
618 | // if no Entity complies to the condition just return null |
619 | return null; |
620 | |
621 | } |
622 | |
623 | /** |
624 | * Returns the entity enqueued directly before the given Entity in the |
625 | * queue. If the given Entity is not contained in this queue or is at the |
626 | * first position thus having no possible predecessor, <code>null</code> |
627 | * is returned. |
628 | * |
629 | * @return Entity : The Entity directly before the given Entity in |
630 | * the queue or <code>null</code>. |
631 | * @param e |
632 | * Entity : An Entity in the queue |
633 | */ |
634 | public E pred(E e) { |
635 | |
636 | if (e == null) { |
637 | sendWarning("Can not find predecessor of Entity in Queue!", |
638 | "Queue : " + getName() + " Method: Entity pred(Entity e)", |
639 | "The Entity -e- given as parameter is a null reference!", |
640 | "Check to always have valid references when querying for Entities"); |
641 | return null; // no proper parameter |
642 | } |
643 | |
644 | return _ql.pred(e); |
645 | |
646 | } |
647 | |
648 | /** |
649 | * Returns the entity enqueued before the given Entity in the queue that |
650 | * also complies to the condition given. If the given Entity is not |
651 | * contained in this queue or is at the first position thus having no |
652 | * possible predecessor, <code>null</code> is returned. If no other Entity |
653 | * before the given one complies to the condition, <code>null</code> is |
654 | * returned, too. |
655 | * |
656 | * @return Entity : The Entity before the given Entity in the queue |
657 | * complying to the condition or <code>null</code>. |
658 | * @param e |
659 | * Entity : An Entity in the queue |
660 | * @param c |
661 | * Condition : The condition that the preceeding Entity has to |
662 | * comply to |
663 | */ |
664 | public E pred(E e, Condition<E> c) { |
665 | |
666 | if (e == null) { |
667 | sendWarning("Can not find predecessor of Entity in Queue!", |
668 | "Queue : " + getName() |
669 | + " Method: Entity pred(Entity e, Condition c)", |
670 | "The Entity 'e' given as parameter is a null reference!", |
671 | "Check to always have valid references when querying " |
672 | + "for Entities"); |
673 | return null; // no proper parameter |
674 | } |
675 | |
676 | if (c == null) { |
677 | sendWarning( |
678 | "Can not return previous Entity complying to condition!", |
679 | "Queue : " + getName() |
680 | + " Method: Entity pred(Entity e, Condition c)", |
681 | "The Condition 'c' given as parameter is a null reference!", |
682 | "Check to always have valid references when querying Queues."); |
683 | return null; // no proper parameter |
684 | } |
685 | |
686 | for (E tmp = pred(e); tmp != null; tmp = pred(tmp)) { |
687 | if (c.check(tmp)) |
688 | return tmp; |
689 | } |
690 | |
691 | return null; // obviously not found here, empty or doesn't comply |
692 | } |
693 | |
694 | /** |
695 | * Removes the given Entity from the Queue. If the given Entity is not in |
696 | * the Queue, a warning will be issued but nothing else will be changed. |
697 | * |
698 | * @param e |
699 | * Entity : The Entity to be removed |
700 | */ |
701 | public void remove(E e) { |
702 | |
703 | if (e == null) { |
704 | sendWarning("Can not remove Entity from Queue!", "Queue : " |
705 | + getName() + " Method: void remove(Entity e)", |
706 | "The Entity 'e' given as parameter is a null reference!", |
707 | "Check to always have valid references when removing " |
708 | + "Entities"); |
709 | return; // no proper parameter |
710 | } |
711 | if (!_ql.remove(e)) { // watch out, already removed as a side |
712 | // effect!!! |
713 | sendWarning("Can not remove Entity from Queue!", "Queue : " |
714 | + getName() + " Method: void remove(Entity e)", |
715 | "The Entity 'e' given as parameter is not enqueued in this " |
716 | + "queue!", |
717 | "Make sure the entity is inside the queue you want it to " |
718 | + "be removed."); |
719 | return; // not enqueued here |
720 | } |
721 | |
722 | if (currentlySendDebugNotes()) { |
723 | sendDebugNote("remove " + e.getQuotedName() + "<br>" |
724 | + _ql.toString()); |
725 | } |
726 | |
727 | // produce trace output |
728 | if (currentlySendTraceNotes()) { |
729 | if (e == currentEntity() && currentEntityAll().size() == 1) { |
730 | sendTraceNote("removes itself from " + this.getQuotedName()); |
731 | } else { |
732 | sendTraceNote("removes " + e.getQuotedName() + " from " |
733 | + this.getQuotedName()); |
734 | } |
735 | } |
736 | |
737 | } |
738 | |
739 | /** |
740 | * Removes the entity queued at the given position. |
741 | * The first position is 0, the last one length()-1. |
742 | * |
743 | * @return : The method returns <code>true</code> if an <code>Entity</code> |
744 | * exists at the given position or <code>false></code> if otherwise. |
745 | */ |
746 | public boolean remove(int index) |
747 | { |
748 | if (index < 0 || index >= this.length()) return false; |
749 | |
750 | E e = get(index); |
751 | if (e == null) { |
752 | return false; |
753 | } else { |
754 | remove(e); |
755 | return true; |
756 | } |
757 | } |
758 | |
759 | /** |
760 | * Resets all statistical counters to their default values. The mininum and |
761 | * maximum length of the queue are set to the current number of queued |
762 | * objects. The counter for the entities refused to be enqueued will be |
763 | * reset. |
764 | */ |
765 | public void reset() { |
766 | |
767 | super.reset(); // reset of QueueBased |
768 | |
769 | _refused = 0; |
770 | |
771 | } |
772 | |
773 | /** |
774 | * Sets the sort order of this Queue to a new value and makes this |
775 | * Queue use another <code>QueueList</code> with the specified |
776 | * queueing discipline. Please choose a constant from |
777 | * <code>QueueBased</code> (<code>QueueBased.FIFO</code>, |
778 | * <code>QueueBased.FIFO</code> or <code>QueueBased.Random</code>) |
779 | * The sort order of a Queue can only be changed if the queue is empty. |
780 | * |
781 | * @param sortOrder |
782 | * int : determines the sort order of the underlying |
783 | * <code>QueueList</code> implementation (<code>QueueBased.FIFO</code>, |
784 | * <code>QueueBased.FIFO</code> or <code>QueueBased.Random</code>) |
785 | */ |
786 | public void setQueueStrategy(int sortOrder) { |
787 | |
788 | // check if the queue is empty |
789 | if (!isEmpty()) { |
790 | sendWarning( |
791 | "The Queue for which the queueing discipline should be " |
792 | + "changed is not empty. The queueing discipline will remain unchanged!", |
793 | getClass().getName() + ": " + getQuotedName() |
794 | + ", Method: " |
795 | + "void setQueueStrategy(int sortOrder)", |
796 | "The Queue already contains some entities ordered according a " |
797 | + "certain order.", |
798 | "Make sure to change the sort order only for an empty ProcessQueue."); |
799 | |
800 | return; // ignore that rubbish and just return |
801 | } |
802 | |
803 | // determine the queueing strategy |
804 | switch (sortOrder) { |
805 | case QueueBased.FIFO : |
806 | _ql = new QueueListFifo<E>(); break; |
807 | case QueueBased.LIFO : |
808 | _ql = new QueueListLifo<E>(); break; |
809 | case QueueBased.RANDOM : |
810 | _ql = new QueueListRandom<E>(); break; |
811 | default : |
812 | sendWarning( |
813 | "The given sortOrder parameter is negative or too big! " |
814 | + "The sort order of the ProcessQueue will remain unchanged!", |
815 | getClass().getName() + ": " + getQuotedName() |
816 | + ", Method: " |
817 | + "void setQueueStrategy(int sortOrder)", |
818 | "A valid positive integer number must be provided to " |
819 | + "determine the sort order of the queue.", |
820 | "Make sure to provide a valid positive integer number " |
821 | + "by using the constants in the class QueueBased, like " |
822 | + "QueueBased.FIFO, QueueBased.LIFO or QueueBased.RANDOM."); |
823 | return; |
824 | } |
825 | _ql.setQueueBased(this); |
826 | } |
827 | |
828 | /** |
829 | * Returns the entity enqueued directly after the given Entity in the queue. |
830 | * If the given Entity is not contained in this queue or is at the last |
831 | * position thus having no possible successor, <code>null</code> is |
832 | * returned. |
833 | * |
834 | * @return Entity : The Entity directly after the given Entity in the |
835 | * queue or <code>null</code>. |
836 | * @param e |
837 | * Entity : An Entity in the queue |
838 | */ |
839 | public E succ(E e) { |
840 | |
841 | if (e == null) { |
842 | sendWarning("Can not find successor of Entity in Queue!", |
843 | "Queue : " + getName() + " Method: Entity succ(Entity e)", |
844 | "The Entity 'e' given as parameter is a null reference!", |
845 | "Check to always have valid references when querying for Entities"); |
846 | return null; // no proper parameter |
847 | } |
848 | |
849 | return _ql.succ(e); |
850 | |
851 | } |
852 | |
853 | /** |
854 | * Returns the entity enqueued after the given Entity in the queue that also |
855 | * complies to the condition given. If the given Entity is not contained in |
856 | * this queue or is at the last position thus having no possible successor, |
857 | * <code>null</code> is returned. If no other Entity after the given one |
858 | * complies to the condition, <code>null</code> is returned, too. |
859 | * |
860 | * @return Entity : The Entity after the given Entity in the queue |
861 | * complying to the condition or <code>null</code>. |
862 | * @param e |
863 | * Entity : An Entity in the queue |
864 | * @param c |
865 | * Condition : The condition that the succeeding Entity has to |
866 | * comply to |
867 | */ |
868 | public E succ(E e, Condition<E> c) { |
869 | |
870 | if (e == null) { |
871 | sendWarning("Can not find predecessor of Entity in Queue!", |
872 | "Queue : " + getName() |
873 | + " Method: Entity succ(Entity e, Condition c)", |
874 | "The Entity 'e' given as parameter is a null reference!", |
875 | "Check to always have valid references when querying for Entities"); |
876 | return null; // no proper parameter |
877 | } |
878 | |
879 | if (c == null) { |
880 | sendWarning( |
881 | "Can not return previous Entity complying to condition!", |
882 | "Queue : " + getName() |
883 | + " Method: Entity succ(Entity e, Condition c)", |
884 | "The Condition 'c' given as parameter is a null reference!", |
885 | "Check to always have valid references when querying Queues."); |
886 | return null; // no proper parameter |
887 | } |
888 | |
889 | for (E tmp = succ(e); tmp != null; tmp = succ(tmp)) { |
890 | if (c.check(tmp)) |
891 | return tmp; |
892 | } |
893 | |
894 | return null; // obviously not found here, empty or doesn't comply |
895 | |
896 | } |
897 | |
898 | /** |
899 | * Returns the underlying queue implementation, providing access to the |
900 | * QueueList implementation, e.g. to add PropertyChangeListeners. |
901 | * |
902 | * @return desmoj.core.simulator.QueueList : The underlying queue implementation of this |
903 | * Queue. |
904 | */ |
905 | public QueueList<E> getQueueList() { |
906 | |
907 | return _ql; // that's all |
908 | } |
909 | |
910 | |
911 | /** |
912 | * Sets the seed of the underlying queue list's pseudo random number generator. |
913 | * Useful for queues with random sort order only; to other queues, calling |
914 | * this method has no effect, resulting in a warning. |
915 | * |
916 | * @param newSeed |
917 | * long : new seed of the underlying queue list's pseudo |
918 | * random number generator |
919 | */ |
920 | public void setSeed(long newSeed) { |
921 | if (_ql instanceof QueueListRandom<?>) { |
922 | ((QueueListRandom<?>) _ql).setSeed(newSeed); |
923 | } else { |
924 | sendWarning( |
925 | "Cannot set seed of queue!", |
926 | "Queue : " + getName() |
927 | + " Method: setSeed(long newSeed)", |
928 | "The queue does not randomize entries.", |
929 | "Make sure to call setSeed(long newSeed) " + |
930 | "on queues with <tt>sortOrder == QueueBased.RANDOM</tt> only."); |
931 | } |
932 | } |
933 | |
934 | |
935 | /** |
936 | * Returns an iterator over the entities enqueued. |
937 | * |
938 | * @return java.lang.Iterator<E> : An iterator over the entities enqueued. |
939 | */ |
940 | public Iterator<E> iterator() { |
941 | return new QueueIterator(this); |
942 | } |
943 | |
944 | /** |
945 | * Private queue iterator, e.g. required for processing all queue elements in a |
946 | * for-each-loop. |
947 | */ |
948 | private class QueueIterator implements Iterator<E> { |
949 | |
950 | Queue<E> clientQ; |
951 | E next, lastReturned; |
952 | |
953 | public QueueIterator(Queue<E> clientQ) { |
954 | this.clientQ = clientQ; |
955 | next = clientQ.first(); |
956 | lastReturned = null; |
957 | } |
958 | public boolean hasNext() { |
959 | return next != null; |
960 | } |
961 | public E next() { |
962 | lastReturned = next; |
963 | next = clientQ.succ(next); |
964 | return lastReturned; |
965 | } |
966 | public void remove() { |
967 | clientQ.remove(lastReturned); |
968 | } |
969 | } |
970 | } |