CSP for Java
(JCSP) 1.1-rc4

org.jcsp.lang
Class Any2AnyCallChannel

java.lang.Object
  extended by org.jcsp.lang.Any2AnyCallChannel
All Implemented Interfaces:
Serializable, ChannelAccept

public abstract class Any2AnyCallChannel
extends Object
implements ChannelAccept, Serializable

This is the super-class for any-to-any interface-specific CALL channels, safe for use by many clients and many servers.

Shortcut to the Constructor and Method Summaries.

Description

Please see One2OneCallChannel for general information about CALL channels. Documented here is information specific to this any-any version.

Converting a Method Interface into a Variant CALL Channel

Constructing a any-any CALL channel for a specific interface follows exactly the same pattern as in the 1-1 case. Of course, it must extend Any2AnyCallChannel rather than One2OneCallChannel.

For example, using the same Foo interface as before, we derive:

 import org.jcsp.lang.*;
 
 public class Any2AnyFooChannel extends Any2AnyCallChannel implements Foo {
 
   ...  same body as One2OneFooChannel
 
 }
 

Calling a CALL Channel

All the client needs to see is the method interface implemented by the CALL channel. So far as the client is concerned, therefore, there is no difference between any of the varieties of CALL channel - it just makes the call.

Accepting a CALL Channel

The mechanics of accepting a CALL channel are the same for all varieties. However, the server should declare which kind (or kinds) it allows to be attached:
 import org.jcsp.lang.*;
 
 class B implements CSProcess, Foo {
 
   private final ChannelAccept in;
 
   public B (final One2OneFooChannel in) {         // original constructor
     this.in = in;
   }
 
   public B (final Any2AnyFooChannel in) {       // additional constructor
     this.in = in;
   }
 
   ...  rest as before
 
 }
 
When wrapping the above to hide its raw method interface, don't forget to include the extra constructor(s):
 import org.jcsp.lang.*;
 
 public class B2 implements CSProcess {            // no Foo interface
 
   private final B b;
 
   public B2 (final One2OneFooChannel in) {        // original constructor
     b = new B (in);
   }
 
   public B2 (final Any2AnyFooChannel in) {      // additional constructor
     b = new B (in);
   }
 
   public void run () {
     b.run ();
   }
 
 }
 

ALTing on a CALL Channel

As for ordinary channels, ALTing over 1-any or any-any versions is not supported. Hence, a server can only choose to accept or not to accept a Any2AnyFooChannel - it cannot back off because of some other event.

Building a CALL Channel Network

Network building with CALL channels is the same as building with ordinary channels. First construct the channels and, then, construct the processes - plugging in the channels as required and running them in Parallel.

For example, the network consisting of several clients and several servers:

where A is unchanged from its definition in One2OneCallChannel, is implemented by:
     Any2AnyFooChannel c = new Any2AnyFooChannel ();
 
     final A[] aClients = new A[n_aClients];
     for (int i = 0; i < aClients.length; i++) {
       aClients[i] = new A (c);
     }
 
     final B2[] bServers = new B2[n_bClients];
     for (int i = 0; i < bServers.length; i++) {
       bServers[i] = new B2 (c);
     }
 
     new Parallel (
       new CSProcess[] {
         new Parallel (aClients),
         new Parallel (bServers)
       }
     ).run ();
 
The clients compete with each other to find a server and the servers compete with each other to find a client. A client must not care which server it gets and vice-versa. The any-any CALL channel strictly serialises client-server transactions - only one at a time can actually take place.

It is a good idea, therefore, to restrict the duration of the CALL to as short a period as possible, so that other clients and servers are not unnecessarilly delayed. For instance, the any-any CALL can be used just to enable a client and server find one another. During the CALL, the client could give the server a private direct line (e.g. a 1-1 CALL channel) on which it promises to call back after hanging up on the shared one. The server could reply with special information (such as how long it is prepared to wait for that call back). In this way, multiple client-server transactions could proceed concurrently. An example is given below.

Example

This further develops the CALL channel version of the Wot-no-Chickens example, introduced in Any2OneCallChannel.

The college authorities have decided to charge its philosophers for all the chickens they are consuming. Unfortunately, getting the canteen to collect money from the customers would mean that its serviceTime would have to be increased from its present zero to one second. Since the canteen can only do one thing at a time, a new form of delay would be introduced into the system. Since the philosophers only think for a maximum of three seconds in between trying to eat, having them wait around (possibly for several seconds) while their colleagues make their purchases is deemed unacceptable.

The college has decided, therefore, to make some new investments. Students are to be employed to sell the chickens from the canteen. Each student is equipped with a hot-plate on which can be (indefinitely) stored one hot chicken, straight from the canteen. The student can get a chicken from the canteen (if the canteen has some available) still with the same zero serviceTime as before - the canteen has not changed. Students that have chickens compete with each other to service any customers. Servicing a customer means collecting some money and giving change, which takes one second, as well as handing over the chicken.

Hungry philosophers compete with each other to find any student who is ready for a customer. Students and philosophers find each other through a any-any CALL channel. However, if the full transaction (which includes a delay of one second) were to take place over that shared channel, the college would be no better off! The canteen-students system would still only be dealing with one customer at a time.

Therefore, the good idea mentioned at the end of the previous section is employed to enable student-philosopher transactions to proceed in parallel. The any-any shared channel is used only for a philosopher to pass over a private direct 1-1 line to a student and to exchange names (out of politeness). The bulk of all transactions takes place in parallel over unshared lines.

Here is the fixed part of the network diagram for the new college. The 1-1 channels for private communication between a philosopher (Prof) and a student (Student) are dynamically connected, continually changing and, therefore, not shown:

For this new system, the Canteen, Chef and Clock processes are unchanged. The philosophers' behaviour has changed as described above and, so, we have chosen a new name for their class - Prof. But first, we describe the new player on the block - the Student.

The Student

Each student process is a server on its studentService channel and a client on its canteenService. As with the Canteen server, we have chosen to define the Student service interface and associated CALL channel class as inner declarations:
 import org.jcsp.lang.*;
 
 class Student implements CSProcess {
 
   public static interface Service {
     public String hello (String profId,
            Canteen.One2OneServiceChannel service);
   }
 
   public static class Any2AnyServiceChannel
    extends Any2AnyCallChannel implements Service {
     public String hello (String profId,
            Canteen.One2OneServiceChannel service) {
       join ();
       String n = ((Service) server).hello (profId, service);
       fork ();
       return n;
     }
   }
 
Note that the hello CALL offers the caller's name and private 1-1 channel. These will be saved and the student's name returned when the student accepts the CALL. Notice also that that private channel instances the 1-1 Service channel exported by the Canteen. This is not surprising since the student, who will accept the CALL on that line, will be acting on behalf of the canteen - one of many proxies set up by the college to reduce the service bottleneck caused by the newly introduced charges.

Following the same pattern as for the Canteen, we next set up the constructor and the local fields for saving its parameters:

   private final String id;
   private final ChannelAccept studentService;
   // provide service on this line
   private final Canteen.Service canteenService;
   // act as a client on this line
   private final int serviceTime;
 
   public Student (String id, Any2AnyServiceChannel studentService,
                   Canteen.Service canteenService, int serviceTime) {
     this.id = id;
     this.studentService = studentService;
     this.canteenService = canteenService;
     this.serviceTime = serviceTime;
   }
 
Now, we need to combine the exported interfaces into a single one so that the inner process can be created (anonymously) by this wrapper's run method:
   private interface inner extends CSProcess, Service, Canteen.Service {};
 
   public void run () {
 
     new inner () {
 
       private AltingChannelAccept service;
       // place holder for the private line
       private int nServed = 0;
 
       private final CSTimer tim = new CSTimer ();
 
Impementations of the required CALL interfaces (including the one for the channel privately supplied) come next:
       public String hello (String profId,
              Canteen.One2OneServiceChannel service) {
         this.service = service;
         System.out.println ("   Student " + id + " -> Prof " +
                             profId + " : hello ... ");
         return id;
       }
 
       public int takeChicken (String profId) {
         System.out.println ("   Student " + id + " -> Prof +"
                             profId + " : that'll be 1-95 please ... ");
         tim.sleep (serviceTime);          // take the money and give any change
         nServed++;
         System.out.println ("   Student " + id + " -> Prof "
                             + profId + " : thank you - have a nice day ["
                             + nServed + " served]");
         return 1;
       }
 
and the run method that conducts everything:
       public void run () {
         System.out.println ("   Student " + id + " : starting ... ");
         while (true) {
           canteenService.takeChicken (id);
           // make a client CALL on the canteen
           System.out.println ("   Student " + id +
                               " : got chicken ... ready to serve ...");
           studentService.accept (this);     // customer makes contact
           service.accept (this);            // deal with customer
         }
       }
 
Finally, don't forget to run this inner process:
     }.run ();
   }
 }
 

The Professor

Professors behave in pretty much the same way as philosophers. The only difference is that they communicate with the student proxies, rather than directly with the canteen. For this, each needs to keep a private channel up its sleeve:
 import org.jcsp.lang.*;
 
 class Prof implements CSProcess {
 
   private final String id;
   private final Student.Service studentService;
   private final int thinkTime;
   private final int eatTime;
   private final boolean greedy;
 
   public Prof (String id, Student.Service studentService,
                int thinkTime, int eatTime, boolean greedy) {
     this.id = id;
     this.studentService = studentService;
     this.thinkTime = thinkTime;
     this.eatTime = eatTime;
     this.greedy = greedy;
   }
 
   public void run () {
     final CSTimer tim = new CSTimer ();
     final Canteen.One2OneServiceChannel service =
           new Canteen.One2OneServiceChannel ();
     // This is the private channel for
     // direct communication with a student
     int nEaten = 0;
     while (true) {
       if (! greedy) {
         System.out.println ("   Prof " + id + " : thinking ...");
         tim.sleep (thinkTime);  // thinking
       }
       System.out.println ("   Prof " + id + " : gotta eat ...");
       String student = studentService.hello (id, service);
                        // find a student
       System.out.println ("   Prof " + id + " -> Student "
                            + student +
                            " : hi, can I have a chicken please?");
       int chicken = service.takeChicken (id);
                     // and pay up ...
       nEaten++;
       System.out.println ("   Prof " + id +
                           " : mmm ... that's good [" +
                           nEaten + " so far]");
       tim.sleep (eatTime);      // eating
     }
   }
 
 }
 

The New College

The new charges slow down the speed with which the professors can get their chickens (although not their eating of them). Most affected are the greedy ones who can no longer consume at a rate approaching 10 per second (whilst supplies hold out) but now have to wait a whole second simply to make a purchase. Bill, therefore, should not get quite so sick. Notice that, so long as supplies hold out and there are enough students, philosophers are not delayed by each other - their purchases will be made in parallel.

For convenience, the college network diagram is reproduced here - naming some more of the characters. The new college seems to have attracted some good students:

Here is the code:
 import org.jcsp.lang.*;
 
 class NewCollege implements CSProcess {
 
   public void run () {
 
     final String[] profId = {"Bill", "Hilary", "Gennifer",
                              "Paula", "Monica"};
     final String[] studentId = {"Occam", "Babbage",
                                 "Einstein", "Turing"};
 
     final int thinkTime = 3000;             // 3 seconds
     final int eatTime = 100;                // 100 milliseconds
 
     final int studentServiceTime = 1000;    // 1 second
 
     final int canteenServiceTime = 0;       // 0 seconds
     final int canteenSupplyTime = 3000;     // 3 seconds
     final int maxChickens = 50;
 
     final Student.Any2AnyServiceChannel studentService
       = new Student.Any2AnyServiceChannel ();
     final Canteen.Any2OneServiceChannel canteenService
       = new Canteen.Any2OneServiceChannel ();
     final Canteen.Any2OneSupplyChannel supply
       = new Canteen.Any2OneSupplyChannel ();
 
     final Student[] students = new Student[studentId.length];
     for (int i = 0; i < students.length; i++) {
       students[i] = new Student (studentId[i], studentService,
                                  canteenService, studentServiceTime);
     }
 
     final Prof[] profs = new Prof[profId.length];
     for (int i = 0; i < profs.length; i++) {
       profs[i] = new Prof (profId[i], studentService,
                            thinkTime, eatTime, i == 0);
     }
 
     new Parallel (
       new CSProcess[] {
         new Clock (),
         new Canteen (canteenService, supply,
                      canteenServiceTime, canteenSupplyTime, maxChickens),
         new Parallel (students),
         new Parallel (profs),
         new Chef ("Pierre", 4, 2000, supply),
         // chefId, batchSize, batchTime
         new Chef ("Henri", 10, 20000, supply),
         new Chef ("Sid", 100, 150000, supply)
       }
     ).run ();
 
   }
   public static void main (String argv[]) {
     new NewCollege ().run ();
   }
 }
 

Author:
P.H. Welch
See Also:
One2OneCallChannel, Any2OneCallChannel, One2AnyCallChannel, Alternative, Serialized Form

Field Summary
protected  int selected
          This may be set during the standard calling sequence to record which method was invoked by a client.
protected  CSProcess server
          This holds a reference to a server process so that a client may make the call.
 
Constructor Summary
Any2AnyCallChannel()
           
 
Method Summary
 int accept(CSProcess server)
          This is invoked by a server when it commits to accepting a CALL from a client.
protected  void fork()
          This is invoked by a client during the standard calling sequence.
protected  void join()
          This is invoked by a client during the standard calling sequence.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

server

protected CSProcess server
This holds a reference to a server process so that a client may make the call. The reference is only valid between the join and fork elements of the standard calling sequence. As shown in that sequence, it will need casting up to the relevant interface supported by the specific CALL channel derived from this class.


selected

protected int selected
This may be set during the standard calling sequence to record which method was invoked by a client. It is only safe to do this between the join and fork elements of that sequence. Either all the CALL channel methods should do this or none - in the latter case, its default value remains as zero. Its value is returned to a server as the result the server's invocation of accept.

Constructor Detail

Any2AnyCallChannel

public Any2AnyCallChannel()
Method Detail

accept

public int accept(CSProcess server)
This is invoked by a server when it commits to accepting a CALL from a client. The parameter supplied must be a reference to this server - see the example from One2OneCallChannel. It will not complete until a CALL has been made. If the derived CALL channel has set the selected field in the way defined by the standard calling sequence, the value returned by this method will indicate which method was called.

Specified by:
accept in interface ChannelAccept
Parameters:
server - the server process receiving the CALL.

join

protected void join()
This is invoked by a client during the standard calling sequence. It will not complete until a server invokes an accept on this channel. In turn, that accept will not complete until the client invokes a fork, after having made its CALL on the server.


fork

protected void fork()
This is invoked by a client during the standard calling sequence. A server must have invoked an accept for the client to have got this far in the sequence - see the join. This call unblocks that accept, releasing the server and client to resume separate lives.


CSP for Java
(JCSP) 1.1-rc4

Submit a bug or feature to jcsp-team@kent.ac.uk
Version 1.1-rc4 of the JCSP API Specification (Copyright 1997-2008 P.D.Austin and P.H.Welch - All Rights Reserved)
Java is a trademark or registered trademark of Sun Microsystems, Inc. in the US and other countries.