Class One2OneCallChannel
- java.lang.Object
-
- org.jcsp.lang.Guard
-
- org.jcsp.lang.AltingChannelAccept
-
- org.jcsp.lang.One2OneCallChannel
-
- All Implemented Interfaces:
java.io.Serializable
,ChannelAccept
public abstract class One2OneCallChannel extends AltingChannelAccept implements java.io.Serializable
This is the super-class for one-to-one interface-specific CALL channels.Shortcut to the Constructor and Method Summaries.
Description
Normal method invocation between objects is sometimes refered to as message-passing between a client (the invoker of the method) object and a server object (the invoked). Information flows from the client (the method name and parameter values) to the server, which reacts in some way (possibly changing state) and may return information back to the client (via the method result or, indirectly, by changing values referenced by the method parameters).This corresponds loosely with the client-server communication pattern between active processes, but where information flows over a pair of channels connecting them. However, there are major semantic differences between the two mechanisms. A server process is in charge of its own life, can act spontaenously and can refuse to accept a client call. A server object is passive, never does anything unless invoked and, then, has no choice but to obey. We must be careful, therefore, not to become confused by the same words computer scientists have chosen to mean very different things.
CALL channels risk deepening this confusion. They provide a method interface for client-server communication between active processes, yet their semantics remain those of a synchronising zero-buffered channel. However, the attraction of replacing a sequence of channel write(s) and read (matched at the other end of the channel-pair by a sequence of channel read(s) and write) with a single method invocation (and a single matching
accept
) makes this risk worthwhile.[Note: CALL channels were part of the occam3 language specification. They provide an extended rendezvous in the sense of an Ada entry, but are considerably more flexible and lightweight.]
Converting a Method Interface into a Variant CALL Channel
A CALL channel must be individually constructed to support a specific method interface. This is done by extending this class to implement that interface in the manner outlined below. The calling (i.e. client) process just sees that interface and invokes its methods. The callee (i.e. server) process just sees theaccept
method of the CALL channel and invokes that (supplying itself as argument). Both actions are voluntary and have to occur for the communication to take place.Consider the following:
interface Foo { public Bar calculate (...); public void processQuery (...); public boolean closeValve (...); }
Deriving the corresponding CALL channel is mechanical and could easilly be automated:import org.jcsp.lang.*; public class One2OneFooChannel extends One2OneCallChannel implements Foo { public static final int CALCULATE = 0; // optional public static final int PROCESS_QUERY = 1; // optional public static final int CLOSE_VALVE = 2; // optional public Bar calculate (...) { join (); // ready to make the CALL Bar result = ((Foo) server).calculate (...); selected = CALCULATE; // optional fork (); // call finished return result; } public void processQuery (...) { join (); // ready to make the CALL ((Foo) server).processQuery (...); selected = PROCESS_QUERY; // optional fork (); // call finished } public boolean closeValve (...) { join (); // ready to make the CALL boolean result = ((Foo) server).closeValve (...); selected = CLOSE_VALVE; // optional fork (); // call finished return result; } }
The above methods will be called by the client process. Thejoin
will not complete until the server invokes anaccept
on this channel. That accept will not complete until the client reaches thefork
. This gives the zero-buffered fully synchronised semantics of CSP channel communication.In between the join and the fork, the client and server processes are locked together in extended rendezvous, commonly executing the chosen method in the server environment. [Actually, it is the client that invokes the method on the server, temporarilly referenced by the
server
field from this One2OneCallChannel super-class and blocked waiting for its accept to complete.] Setting theselected
field is optional. However, its value is returned to the server by theaccept
method and can be used (as in the above) to let the server know which of its methods the client invoked.[Note: a One2OneFooChannel is only safe to use between a single client and a single server. Any-1, 1-Any and Any-Any versions may be derived from
Any2OneCallChannel
,One2AnyCallChannel
andAny2AnyCallChannel
(respectively) using exactly the same pattern as above.]Calling a CALL Channel
All the client needs to see is the method interface implemented by the CALL channel. For example:import org.jcsp.lang.*; public class A implements CSProcess { private final Foo out; public A (final Foo out) { this.out = out; } public void run () { ... Bar t = out.calculate (...); ... out.processQuery (...); ... if (! out.closeValve (...)) ...; ... } }
[Note: this means, of course, that a client is blind to the variety of CALL channel it is calling. It may be connected to its server(s) via a 1-1, Any-1, 1-Any or Any-Any link without any change in its coding.]Accepting a CALL Channel
To receive the calls forwarded by the CALL channel, the server needs to implement the same interface. To accept a call, it invokes theaccept
method of the CALL channel, passing itself (usually this) as the argument. All it needs to see, therefore, is theChannelAccept
interface implemented by the channel. For example:import org.jcsp.lang.*; class B implements CSProcess, Foo { private final ChannelAccept in; public B (final One2OneFooChannel in) { this.in = in; } ... other fields, methods etc. ... implementation of Foo methods public void run () { // controls when Foo invocations are acceptable ... in.accept (this); // don't care which method was called ... switch (in.accept (this)) { // care which method was called case One2OneFooChannel.CALCULATE: ... break; case One2OneFooChannel.PROCESS_QUERY: ... break; case One2OneFooChannel.CLOSE_VALVE: ... break; }] ... in.accept (this); // don't care which method was called ... } }
However, it is not very secure for a server process (like B) to advertise a standard method interface (like Foo). In the above example, there is the danger that someone might try to invoke one of the Foo methods directly on an instance of B (e.g. by plugging an instance of B, instead of the CALL channel, into an instance of A). That would not be a good idea!It is also semantically misleading - B's interface is through the CALL channel passed to its constructor, not through its (necessarilly public) Foo methods.
So, B should not be the public server process - we need to hide its directly invocable methods. A simple way to do this is to wrap it up in another process that simply omits the public declaration of the relevant interface:
import org.jcsp.lang.*; public class B2 implements CSProcess { // no Foo interface private final B b; public B2 (final One2OneFooChannel in) { b = new B (in); } public void run () { b.run (); } }
Notice that this wrapper imposes no run-time overhead, apart from a small start-up cost. The hidden inner process does all the work and has direct access to the CALL channel and, hence, to the client.[Note: the only difference needed in the server code to support Any-1, 1-Any and Any-Any CALL channels is in the parameter declaration that specifies the variety to be used. For complete flexibility, constructors (or setFooChannel methods) for each kind (i.e. One2OneFooChannel, Any2OneFooChannel, One2AnyFooChannel and Any2AnyFooChannel may be provided.]
ALTing on a CALL Channel
This class is a sub-class ofGuard
and, therefore, its derived CALL channels may be included in a Guard array associated with anAlternative
. Hence, the server may ALT between any mixture of CALL channels, ordinary channels,timeouts
andSkips
.However, when implementing the server, the CALL channel field needs to be declared as an
AltingChannelAccept
, rather than aChannelAccept
. So, in the above example, the first field declaration of B needs to become:private final AltingChannelAccept in;
See Any2OneCallChannel for an example of ALTing between CALL channels.[Note: a server may ALT on a Any-1 CALL channel with this same change. However, as for ordinary channels, ALTing over 1-Any or Any-Any versions is not supported.]
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 inParallel
.For example, the simple two process network:
is implemented by:One2OneFooChannel c = new One2OneFooChannel (); new Parallel ( new CSProcess[] { new A (c), new B2 (c) } ).run ();
[Note: simple network examples using Any-1, 1-Any and Any-Any CALL channels are given in their respective classes.]
Example
Please see Any2OneCallChannel for an example that includes one server, ALTing between two (Any-1) CALL channels, and lots of clients.- Author:
- P.H. Welch
- See Also:
Any2OneCallChannel
,One2AnyCallChannel
,Any2AnyCallChannel
,Alternative
, Serialized Form
-
-
Field Summary
Fields Modifier and Type Field Description 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
Constructors Constructor Description One2OneCallChannel()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description 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.
-
-
-
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 thejoin
andfork
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 thejoin
andfork
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 ofaccept
.
-
-
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 above. It will not complete until a CALL has been made. If the derived CALL channel has set theselected
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 interfaceChannelAccept
- 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 anaccept
on this channel. In turn, that accept will not complete until the client invokes afork
, 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 anaccept
for the client to have got this far in the sequence - see thejoin
. This call unblocks that accept, releasing the server and client to resume separate lives.
-
-