Source code: desmoj/TransportJunction.java
1 package desmoj;
2
3 import java.util.*;
4 /**
5 * The TransportJunction is the place where <code>Transporter</code>s pick up
6 * the goods to move them around in a manufacturing system. The goods are
7 * normally modeled as some kind of <code>SimProcess</code>es. So what happens
8 * at the TransportJunction is some kind of Rendez-vous synchronisation, where
9 * <code>Transporter</code>s meet the goods to carry them around.
10 * There is one wait queue for the masters (<code>Transporter</code>s) and one
11 * queue for the slaves (<code>SimProcess</code>es), where they have to wait for
12 * each other to cooperate. The <code>Transporter</code>s are the masters which
13 * perform the transportation.
14 * The corporate transportation process is described in the method
15 * <code>cooperation</code> in a subclass of <code>Transportation</code>.
16 * The goods (<code>SimProcess</code>es) transported as slaves keep still
17 * during the transport and will be reactivated thereafter.
18 * The main difference to a normal <code>WaitQueue</code> is, that in this case
19 * one master (<code>Transporter</code>) can cooperate with more than one slave
20 * process at a time.
21 * The number of slaves processes which will be transported togehter
22 * will be determined by the master <code>Transporter</code> process. It depends
23 * on the number of available slaves and will be between the minLoad and the
24 * capacity of the <code>Transporter</code>.
25 * Note that a <code>Transporter</code> with a large minimumLoad in front of the
26 * wait queue might block all following <code>Transporter</code>s in the queue
27 * until enough goods are available to satisfy his minimum load. Use different
28 * priorities for the different <code>Transporter</code>s to cope with this
29 * problem. Or set the passBy flag to <code>true</code> to make it possible for
30 * transporters with a low minimumLoad to pass by the other transporters. Use
31 * the methods <code>setPassBy()</code> and <code>getPassBy()</code>.
32 * The first sort criteria for the queues is always highest priorities first,
33 * the second queueing discipline of the underlying queues and the capacity
34 * limit can be determined by the user (default is Fifo and unlimited
35 * capacity).
36 * TransportJunction is derived from <code>WaitQueue</code> which in turn is
37 * derived from <code>QueueBased</code>, which provides all the statistical
38 * functionality for the queues.
39 *
40 * @see desmoj.WaitQueue
41 * @see desmoj.QueueBased
42 * @see desmoj.ProcessCoop
43 *
44 * @author: Soenke Claassen
45 *
46 * @version DESMO-J, Ver. 1.5 copyright (c) 2001 licensed under GNU GPL
47 */
48 public class TransportJunction extends WaitQueue {
49
50 /**
51 * Flag to indicate whether a transporter can pass by other transporters in the
52 * master queue which are enqueued before that transporter in the queue.
53 * Is <code>false</code> per default.
54 */
55 private boolean passBy = false;
56 /**
57 * Constructor for a TransportJunction. There are two waiting queues constructed,
58 * one internal <code>QueueList</code> for the <code>Transporter</code>s (masters)
59 * and one separate <code>ProcessQueue</code> for the slave processes.
60 * The queueing discipline and the capacity limit of the underlying queues
61 * can be chosen. Highest priority are always first in the queues.
62 * @param owner desmoj.Model : The model this TransportJunction is associated to.
63 * @param name java.lang.String : The name of this TransportJunction.
64 * @param mSortOrder int : determines the sort order of the underlying master
65 * queue implementation. Choose a constant from <code>QueueBased</code>
66 * like <code>QueueBased.FIFO</code> or <code>QueueBased.LIFO</code> or ...
67 * @param mQCapacity int : The capacity of the master queue, that is how many
68 * processes can be enqueued. Zero (0) means unlimited capacity.
69 * @param sSortOrder int : determines the sort order of the underlying slave
70 * queue implementation. Choose a constant from <code>QueueBased</code>
71 * like <code>QueueBased.FIFO</code> or <code>QueueBased.LIFO</code> or ...
72 * @param sQCapacity int : The capacity of the slave queue, that is how many
73 * processes can be enqueued. Zero (0) means unlimited capacity.
74 * @param showInReport boolean : Flag, if TransportJunction should produce a
75 * report or not.
76 * @param showInTrace boolean : Flag, if trace messages of this TransportJunction
77 * should be displayed in the trace file.
78 */
79 public TransportJunction(Model owner, String name, int mSortOrder,
80 int mQCapacity, int sSortOrder, int sQCapacity,
81 boolean showInReport, boolean showInTrace)
82 {
83 super(owner, name, mSortOrder, mQCapacity, sSortOrder, sQCapacity,
84 showInReport, showInTrace);
85 }
86 /**
87 * Constructor for a TransportJunction. There are two waiting queues constructed,
88 * one internal <code>QueueList</code> for the <code>Transporter</code>s (masters)
89 * and one separate <code>ProcessQueue</code> for the slave processes.
90 * Both queues have a FIFO sort order and no capacity limit.
91 * @param owner desmoj.Model : The model this TransportJunction is associated to.
92 * @param name java.lang.String : The TransportJunction's name
93 * @param showInReport boolean : Flag, if TransportJunction should produce a report
94 * or not.
95 * @param showInTrace boolean : Flag, if trace messages of this TransportJunction
96 * should be displayed in the trace file.
97 */
98 public TransportJunction(Model owner, String name,
99 boolean showInReport, boolean showInTrace)
100 {
101 super(owner, name, showInReport, showInTrace);
102 }
103 /**
104 * Returns an array of available slave SimProcesses which comply to a given
105 * condition at this moment.
106 * @return desmoj.SimProcess[] : The array of available slave SimProcesses
107 * which comply to the given condition. If no suitable SimProcess is available
108 * <code>null</code> will be returned.
109 * @param cond desmoj.Condition : The condition to which the SimProcesses we
110 * are looking for must comply.
111 */
112 public synchronized SimProcess[] availableSet(Condition cond) {
113
114 where = "synchronized SimProcess[] availableSet(Condition cond)";
115
116 // check the condition
117 if ( !checkCondition (cond, where) ) // if the condition is not valid
118 { return null; } // just return null
119
120 // get the first SimProcess fulfilling the given condition
121 SimProcess first = slaveQueue.first(cond);
122
123 // check if any SimProcess fulfilling the condition is available
124 if ( first == null )
125 {
126 return null; // no such slave available
127 }
128 else
129 {
130 // make a Vector to hold all the SimProcesses we find
131 Vector foundSlaves = new Vector();
132
133 // loop through all the SimProcesses fulfilling the given condition
134 for (SimProcess tmp = first; tmp != null; tmp = slaveQueue.succ(tmp, cond) )
135 {
136 foundSlaves.addElement( tmp );
137 }
138
139 // make an array to hold all the found SimProcesses
140 SimProcess[] foundProcs = new SimProcess[foundSlaves.size()];
141
142 // copy the Vector into that array
143 foundSlaves.copyInto( foundProcs );
144
145 // return that array
146 return foundProcs;
147 }
148
149 }
150 /**
151 * Returns a transporter process waiting in the transporter (master) queue
152 * complying to the given condition. If there is no such transporter waiting
153 * <code>null</code> is returned.
154 * @return Transporter : Returns the first transporter in the master queue
155 * which complies to the given condition.
156 * @param cond Condition : The Condition <code>cond</code> is describing the
157 * condition to which the trasnporter must comply to. This has to be
158 * implemented by the user in the class: <code>Condition</code> in the method:
159 * <code>check()</code>.
160 */
161 public Transporter availTransporter ( Condition cond )
162 {
163 where = "Transporter availTransporter(Condition cond)";
164
165 // the current SimProcess is assumed to be a slave looking for a master
166 SimProcess slave = currentSimProcess();
167
168 if ( !checkProcess (slave, where) ) // if slave is not valid
169 { return null; } // return null
170
171 if ( !checkCondition (cond, where) ) // if the condition is not valid
172 { return null; } // return null
173
174 if ( masterQueue.isEmpty() ) // nobody home to be checked
175 { return null; } // return null
176
177 for (Transporter master = (Transporter)masterQueue.first();
178 master != null;
179 master = (Transporter)masterQueue.succ(master) )
180 {
181 if ( cond.check(master) )
182 return master;
183 }
184
185 // if no Transporter complies to the condition just return null
186 return null;
187
188 } // end method
189 /**
190 * This method is inherited from the class <code>WaitQueue</code> and will be
191 * overwritten here to use the more suitable method
192 * <code>transport(Transportation)</code>.
193 * If the capacity limit of the master queue is reached, the process will not
194 * be enqueued and <code>false</code> returned.
195 * @return boolean : Is <code>true</code> if the process can be enqueued
196 * successfully, <code>false</code> otherwise (i.e. capacity limit of the
197 * master queue is reached).
198 * @param transportation Transportation : The transportation process transportation
199 * is describing the joint action of the processes. The transport to be carried
200 * out has to be implemented by the user in the class: <code>Transportation</code>
201 * in the method: <code>cooperation()</code>.
202 */
203 public boolean cooperate ( Transportation transportation )
204 {
205 // call the new method especially for transport purposes from this
206 // TransportJunction
207 return transport(transportation);
208 }
209 /**
210 * This method is inherited from the class <code>WaitQueue</code> and will be
211 * overwritten here to use the more suitable method
212 * <code>transport(Transportation, Condition)</code>.
213 * @return boolean : Is <code>true</code> if the process can be enqueued
214 * successfully, <code>false</code> otherwise (i.e. capacity limit of the
215 * master queue is reached).
216 * @param transportation Transportation : The transportation process transportation
217 * is describing the joint action of the processes. The transport to be carried
218 * out has to be implemented by the user in the class: <code>Transportation</code>
219 * in the method: <code>cooperation()</code>.
220 * @param cond Condition : The Condition <code>cond</code> is describing the
221 * condition to which the slave process must comply to. This has to be
222 * implemented by the user in the class: <code>Condition</code> in the method:
223 * <code>check()</code>.
224 */
225 public boolean cooperate ( Transportation transportation, Condition cond)
226 {
227 // call the new method especially for transport purposes from this
228 // TransportJunction
229 return transport(transportation, cond);
230 }
231 /**
232 * Returns a Reporter to produce a report about this TransportJunction.
233 * @return desmoj.report.Reporter : The Reporter for the queues inside this
234 * TransportJunction.
235 */
236 public desmoj.report.Reporter createReporter()
237 {
238 return new desmoj.report.TransportReporter(this);
239 // a reporter for the queue statistics
240 }
241 /**
242 * Returns whether a transporter can pass by other transporters which are
243 * enqueued before him in the queue.
244 * @return boolean : Indicates whether transporters can pass by other
245 * transporters which are enqueued before them in the queue.
246 */
247 public boolean getPassBy()
248 {
249 return passBy;
250 }
251 /**
252 * Sets the flag passBy to a new value. PassBy is indicating whether transporters
253 * can pass by other transporters which are enqueued before them in the queue.
254 * @param newPassBy boolean : The new value of passBy. Set it to <code>true</code>
255 * if you want transporters to pass by other transporters which are enqueued
256 * before them in the queue. Set it to <code>false</code> if you don't want
257 * transporters to overtake other transporters in the queue.
258 */
259 public void setPassBy(boolean newPassBy)
260 {
261 this.passBy = newPassBy; // that's all!
262 }
263 /**
264 * This method is to be called from a <code>Transporter</code> which wants to
265 * transport goods as a master. If not enough suitable goods (slave processes)
266 * are available at the moment, the transporter process will be stored in the
267 * master waiting queue, until enough suitable slaves are available.
268 * If the capacity limit of the master queue is reached, the process will not
269 * be enqueued and <code>false</code> returned.
270 * When enough suitable slaves are available their <code>prepareTransport()</code>
271 * method (in the class <code>SimProcess</code>) will be called.
272 * During the transportation process the master process is the only active one.
273 * The slave process is passive and will be reactivated after the
274 * transportation is done.
275 * @return boolean : Is <code>true</code> if the process can be enqueued
276 * successfully, <code>false</code> otherwise (i.e. capacity limit of the
277 * master queue is reached).
278 * @param transportation Transportation : The transportation process
279 * transportation is describing the joint action of the processes.
280 * The transportation to be carried out has to be implemented by the user
281 * in the class: <code>Transportation</code> in the method:
282 * <code>transport()</code>.
283 */
284 public boolean transport (Transportation transportation)
285 {
286 where = "boolean transport(Transportation transportation)";
287
288 // check the ProcessCoop
289 if ( !isModelCompatible( transportation ) )
290 {
291 sendWarning ( "The given Transportation object does not "+
292 "belong to this model. The attempted transportation is ignored!" ,
293 getClass().getName() + ": " + getQuotedName() + ", Method: " + where ,
294 "The Transportation is not modelcompatible.",
295 "Make sure that the Transportation belongs to this model.");
296
297 return false; // transport is not modelcompatible
298 }
299
300 // the current SimProcess which was calling transport() is the master
301 SimProcess currntProc = currentSimProcess();
302
303 Transporter master; // declare the variable for later use
304
305 // check if it is a Transporter
306 if ( currntProc instanceof desmoj.Transporter )
307 {
308 master = (Transporter)currntProc; // cast it to the right type
309 }
310 else
311 {
312 sendWarning ( "The SimProcess using a TransportJunction is not a " +
313 "Transporter. The attempted action is ignored!",
314 getClass().getName() + ": " + getQuotedName() + ", Method: "+
315 where ,
316 "A TransportJunction is designed to let Transporters pick " +
317 "up other SimProcesses for transportation purposes.",
318 "Make sure that only Transporters are trying to cooperate "+
319 "as masters in a TransportJunction with other SimProcesses.");
320
321 return false; // ignore that rubbish
322 }
323
324 if ( !checkProcess (master, where) ) // if the master is no valid process
325 { return false; } // just return false
326
327 // check if capacity limit of master queue is reached
328 if ( queueLimit <= length() )
329 {
330 // to have a queue capacity limit which is less than the number of
331 // transporters does not make much sense
332 sendWarning ( "The queue capacity of the TransportJunction can not hold " +
333 "all the transporters. That does not make much sense!",
334 getClass().getName() + ": " + getQuotedName() + ", Method: "+
335 where ,
336 "There are more transporters than the queue in the " +
337 "TransportJunction can hold. The remainder of the " +
338 "transporters will get lost.",
339 "Make sure to provide a queue capacity in the Transport"+
340 "Junction which can hold all of the transporters, so no "+
341 "one gets lost.");
342
343 sendDebugNote("refuses to insert "+master.getQuotedName()+
344 " in master queue, because the capacity limit is reached.");
345
346 sendTraceNote("is refused to be enqueued in "+this.getQuotedName() +
347 "'s master queue because the capacity limit (" + getQueueLimit() +
348 ") of the queue is reached");
349
350 mRefused++; // count the refused ones
351
352 return false; // capacity limit is reached
353 }
354
355 // insert the master in its waiting queue
356 masterQueue.insert(master);
357
358 // is it possible for this process to pass by?
359 if ( passBy == false )
360 {
361 // check if the master has to wait in his queue; in case of:
362 // not enough slaves available OR
363 // this master is not the first to be served
364 if ( slaveQueue.length() < master.getMinLoad() ||
365 master != (SimProcess)masterQueue.first() )
366 {
367 // tell in the trace where the master is waiting
368 if ( traceIsOn() )
369 {
370 sendTraceNote ( "waits in " + this.getQuotedName() );
371 }
372
373 if ( slaveQueue.length() > 0 ) // there are slaves waiting
374 {
375 activateFirst(); // activate the first master in the
376 } // queue to see what he can do
377
378 do
379 { // block the master process
380 master.setBlocked(true); // as long as ...(see while)
381 master.skipTraceNote(); // don't tell the user, that we
382 master.passivate(); // passivate the master process
383 }
384 while ( slaveQueue.length() < master.getMinLoad() ); // not enough slaves
385 }
386 } // end if (passBy = false)
387
388 else // the transporter can pass by other transporters in the queue
389 {
390 if ( slaveQueue.length() < master.getMinLoad() ||
391 master != (SimProcess)masterQueue.first() )
392 {
393 // if this transporter is not the first in the queue OR
394 if ( master != (SimProcess)masterQueue.first() ||
395 slaveQueue.length() > 0 ) // there are slaves waiting
396 {
397 // we have to make sure that no other transporter in front of this
398 // current process in the master queue could be satisfied, so activate
399 // the first transporter in the queue to see what he can do. He will
400 // pass the activation on to his successors until this process will be
401 // activated again to get his goods to transport. (hopefully)
402 activateFirst();
403 }
404
405 // only if not enough slaves are available the master has to wait
406 if ( slaveQueue.length() < master.getMinLoad() )
407 {
408 // tell in the trace where the master is waiting
409 if ( traceIsOn() )
410 {
411 sendTraceNote ( "waits in " + this.getQuotedName() );
412 }
413 }
414
415 // block and passivate the transporter until enough goods are available
416 do
417 { // block the master process
418 master.setBlocked(true); // as long as ...(see while)
419 master.skipTraceNote(); // don't tell the user, that we
420 master.passivate(); // passivate the master process
421
422 // activate the transporter in the master queue to see what he can do
423 activateAsNext ( (SimProcess)masterQueue.succ(master) );
424 }
425 while ( slaveQueue.length() < master.getMinLoad() ); // not enough slaves
426 }
427 } // end else (passBy = true)
428
429 // the master has found slave(s) to cooperate with...
430
431 masterQueue.remove(master); // remove this master from the wait queue
432 master.setBlocked(false); // this master is not blocked anymore
433
434 // activate the new first transporter in the master queue
435 activateFirst();
436
437 // determine how many slaves will be transported
438 int units;
439 if ( slaveQueue.length() < master.getCapacity() )
440 {
441 units = slaveQueue.length();
442 }
443 else
444 {
445 units = master.getCapacity();
446 }
447
448 // make the array of slaves which will be transported
449 SimProcess[] goods = new SimProcess[units];
450
451 // fill the array of goods to be transported
452 for ( int i=0; i < units; i++ )
453 {
454 // get the first slave from its queue
455 SimProcess slave = slaveQueue.first();
456
457 if ( !checkProcess(slave, where) ) // if the slave process is not O.K.
458 { return false; } // just return
459
460 // put the slave in the array
461 goods[i] = slave;
462
463 // prepare the slave for the transport
464 slave.prepareTransport(); // removes the slave from its queue also
465 }
466
467 // start the real transport with the array of slaves
468 transportation.transport (master, goods);
469
470 // release and activate all the slaves again
471 for ( int i=0; i < units; i++ )
472 {
473 // the transport is over, so no master is controlling the slave anymore
474 goods[i].resetMaster();
475
476 // the master is done with the transportation
477 // so get the slave activated after him
478 goods[i].activateAfter ( master );
479 }
480
481 return true;
482 }
483 /**
484 * This method is to be called from a <code>Transporter</code> who wants to
485 * transport goods which comply to a certain condition. The condition must be
486 * specified in the method <code>check()</code> in a class derived from
487 * <code>Condition</code>. If not enough suitable goods (slave processes)
488 * are available at the moment, the transporter process will be stored in the
489 * master waiting queue, until enough suitable slaves are available.
490 * If the capacity limit of the master queue is reached, the process will not
491 * be enqueued and <code>false</code> returned.
492 * When enough suitable slaves are available their <code>prepareTransport()</code>
493 * method (in the class <code>SimProcess</code>) will be called.
494 * During the transportation process the master process is the only active one.
495 * The slave process is passive and will be reactivated after the
496 * transportation is done.
497 * @return boolean : Is <code>true</code> if the process can be enqueued
498 * successfully, <code>false</code> otherwise (i.e. capacity limit of the
499 * master queue is reached).
500 * @param transportation Transportation : The transportation process is
501 * describing the joint action of the processes. The transportation to be carried
502 * out has to be implemented by the user in the class: <code>Transportation</code>
503 * in the method: <code>transport()</code>.
504 * @param cond Condition : The Condition <code>cond</code> is describing the
505 * condition to which the slave process must comply. This has to be
506 * implemented by the user in the class: <code>Condition</code> in the method:
507 * <code>check()</code>.
508 */
509 public boolean transport (Transportation transportation, Condition cond)
510 {
511 where = "boolean transport(Transportation transportation, Condition cond)";
512
513 // check the ProcessCoop
514 if ( !isModelCompatible( transportation ) )
515 {
516 sendWarning ( "The given Transportation object does not "+
517 "belong to this model. The attempted transportation is ignored!" ,
518 getClass().getName() + ": " + getQuotedName() + ", Method: " + where ,
519 "The Transportation is not modelcompatible.",
520 "Make sure that the Transportation belongs to this model.");
521
522 return false; // transport is not modelcompatible
523 }
524
525 // the current SimProcess which was calling transport() is the master
526 SimProcess currntProc = currentSimProcess();
527
528 Transporter master; // declare the variable for later use
529
530 // check if it is a Transporter
531 if ( currntProc instanceof desmoj.Transporter )
532 {
533 master = (Transporter)currntProc; // cast it to the right type
534 }
535 else
536 {
537 sendWarning ( "The SimProcess using a TransportJunction is not a " +
538 "Transporter. The attempted action is ignored!",
539 getClass().getName() + ": " + getQuotedName() + ", Method: "+
540 where ,
541 "A TransportJunction is designed to let Transporters pick " +
542 "up other SimProcesses for transportation purposes.",
543 "Make sure that only Transporters are trying to cooperate "+
544 "as masters in a TransportJunction with other SimProcesses.");
545
546 return false; // ignore that rubbish
547 }
548
549 if ( !checkProcess (master, where) ) // if the master is no valid process
550 { return false; } // just return false
551
552 if ( !checkCondition (cond, where) ) // if the condition is not valid
553 { return false; } // just return false
554
555 // check if capacity limit of master queue is reached
556 if ( queueLimit <= length() )
557 {
558 // to have a queue capacity limit which is less than the number of
559 // transporters does not make much sense
560 sendWarning ( "The queue capacity of the TransportJunction can not hold " +
561 "all the transporters. That does not make much sense!",
562 getClass().getName() + ": " + getQuotedName() + ", Method: "+
563 where ,
564 "There are more transporters than the queue in the " +
565 "TransportJunction can hold. The remainder of the " +
566 "transporters will get lost.",
567 "Make sure to provide a queue capacity in the Transport"+
568 "Junction which can hold all of the transporters, so no "+
569 "one gets lost.");
570
571 sendDebugNote("refuses to insert "+master.getQuotedName()+
572 " in master queue, because the capacity limit is reached.");
573
574 sendTraceNote("is refused to be enqueued in "+this.getQuotedName() +
575 "'s master queue because the capacity limit (" + getQueueLimit() +
576 ") of the queue is reached");
577
578 mRefused++; // count the refused ones
579
580 return false; // capacity limit is reached
581 }
582
583 // insert the master in its waiting queue
584 masterQueue.insert(master);
585
586 // get the array of suitable slaves
587 SimProcess[] foundProcs = availableSet( cond );
588
589 // is it possible for this master process to pass by?
590 if ( passBy == false )
591 {
592
593 // check if the master has to wait in his queue; in case of:
594 // no OR not enough suitable slaves available OR
595 // this master is not the first to be served
596 if ( foundProcs == null || foundProcs.length < master.getMinLoad() ||
597 master != (SimProcess)masterQueue.first() )
598 {
599 if ( traceIsOn() ) // tell in the trace where the master is waiting
600 { // and on what condition
601 sendTraceNote ( "waits in " + this.getQuotedName() + " for " +
602 cond.getQuotedName() );
603 }
604
605 // if there are slaves waiting AND this master is not the first in the queue
606 if ( slaveQueue.length() > 0 && master != (SimProcess)masterQueue.first() )
607 {
608 activateFirst(); // activate the first master in the
609 } // queue to see what he can do
610
611 do
612 { // block the master process
613 master.setBlocked(true); // as long as ...(see while)
614 master.skipTraceNote(); // don't tell the user, that we
615 master.passivate(); // passivate the master process
616
617 // check again if suitable slaves are available
618 foundProcs = availableSet( cond );
619
620 // if there are slaves waiting
621 if ( slaveQueue.length() > 0 )
622 {
623 // activate the next master in the queue to see what he can do
624 activateAsNext( (SimProcess)masterQueue.succ(master) );
625 }
626 }
627 // no OR not enough suitable slaves available
628 while ( foundProcs == null || foundProcs.length < master.getMinLoad() );
629 }
630
631 // the master has found enough suitable slave(s) to cooperate with...
632 }
633 else // the master process is allowed to pass by other processes (passBy = true)
634 {
635 // check if the master has to wait in his queue; in case of:
636 // no OR not enough suitable slaves available OR
637 // this master is not the first to be served
638 if ( foundProcs == null || foundProcs.length < master.getMinLoad() ||
639 master != (SimProcess)masterQueue.first() )
640 {
641 // if this transporter is not the first in the queue OR
642 if ( master != (SimProcess)masterQueue.first() ||
643 slaveQueue.length() > 0 ) // there are slaves waiting
644 {
645 // we have to make sure that no other transporter in front of this
646 // current process in the master queue could be satisfied, so activate
647 // the first transporter in the queue to see what he can do. He will
648 // pass the activation on to his successors until this process will be
649 // activated again to get his goods to transport. (hopefully)
650 activateFirst();
651 }
652
653 // only if not enough slaves are available the master has to wait
654 if ( slaveQueue.length() < master.getMinLoad() )
655 {
656 // tell in the trace where the master is waiting and on what condition
657 if ( traceIsOn() )
658 {
659 sendTraceNote ( "waits in " + this.getQuotedName() + " for " +
660 cond.getQuotedName() );
661 }
662 }
663
664 do
665 { // block the master process
666 master.setBlocked(true); // as long as ...(see while)
667 master.skipTraceNote(); // don't tell the user, that we
668 master.passivate(); // passivate the master process
669
670 // check again if suitable slaves are available
671 foundProcs = availableSet( cond );
672
673 // if there are slaves waiting
674 if ( slaveQueue.length() > 0 )
675 {
676 // activate the next master in the queue to see what he can do
677 activateAsNext( (SimProcess)masterQueue.succ(master) );
678 }
679 }
680 // no OR not enough suitable slaves available
681 while ( foundProcs == null || foundProcs.length < master.getMinLoad() );
682 }
683 }
684 masterQueue.remove(master); // remove this master from the wait queue
685 master.setBlocked(false); // this master is not blocked anymore
686
687 // determine how many slaves will be transported
688 int units;
689 if ( foundProcs.length < master.getCapacity() )
690 {
691 units = foundProcs.length;
692 }
693 else
694 {
695 units = master.getCapacity();
696 }
697
698 // make the array of slaves which will be transported
699 SimProcess[] goods = new SimProcess[units];
700
701 // fill the array of goods to be transported
702 for ( int i=0; i < units; i++ )
703 {
704 // if the slave process is not O.K.
705 if ( !checkProcess(foundProcs[i], where) )
706 { return false; } // just return
707
708 // copy the slaves to the array of transported goods
709 goods[i] = foundProcs[i];
710
711 // tell in the trace for which condition the master has found which
712 // slaves in which queue for which transport...
713 if ( traceIsOn() )
714 {
715 sendTraceNote ( "finds " + cond.getQuotedName() + " " +
716 foundProcs[i].getQuotedName() + " in " +
717 slaveQueue.getQuotedName() + " for " +
718 transportation.getQuotedName() );
719
720 skipTraceNote(); // skip the trace note from the following cooperate()
721 }
722
723 // prepare the slave for the transport
724 foundProcs[i].prepareTransport(); // removes the slave from its queue also
725 }
726
727 // start the real transport with the array of slaves
728 transportation.transport (master, goods);
729
730 // release and activate all the slaves again
731 for ( int i=0; i < units; i++ )
732 {
733 // the transportation is over, so no master is controlling the slave anymore
734 goods[i].resetMaster();
735
736 // the master is done with the transportation
737 // so get the slave activated after him
738 goods[i].activateAfter ( master );
739 }
740
741 return true;
742 }
743 /**
744 * This method is inherited from the class <code>WaitQueue</code> and will be
745 * overwritten here to use the more suitable method
746 * <code>waitOnTransport()</code>.
747 * @return boolean : Is <code>true</code> if the process requesting the
748 * transportation has been transported successfully to his destination,
749 * <code>false</code> otherwise (i.e. capacity limit of the slave queue
750 * is reached).
751 */
752 public boolean waitOnCoop () // wait() is a final method in java.lang.Object
753 {
754 // call the new method especially for transport purposes from this
755 // TransportJunction
756 return waitOnTransport();
757 }
758 /**
759 * This method is called from a SimProcess which wants to be transported as
760 * a slave. If no suitable master process (transporter) is available at the
761 * moment, the slave process will be stored in the slave queue, until a
762 * suitable master (transporter) is available. If the capacity limit of the
763 * slave queue is reached, the process will not be enqueued and
764 * <code>false</code> will be returned.
765 * During the transportation the master process (transporter) is the only
766 * active one. The slave process is passive and will be reactivated after the
767 * transportation is done.
768 * @return boolean : Is <code>true</code> if the process requesting the
769 * transportation has been transported successfully to his destination,
770 * <code>false</code> otherwise (i.e. capacity limit of the slave queue
771 * is reached).
772 */
773 public boolean waitOnTransport () // wait() is a final method in java.lang.Object
774 {
775 where = "boolean waitOnTransport ()";
776
777 // the current process calling the waitOnTransport()-method is the slave
778 SimProcess slave = currentSimProcess();
779
780 if (!checkProcess(slave, where)) // if the slave is not a valid process
781 { return false; } // just return false
782
783 if ( slave.getSlaveWaitQueue() != null ) // the slave process is already
784 { // waiting for a master
785 sendWarning ( "A slave process already waiting in the slave waiting " +
786 "queue: " + slave.getSlaveWaitQueue().getName() +
787 " is trying to initiate a second transportation. The attempted second " +
788 "transportation is ignored!" ,
789 getClass().getName() + ": " + getQuotedName() + ", Method: " + where ,
790 "The slave process can not wait in more than one waiting queue.",
791 "Make sure that slave processes are only transported by one master " +
792 "at a time.");
793 return false; // ignore the second transportation, just return false.
794 }
795
796 // check if capacity limit of slave queue is reached
797 if ( slaveQueue.getQueueLimit() <= slaveQueue.length() )
798 {
799 sendDebugNote("refuses to insert "+slave.getQuotedName()+
800 " in slave queue, because the capacity limit is reached.");
801
802 sendTraceNote("is refused to be enqueued in "+this.getQuotedName() +
803 "'s slave queue because the capacity limit (" +
804 slaveQueue.getQueueLimit() + ") of the queue is reached");
805
806 sRefused++; // count the refused ones
807
808 return false; // capacity limit is reached
809 }
810
811 slaveQueue.insert (slave); //insert the slave process in the wait queue
812
813 slave.setSlaveWaitQueue( slaveQueue ); // tell the SimProcess where he
814 // is waiting. Will be reset in SimProcess.cooperate(), when the
815 // master is leading the slave through the transportation.
816
817 if ( traceIsOn() ) // tell in the trace where the slave is waiting
818 {
819 sendTraceNote ( "waits in " + slaveQueue.getQuotedName() );
820 }
821
822 // are there masters already waiting?
823 if ( length() > 0 )
824 {
825 activateFirst(); // activate the first master in the queue
826 }
827
828 slave.setBlocked (true); // the slave process is blocked (in the wq)
829 slave.skipTraceNote(); // don't tell the user, that we ...
830 slave.passivate(); // passivate the slave process
831
832 return true; // transportation performed successfully
833 }
834 }