Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

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 }