{- 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 * * Forwarding Pointers * *********************************************************************-} {Agent} = [Agent Site Agent] {Site} = [Site Agent] new register : ^Agent new migrating : ^Agent new migrated : ^[Agent [Site Agent]] new message : ^[#X [Agent Site Agent] !X X] new currentloc : ^[Site Agent] new ack : ^[] { toplevel P pa }Agent = ( val s1 = (sys.get_site 0) val s2 = (sys.get_site 1) {- Spawn daemons on sites -} new daemondaemon : ^Site new nd : ^[Site Agent] agent A = ( daemondaemon?*S:Site= (agent D = (migrate to S def eq (a:Agent b:Agent) : Bool = (sys.== #Agent a b) new lock : ^(Map Agent ^[Site Agent]) (lock!(map.make eq) | register?*B:Agent= lock?m= switch (map.lookup m B) of ( Found> Bstate:^[Site Agent] -> Bstate?_= ( Bstate![S D] | lock!m | ack![]) NotFound> [] -> (new Bstate : ^[Site Agent] ( Bstate![S D] | lock!(map.add m B Bstate) | ack![]))) | migrating?*B:Agent= lock?m= switch (map.lookup m B) of ( Found> Bstate:^[Site Agent] -> Bstate?_= ( lock!m | ack![]) NotFound> [] -> ()) | migrated?*[B:Agent [U:Site DU:Agent]]= lock?m= switch (map.lookup m B) of ( Found> Bstate:^[Site Agent] -> ( lock!m | Bstate![U DU] | ack![]) NotFound> [] -> ()) | message?*[#X [B:Agent U:Site DU:Agent] c:!X v:X]= lock?m= switch (map.lookup m B) of ( Found> Bstate:^[Site Agent] -> ( lock!m | Bstate?[R DR]= iflocal c!v then Bstate![R DR] else (message![#X [B U DU] c v] | Bstate![R DR])) NotFound> [] -> ( lock!m | message![#X [B U DU] c v])) | nd![S D])) in ()) | daemondaemon!s1 | nd?s1= (daemondaemon!s2 | nd?s2= (val [S1 DS1] = s1 val a = [A S1 DS1] (currentloc![S1 DS1] | register!A | ack?_= (val !pa = [s1 s2] {P}A) ))) ) in ()) { agent b=P in Q }A = currentloc?[S DS]= (agent B = ( currentloc![S DS] | register!B | ack?_= (val !b = [B S DS] iflocal ack![] then { P }B else ())) in ack?_= (currentloc![S DS] | (val !b = [B S DS] {Q}A))) { migrate to u P }A = currentloc?[S DS]= (val [U DU] = u if (&& (sys.== #Agent DS DU) (sys.== #Site S U)) then ( currentloc![U DU] | { P }A) else ( migrating!A | ack?_= (migrate to U ( register!A | ack?_= ( migrated![A [U DU]] | ack?_= ( currentloc![U DU] | {P}A)))))) {- Location-independent output to agent -} { c@b!v }A = currentloc?[S DS]= (val [B U DU] = b {- optimisation iflocal c!v then currentloc![S DS] else -} iflocal message![b c v] then currentloc![S DS] else currentloc![S DS]) {- Output to agent on specified site -} { c!v }A = (val [B _ _] = b val [S _] = s iflocal c!v then () else (agent m = (migrate to S iflocal c!v then () else ()) in ())) {- Output to agent on current site -} { c!v }A = (val [B _ _] = b iflocal c!v then () else ()) {- Test & send -} { iflocal c!v then P else Q }A = (val [B _ _] = b iflocal c!v then {P}A else {Q}A)