Source code: desmoj/Bin.java
1 package desmoj;
2
3 /**
4 * Bin is the place where producers can store their products for consumers
5 * to come and use them up.
6 * Bin is used to implement process synchronization between producers and
7 * consumers. Producers are producing products and store them using
8 * <code>store()</code> in the bin. Consumers make the Bin
9 * <code>deliver()</code> the products to use them up.
10 * If no or not enough units of a product are available for the consumers,
11 * they have to wait in a queue until new units are delivered by a
12 * producer.
13 * The first sort criteria of the queue is always highest priorities first,
14 * the second queueing discipline of the underlying queue and the capacity
15 * limit can be determined by the user (default is Fifo and unlimited
16 * capacity).
17 * Bin is derived from QueueBased, which provides all the statistical
18 * functionality for a queue.
19 * @see QueueBased
20 *
21 * @author Soenke Claassen
22 * @author based on DESMO-C from Thomas Schniewind, 1998
23 *
24 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
25 */
26
27 public class Bin extends desmoj.QueueBased
28 {
29
30 // ****** attributes ******
31
32 /**
33 * The queue, actually storing the processes waiting for products
34 */
35 private QueueList queue;
36
37 /**
38 * The initial number of products in the Bin
39 */
40 private long initial;
41
42 /**
43 * The maximum number of products in the Bin
44 */
45 private long maximum;
46
47 /**
48 * Number of products available at the moment
49 */
50 private long avail;
51
52 /**
53 * Number of producers having visited the Bin
54 */
55 private long producers;
56
57 /**
58 * Number of consumers having visited the Bin
59 */
60 private long consumers;
61
62 /**
63 * Weighted sum of available products in the Bin over the time
64 * (must be divided by the total time to get the average available units!)
65 */
66 private double wSumAvail;
67
68 /**
69 * The last time the Bin has been used
70 */
71 private SimTime lastUsage;
72
73 /**
74 * Indicates the method where something has gone wrong. Is passed as a
75 * parameter to the method <code>checkProcess()</code>.
76 */
77 private String where;
78
79 /**
80 * Counter for the SimProcesses which are refused to be enqueued, because the
81 * queue capacity is full.
82 */
83 private long refused;
84
85 /**
86 * Flag to indicate whether an entity can pass by other entities in the queue
87 * which are enqueued before that entity in the queue. Is <code>false</code> per
88 * default.
89 */
90 private boolean passBy = false;
91
92 // ****** methods ******
93
94 /**
95 * Constructor for a Bin with a number of initial units of a product in it.
96 * The queueing discipline and the capacity limit of the underlying queue
97 * can be chosen, too. Highest priority are always first in the queue.
98 * @param owner Model : The model this Bin is associated to.
99 * @param name java.lang.String : The Bin's name
100 * @param sortOrder int : determines the sort order of the underlying
101 * queue implementation. Choose a constant from <code>QueueBased</code>
102 * like <code>QueueBased.FIFO</code> or <code>QueueBased.LIFO</code> or ...
103 * @param qCapacity int : The capacity of the queue, that is how many
104 * processes can be enqueued. Zero (0) means unlimited capacity.
105 * @param initialUnits long : The units of a product the Bin starts with.
106 * Must be positive.
107 * @param showInReport boolean : Flag, if Bin should produce a report or not.
108 * @param showInTrace boolean : Flag for trace to produce trace messages.
109 */
110 public Bin (desmoj.Model owner, String name, int sortOrder, int qCapacity,
111 long initialUnits, boolean showInReport, boolean showInTrace)
112 {
113 super (owner, name, showInReport, showInTrace); // construct QueueBased
114 reset();
115
116 this.initial = initialUnits;
117 this.maximum = initialUnits;
118 this.avail = initialUnits;
119
120 if (initialUnits < 0) // there can't be less than nothing
121 {
122 sendWarning ( "Attempt to construct a Bin with a negativ number of"+
123 " units. Initial number of units set to zero!",
124 "Bin: " + getName() + " Constructor: Bin (desmoj.Model owner, " +
125 "String name, long initialUnits, boolean showInReport, " +
126 "boolean showInTrace)",
127 "A negative number of units does not make sense here.",
128 "Make sure to initialize a Bin always with a positive number of "+
129 "initialUnits.");
130
131 initial = maximum = avail = 0; // set it to 0, that makes more sense
132 }
133
134 // check if a valid sortOrder is given
135 if ( sortOrder < 0 ) {
136 sendWarning ( "The given sortOrder parameter is negative! " +
137 "A queue with Fifo sort order will be created.",
138 "Bin : "+getName()+
139 " Constructor: Bin (desmoj.Model owner, String name, "+
140 "int sortOrder, long qCapacity, long initialUnits, " +
141 "boolean showInReport, boolean showInTrace)",
142 "A valid positive integer number must be provided to " +
143 "determine the sort order of the underlying queue.",
144 "Make sure to provide a valid positive integer number "+
145 "by using the constants in the class QueueBased, like "+
146 "QueueBased.FIFO or QueueBased.LIFO.");
147 // make a Fifo queue
148 queue = new QueueListFifo(); // better than nothing
149 queue.setQueueBased(this);
150 }
151 else {
152 try {
153 // determine the queueing strategy
154 Class queueListStrategy = queueingStrategy[sortOrder];
155
156 queue = (QueueList)queueListStrategy.newInstance();
157 }
158
159 catch ( ArrayIndexOutOfBoundsException arrayExcept) {
160 // the given sortOrder is not valid
161 sendWarning ( "The given sortOrder parameter is not valid! " +
162 "A queue with Fifo sort order will be created.",
163 "Bin : "+getName()+
164 " Constructor: Bin (desmoj.Model owner, String name, "+
165 "int sortOrder, long qCapacity, long initialUnits, " +
166 "boolean showInReport, boolean showInTrace)",
167 "A valid positive integer number must be provided to " +
168 "determine the sort order of the underlying queue.",
169 "Make sure to provide a valid positive integer number "+
170 "by using the constants in the class QueueBased, like "+
171 "QueueBased.FIFO or QueueBased.LIFO.");
172 // make a Fifo queue
173 queue = new QueueListFifo(); // better than nothing
174 }
175
176 catch ( IllegalAccessException illAccExcept) {
177 // the class to be loaded can not be found
178 sendWarning ( "IllegalAccessException: The class implementing the " +
179 "sortOrder of the queue can not be found. A queue with "+
180 "Fifo sort order will be created instead.",
181 "Bin : "+getName()+
182 " Constructor: Bin (desmoj.Model owner, String name, "+
183 "int sortOrder, long qCapacity, long initialUnits, " +
184 "boolean showInReport, boolean showInTrace)",
185 "Programm error when trying to create an instance of a " +
186 "class. Maybe the zero-argument constructor of that " +
187 "class can not be found",
188 "Make sure to provide a valid positive integer number "+
189 "for the sort order by using the constants in the class "+
190 "QueueBased, like QueueBased.FIFO or QueueBased.LIFO. "+
191 "Contact one of the developers of DESMO-J!");
192 // make a Fifo queue
193 queue = new QueueListFifo(); // better than nothing
194 }
195
196 catch ( InstantiationException instExcept) {
197 // no object of the given class can be instantiated
198 sendWarning ( "InstantiationException: No object of the given class " +
199 "can be instantiated! A queue with Fifo sort order will "+
200 "be created instead.",
201 "Bin : "+getName()+
202 " Constructor: Bin (desmoj.Model owner, String name, "+
203 "int sortOrder, long qCapacity, long initialUnits, " +
204 "boolean showInReport, boolean showInTrace)",
205 "Programm error when trying to create an instance of a " +
206 "class. Maybe the the class is an interface or an " +
207 "abstract class that can not be instantiated",
208 "Make sure to provide a valid positive integer number "+
209 "for the sort order by using the constants in the class "+
210 "QueueBased, like QueueBased.FIFO or QueueBased.LIFO. "+
211 "Contact one of the developers of DESMO-J!");
212 // make a Fifo queue
213 queue = new QueueListFifo(); // better than nothing
214 }
215
216 // give the QueueList a reference to this QueueBased
217 queue.setQueueBased(this);
218 }
219
220 // set the capacity of the queue
221 queueLimit = qCapacity;
222
223 // check if it the capacity does make sense
224 if ( qCapacity < 0 )
225 {
226 sendWarning ( "The given capacity of the queue is negative! " +
227 "A queue with unlimited capacity will be created instead.",
228 "Bin : "+getName()+
229 " Constructor: Bin (desmoj.Model owner, String name, "+
230 "int sortOrder, long qCapacity, long initialUnits, " +
231 "boolean showInReport, boolean showInTrace)",
232 "A negative capacity for a queue does not make sense." ,
233 "Make sure to provide a valid positive capacity "+
234 "for the underlying queue.");
235 // set the capacity to the maximum value
236 queueLimit = Integer.MAX_VALUE;
237 }
238
239 // check if qCapacity is zero (that means unlimited capacity)
240 if ( qCapacity == 0 )
241 {
242 // set the capacity to the maximum value
243 queueLimit = Integer.MAX_VALUE;
244 }
245
246 }
247 // ****** methods ******
248
249 /**
250 * Constructor for a Bin with a number of initial units of a product in it.
251 * The underlying queue has a Fifo queueing discipline and unlimited capacity.
252 * @param owner Model : The model this Bin is associated to.
253 * @param name java.lang.String : The Bin's name
254 * @param initialUnits long : The units of a product the Bin starts with.
255 * Must be positive.
256 * @param showInReport boolean : Flag, if Bin should produce a report or not.
257 * @param showInTrace boolean : Flag for trace to produce trace messages.
258 */
259 public Bin (desmoj.Model owner, String name, long initialUnits,
260 boolean showInReport, boolean showInTrace)
261 {
262 super (owner, name, showInReport, showInTrace); // construct QueueBased
263 reset();
264
265 queue = new QueueListFifo(); // make an actual queue and give it a
266 queue.setQueueBased(this); // reference of this "QueueBased"-Bin
267
268 this.initial = initialUnits;
269 this.maximum = initialUnits;
270 this.avail = initialUnits;
271
272 if (initialUnits < 0) // there can't be less than nothing
273 {
274 sendWarning ( "Attempt to construct a Bin with a negativ number of"+
275 " units. Initial number of units set to zero!",
276 "Bin: " + getName() + " Constructor: Bin (desmoj.Model owner, " +
277 "String name, long initialUnits, boolean showInReport, " +
278 "boolean showInTrace)",
279 "A negative number of units does not make sense here.",
280 "Make sure to initialize a Bin always with a positive number of "+
281 "initialUnits.");
282
283 initial = maximum = avail = 0; // set it to 0, that makes more sense
284 }
285 }
286 /**
287 * Activates the SimProcess <code>process</code>, given as a parameter of
288 * this method, as the next process. This process should be a SimProcess
289 * waiting in the queue for some products.
290 * @param process SimProcess : The process that is to be activated as next.
291 */
292 protected void activateAsNext ( SimProcess process )
293 {
294 where = "protected void activateAsNext(SimProcess process)";
295
296 if ( process != null )
297 {
298 // if the given process is not valid just return
299 if ( ! checkProcess (process, where) )
300 { return; }
301
302 // if the process is scheduled (on the event list) already
303 if ( process.isScheduled() )
304 {
305 process.skipTraceNote(); // don't tell the user, that we ...
306 process.cancel(); // get the process from the EventList
307 }
308
309 // remember if the process is blocked at the moment
310 boolean wasBlocked = process.isBlocked();
311
312 // unblock the process to be able to activate him
313 if (wasBlocked)
314 {
315 process.setBlocked(false); // the process is not blocked anymore and
316 } // ready to become activated
317
318 // don't tell the user, that we activate the process after the current process
319 process.skipTraceNote();
320 process.activateAfter (current());
321
322 // the process status is still "blocked"
323 if (wasBlocked)
324 {
325 process.setBlocked(true);
326 }
327 } // end outer if
328 }
329 /**
330 * Activates the first process waiting in the queue. That is a
331 * process which was trying to take products, but it could not get any
332 * because there were not enough products for it or another process was
333 * first in the queue to be served. This method is called every time a
334 * producer has given new products or a consumer in the waiting queue is
335 * satisfied.
336 */
337 protected void activateFirst ()
338 {
339 where = "protected void activateFirst()";
340
341 // first is the first process in the queue (or null if none is in the queue)
342 SimProcess first = (SimProcess) queue.first();
343
344 if ( first != null )
345 {
346 // if first is not modelcompatible just return
347 if ( !checkProcess (first, where))
348 { return;}
349
350 // if first is scheduled (on the event list) already
351 if (first.isScheduled())
352 {
353 first.skipTraceNote(); // don't tell the user, that we ...
354 first.cancel(); // get the process from the Eventlist
355 }
356
357 // remember if first is blocked at the moment
358 boolean wasBlocked = first.isBlocked();
359
360 // unblock the process to be able to activate him
361 if (wasBlocked)
362 {
363 first.setBlocked(false);
364 }
365
366 // don't tell the user, that we activate first after the current process
367 first.skipTraceNote();
368 first.activateAfter (current());
369
370 // the status of first is still "blocked"
371 if (wasBlocked)
372 {
373 first.setBlocked(true);
374 }
375 } // end outer if
376 }
377 /**
378 * Returning the average number of products available in the bin
379 * over the time since the last reset of the bin.
380 * @return double : The average number of products available in the bin
381 * over the time since the last reset of the bin.
382 */
383 public double avgAvail ()
384 {
385 SimTime now = currentTime(); // what is the time?
386 // how long since the last reset
387 double diff = now.getTimeValue() - resetAt().getTimeValue();
388
389 // update the weighted sum of available units
390 double wSumAvl = wSumAvail +
391 ((double)avail * (now.getTimeValue() - lastUsage.getTimeValue()));
392
393 if (diff < epsilon().getTimeValue()) // diff is not long enough
394 {
395 sendWarning ( "A Division-by-Zero error occured in a calculation. " +
396 "The UNDEFINED Value: -1.0 is returned as result." ,
397 "Bin: " + getName() + " Method: double avgAvail ()",
398 "The Time difference is shorter than epsilon.",
399 "Make sure not to use avgAvail() right after a reset.");
400 return UNDEFINED; // see QueueBased: UNDEFINED = -1
401 }
402 // return the rounded average
403 return java.lang.Math.rint( 100000 * (wSumAvl/diff) ) / 100000;
404 }
405 /**
406 * Checks whether the entity using the bin is a valid process.
407 * @return boolean : Returns whether the SimProcess is valid or not.
408 * @param p SimProcess : Is this SimProcess a valid one?
409 * @param where String : The method having called <code>checkProcess()</code>
410 * as a String.
411 */
412 protected boolean checkProcess (SimProcess p, String where)
413 {
414 if (p == null) //if p is a null pointer instead of a process
415 {
416 sendWarning ( "A non existing process is trying to use a Bin object. " +
417 "The attempted action is ignored!",
418 "Bin: " + getName() + " Method: " + where ,
419 "The process is only a null pointer.",
420 "Make sure that only real SimProcesses are using Bins." );
421 return false;
422 }
423
424 if (!isModelCompatible( p ) ) // if p is not modelcompatible
425 {
426 sendWarning ( "The process trying to use a Bin object does not "+
427 "belong to this model. The attempted action is ignored!" ,
428 "Bin: " + getName() + " Method: " + where ,
429 "The process is not modelcompatible.",
430 "Make sure that processes are using only Bins within their model.");
431 return false;
432 }
433
434 return true;
435 }
436 /**
437 * Returns a Reporter to produce a report about this Bin.
438 * @return desmoj.report.Reporter : The Reporter for the queue inside this bin
439 */
440 public desmoj.report.Reporter createReporter()
441 {
442 return new desmoj.report.BinReporter(this);
443 }
444 /**
445 * Method for consumers to make the Bin deliver a number of n products.
446 * When there are not enough products available or another consumer is first
447 * in the queue to be served (and it is not possible to pass by), the current
448 * consumer process will be blocked and inserted in the waiting queue.
449 * @return boolean : Is <code>true</code> if the specified number of units
450 * have been delivered successfully, <code>false</code> otherwise
451 * (i.e. capacity limit of the queue is reached).
452 * @param n long : The number of products the Bin is delivering to the
453 * consumer.
454 */
455 public boolean deliver (long n)
456 {
457 where = "boolean deliver (long n)";
458
459 SimProcess currentProcess = currentSimProcess();
460
461 if (!checkProcess(currentProcess, where)) //check the current process
462 { return false; } // if it is not valid return false
463
464 if (n <= 0) // if the process is taking nothing or less
465 {
466 sendWarning ( "Attempt to take nothing or a negative number of units"+
467 " out of a Bin. The attempted action is ignored!" ,
468 "Bin: " + getName() + " Method: " + where,
469 "It does not make sense to take nothing or less out of a Bin. " +
470 "The statistic will be corrupted with negative numbers!" ,
471 "Make sure to take at least one unit out of the Bin.");
472 return false; // go to where you came from; ignore that rubbish
473 }
474
475 if ( queueLimit <= length() ) // check if capac. limit of queue is reached
476 {
477 sendDebugNote("refuses to insert "+currentProcess.getQuotedName()+
478 " in waiting queue, because the capacity limit is reached. ");
479
480 sendTraceNote("is refused to be enqueued in "+this.getQuotedName() +
481 "because the capacity limit (" + getQueueLimit() + ") of the " +
482 "queue is reached");
483
484 refused++; // count the refused ones
485
486 return false; // capacity limit is reached
487 }
488
489 // insert every process in the queue for statistic reasons
490 queue.insert (currentProcess);
491
492 // is it possible for this process to pass by?
493 if ( passBy == false )
494 {
495 if ( n > avail || // not enough products available OR
496 currentProcess != queue.first() ) // other process is first in the q
497 {
498 // tell in the trace what the process is waiting for
499 if ( traceIsOn() )
500 {
501 sendTraceNote ( "awaits " + n + " of '" + this.getName() + "'" );
502 }
503
504 // for debugging purposes
505 if ( debugIsOn() )
506 {
507 sendDebugNote( "can not deliver "+ n + " units for " +
508 currentProcess.getQuotedName() + "<br>" +
509 "because there are only "+ getAvail() + " units " +
510 "right now.");
511 }
512
513 do
514 { // the process is stuck in here
515 currentProcess.setBlocked(true); // as long as ...see while
516 currentProcess.skipTraceNote(); // don't tell the user, that we ...
517 currentProcess.passivate(); // passivate the current process
518 }
519 while ( n > avail || // not enough products available OR
520 currentProcess != queue.first() ); // other process is first
521 } // end if
522
523 } // end if (passBy = false)
524
525 else // the process can pass by other processes in the queue, passBy = true
526 {
527 if ( n > avail || // not enough products available OR
528 currentProcess != queue.first() ) // other process is first in the q
529 {
530 // if this process is not the first in the queue
531 if ( currentProcess != queue.first() )
532 {
533 // we have to make sure that no other process in front of this current
534 // process in the wait queue could be satisfied, so activate
535 // the first Process in the queue to see what he can do. He will pass
536 // the activation on to his successors until this process will be
537 // activated again to get his products. (hopefully)
538 activateFirst();
539 }
540
541 // only if not enough units are available the process has to wait
542 if ( n > avail )
543 {
544 // tell in the trace what the process is waiting for
545 if ( traceIsOn() )
546 {
547 sendTraceNote ( "awaits " + n + " of '" + this.getName() + "'" );
548 }
549
550 // for debugging purposes
551 if ( debugIsOn() )
552 {
553 sendDebugNote( "can not deliver "+ n + " units for " +
554 currentProcess.getQuotedName() + "<br>" +
555 "because there are only "+ getAvail() + " units " +
556 "right now.");
557 }
558 } // end if not enough units are available
559
560 // block and passivate the process until enough products are available
561 do
562 { // the process is stuck in here
563 currentProcess.setBlocked(true); // as long as ...see while
564 currentProcess.skipTraceNote(); // don't tell the user, that we ...
565 currentProcess.passivate(); // passivate the current process
566
567 // activate the next process in the queue to see what he can do
568 activateAsNext( (SimProcess)queue.succ(currentProcess) );
569 }
570 while ( n > avail ); // not enough products available
571 }
572 } // end else (passBy = true)
573
574 // the current process has got the products he wanted ...
575
576 // tell in the trace what the process is taking from the Bin
577 if ( traceIsOn() )
578 {
579 sendTraceNote ( "takes " + n + " from '" + this.getName() + "'" );
580 }
581
582 queue.remove (currentProcess); // get the process out of the queue
583 currentProcess.setBlocked(false); //we are not blocked (anymore), yeah!
584
585 // activate the new first process in the queue
586 activateFirst();
587
588 updateStatistics ( -n ); // statistics will be updated
589 // with a negative n for deliver(), remember?!
590 return true;
591 }
592 /**
593 * Returns the number of units available at the moment.
594 * @return long : The number of units available at the moment.
595 */
596 public long getAvail ()
597 {
598 return this.avail;
599 }
600 /**
601 * Returns the number of consumers having visited the Bin.
602 * @return long : The number of consumers having visited the bin.
603 */
604 public long getConsumers ()
605 {
606 return this.consumers;
607 }
608 /**
609 * Returns the initial number of products in the bin.
610 * @return long : The number of products the bin started with.
611 */
612 public long getInitial ()
613 {
614 return this.initial;
615 }
616 /**
617 * Returns the maximum number of products in the bin.
618 * @return long : The maximum number of products in the bin.
619 */
620 public long getMaximum ()
621 {
622 return this.maximum;
623 }
624 /**
625 * Returns whether entities can pass by other entities which are enqueued before
626 * them in the queue.
627 * @return boolean : Indicates whether entities can pass by other entities which
628 * are enqueued before them in the queue.
629 */
630 public boolean getPassBy()
631 {
632 return passBy;
633 }
634 /**
635 * Returns the number of producers having used the Bin.
636 * @return long : The number of producers having put products in the bin.
637 */
638 public long getProducers ()
639 {
640 return this.producers;
641 }
642 /**
643 * Returns the implemented queueing discipline of the underlying queue
644 * as a String, so it can be displayed in the report.
645 * @return String : The String indicating the queueing discipline.
646 */
647 public String getQueueStrategy() {
648
649 return queue.getAbbreviation(); // that's it
650
651 }
652 /**
653 * Returns the number of entities refused to be enqueued in the queue,
654 * because the capacity limit is reached.
655 * @return long : The number of entities refused to be enqueued in the queue.
656 */
657 public long getRefused() {
658
659 return refused; // that's it
660 }
661 /**
662 * To reset the statistics of this bin. The number of available
663 * products at this moment and the processes waiting in the queue are not
664 * changed. But all statistic counters are reset.
665 * The <code>QueueBased</code> is also reset.
666 */
667 public void reset ()
668 {
669 super.reset(); // reset the QueueBased also
670
671 maximum = avail;
672 producers = 0;
673 consumers = 0;
674 wSumAvail = 0.0;
675 lastUsage = currentTime();
676 refused = 0;
677 }
678 /**
679 * Sets the flag passBy to a new value. PassBy is indicating whether entities can
680 * pass by other entities which are enqueued before them in the queue.
681 * @param newPassBy boolean : The new value of passBy. Set it to <code>true</code>
682 * if you want entities to pass by other entities which are enqueued before them
683 * in the queue. Set it to <code>false</code> if you don't want entities to
684 * overtake other entities in the queue.
685 */
686 public void setPassBy(boolean newPassBy)
687 {
688 this.passBy = newPassBy; // that's all!
689 }
690 /**
691 * Method for producers to put a number of n new products in the Bin.
692 * When producers <code>store()</code> new products n is positive.
693 * Producers can always store products into the Bin and will never be inserted
694 * in a queue and blocked, because the Bin has no capacity limit..
695 * @param n long : The number of products put into the Bin.
696 */
697 public void store (long n)
698 {
699 where = "void store (long n)";
700
701 SimProcess currentProcess = currentSimProcess();
702
703 if ( !checkProcess(currentProcess, where) ) // if the current process
704 { return; } // is not valid: just return
705
706 if ( n <= 0) // trying to store nothing or less, don't fool me!
707 {
708 sendWarning ( "Attempt to store nothing or a negative number of units"+
709 " in a Bin. The attempted action is ignored!" ,
710 "Bin: " + getName() + " Method: void store (long n)",
711 "It does not make sense to put nothing or less into a Bin. " +
712 "The statistic will be corrupted with negative numbers!",
713 "Make sure to store at least one unit in the Bin." );
714 return; // ignore it and just return
715 }
716
717 if ( traceIsOn() )
718 {
719 sendTraceNote ( "stores " + n + " to ' " + getName() + " '" );
720 } // tell in the trace what the process is giving into the Bin
721
722 updateStatistics ( n );
723
724 // see if someone is in the queue waiting for products
725 activateFirst();
726 }
727 /**
728 * Updates the statistics for producers and consumers.
729 * @param n long : Is positive when producers <code>store()</code> new
730 * products in the bin and negative when the Bin <code>deliver()</code>'s
731 * products to the consumer process.
732 */
733 protected void updateStatistics ( long n)
734 {
735 SimTime now = currentTime();
736 wSumAvail = wSumAvail +
737 ((double)avail * (now.getTimeValue() - lastUsage.getTimeValue()));
738 lastUsage = now;
739 avail += n; // n can be positive or negative
740
741 if (n > 0) // it is a real producer
742 {
743 producers++;
744 if (avail > maximum)
745 { maximum = avail; }
746 }
747 else // it is a consumer
748 { consumers++; }
749 }
750 }