|
CSP for Java (JCSP) 1.1-rc4 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.jcsp.lang.Guard
org.jcsp.lang.AltingChannelAccept
org.jcsp.lang.One2OneCallChannel
public abstract class One2OneCallChannel
This is the super-class for one-to-one interface-specific CALL channels.
Shortcut to the Constructor and Method Summaries.
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.]
accept
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.
The join
will not complete until the server invokes
an accept
on this channel.
That accept will not complete until the client reaches
the fork
. 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 the selected
field is optional. However, its value
is returned to the server by the accept
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
and Any2AnyCallChannel
(respectively) using exactly the same pattern
as above.]
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.]
accept
method of the CALL channel, passing itself (usually
this) as the argument. All it needs to see, therefore, is
the ChannelAccept
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.]
Guard
and, therefore, its derived CALL channels
may be included in a Guard array associated with an Alternative
.
Hence, the server may ALT between any mixture of CALL channels, ordinary
channels, timeouts
and Skips
.
However, when implementing the server, the CALL channel field needs to be declared as
an AltingChannelAccept
, rather than a ChannelAccept
.
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.]
Parallel
.
For example, the simple two process network:
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.]
Any2OneCallChannel
,
One2AnyCallChannel
,
Any2AnyCallChannel
,
Alternative
,
Serialized FormField 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 | |
---|---|
One2OneCallChannel()
|
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 org.jcsp.lang.Guard |
---|
schedule |
Methods inherited from class java.lang.Object |
---|
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Field Detail |
---|
protected CSProcess server
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.
protected int selected
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 |
---|
public One2OneCallChannel()
Method Detail |
---|
public int accept(CSProcess server)
selected
field
in the way defined by the standard calling sequence,
the value returned by this method will indicate which method was called.
accept
in interface ChannelAccept
server
- the server process receiving the CALL.protected void join()
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.
protected void fork()
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 |
||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |