{- Applet Server & Client; runs on one/two machines. This program demonstrates how to write an example communication infrastructure (middleware) for delivering location-independent messages. On top of it, a simple application is executed. The program works as follows: a top-level spawns any daemon(s) which are part of the infrastructure and begins the user-defined application. The application installs an applet server on a remote site and invokes a client process. The client downloads an applet to perform some computation; the result of the computation is printed out. The communication between 'client','server', and 'applet' is here entirely encoded using pi-calculus channels. An implementation that would be somewhat closer to those in traditional programming languages could use distributed objects in Nomadic Pict (see another example). You can execute the program choosing one of two different infrastructure algorithms: - Central Server (applet_cs.pi) - or, Forwarding Pointers (applet_fp.pi) Specify your machines in config file, type np on second machine and np applet_cs.pi (or np applet_fp.pi) on first machine. Note: if IP address of some machine appears in config more than once (with different port numbers) then you may need to execute np on that machine with an option -p to specify which port number shall be used. -} import "Nstd/Map" program param : [Site Site] = ( val [clnt_host server_host] = param new download : ^[Agent Site String] new receive : ^Agent new migrated : ^[] new compute : ^[Agent ^Int Int] {- applet specific -} agent top= ( agent server = ( migrate to server_host run print!"Applet server installed." run migrated@top![] {- signal migration succeeded -} download?*[clnt addr appname]= if (==$ appname "incr") then (agent applet = ( migrate to addr run print!"Applet downloaded." (receive@clnt!applet | compute?[caller r arg] = (print!"Add 1 to " | printi!arg | r@caller!(+ arg 1))) ) in ()) else () ) agent clnt = ( new get : ^Int migrated?_ = (download@server![clnt clnt_host "incr"] | receive?applet = ( compute@applet![clnt get 3] | get?result= print!(+$ "Applet computed that 3+1=" ($$ result)))) ) in migrated?*_= migrated![] {- say to clients that server ready -} ) ()) {-********************************************************************* * Copyright (c) 1998-2001 Pawel T. Wojciechowski * * Central Server * *********************************************************************-} {Agent} = Agent {Site} = Site new register : ^[Agent Site] new migrating : ^Agent new migrated : ^Site new message : ^[#X Agent !X X] new dack : ^[] new deliver : ^[#X !X X] new ack : ^[] new currentloc : ^Site { toplevel P prog_param }[Agent Agent Site] = ( val s1 = (sys.get_site 0) val s2 = (sys.get_site 1) agent a = (agent D = (def eq (a:Agent b:Agent) : Bool = (sys.== #Agent a b) new lock : ^(Map Agent Site) (lock!(map.make eq) | register?*[a s]= lock?m= ( lock!(map.add m a s) | ack![]) | migrating?*a= lock?m= switch (map.lookup m a) of (Found> s:Site -> ( ack![] | migrated?s' = ( lock!(map.add m a s') | ack![])) NotFound> _:[] -> ()) | message?*[#X a:Agent c:!X v:X]= lock?m= switch (map.lookup m a) of (Found> s:Site -> ( deliver![c v] | dack?_ = lock!m) NotFound> _:[] -> ()) )) in val SD = s1 ( deliver?*[#X c:!X v:X] = (dack![] | c!v) | register![a s1] | ack?_ = (currentloc!s1 | (val !prog_param = [s1 s2] val par = [a D SD] {P}par))) ) in () ) { agent b=P in Q } par = currentloc?s= (val [a D SD] = par agent B = (val !b = B ( deliver?*[#X c:!X v:X] = (dack![] | c!v) | register![B s] | ack?_= iflocal ack![] then ( currentloc!s | (val par = [B D SD] {P}par)) else () )) in val !b = B ack?_= ( currentloc!s | {Q}par)) { migrate to s P }par = ( val [a D SD] = par currentloc?_= ( migrating!a | ack?_ = ( migrate to s ( migrated!s | ack?_ = ( currentloc!s | {P}par) ))) ) { c@b!v }par = (val [a D SD] = par message![b c v])