_ 3.3.1 RMI på klientsidan Uppgiften belyser högnivåkopplingar med RMI där man delar upp ett program i flera delar där delarna körs på olika maskiner. Med RMI kan man i sina program använda objekt som körs på andra maskiner på ett mycket naturligt sätt, trots att objekten egentligen "lever" på olika maskiner. __ Uppgift På servern §atlas.dsv.su.se§ körs ett RMI-serversidesprogram (med tillhörande stubbe §[Server_Stub.class, 05_ass/ip1/3/3.3.2/space/Server_Stub.class]§) som man kan nå via RMI-registryt på defaultporten §1099§ anknytning §server§ och som kan anropas via de metoder som programmet implementerar i interfacet §[RemoteServer.java, 05_ass/ip1/3/3.3.2/space/RemoteServer.java]§. Detta program simulerar ett antal bollar som studsar runt inom ett koordinatsystem som har: - Origo längst upp till vänster - Positiva §x§-värden åt höger - Positiva §y§-värden neråt Varje boll beskrivs med: - Position §x§ som ligger inom intervallet §0-500§ - Position §y§ som ligger inom intervallet §30-500§ - Radie §r§ som ligger inom intervallet §0-70§, där bollar med radie §0§ tas bort Metoderna som kan anropas har följande funktion: - §addBall§ lägger till en ny boll - §pauseBalls§ pausar eller startar bollarna - §getBalls§ returnerar alla bollar i en vektor där: -- Element 1 innehåller första bollens §x§-värde -- Element 2 innehåller första bollens §y§-värde -- Element 3 innehåller första bollens radie -- Element 4 innehåller andra bollens §x§-värde, och så vidare Gör ett RMI-klientsidesprogram som använder dessa metoder för att grafiskt åskådliggöra de processer som kan sättas igång, pausas och köras på RMI-serversidesprogrammet. Om man tycker att rörlig grafik är svårt (trots tipsen nedan) så kan man istället välja att bygga en RMI-klient och en RMI-server som implementarar något annat. Exempelvis så kan man implementera Mandelbrots mängd på ett liknande sätt fast då även göra serversidesprogrammet samtidigt. Några tips om det: - [Mandelbrots mängd, 03_material/docs/mandel/ip1.txt] Frivillig överkurs är att hämta stubben §[Server_Stub.class, 05_ass/ip1/3/3.3.2/space/Server_Stub.class]§ dynamiskt vid körning. __ Exempel Hämta filerna: - §[Client.class, 05_ass/ip1/3/3.3.1/space/Client.class]§ - §[Client$L.class, 05_ass/ip1/3/3.3.1/space/Client$L.class]§ - §[RemoteServer.class, 05_ass/ip1/3/3.3.1/space/RemoteServer.class]§ - §[Server_Stub.class, 05_ass/ip1/3/3.3.1/space/Server_Stub.class]§ Kör igång RMI-klientprogrammet med: - §java Client atlas.dsv.su.se§ Tryck på §+§-knappen för att skapa nya bollar och på §p§-knappen för att pausa och sätta igång bollarna. Testa att starta flera program för att se att bollarna är synkroniserade på de olika programmen, gärna på flera olika maskiner. Ett annat exempel är ett RMI-klientprogram för Mandelbrots mängd. Hämta filerna: - §[Client.class, 05_ass/ip1/3/3.3.1/mandelbrot/Client.class]§ - §[Client$ThePanel.class, 05_ass/ip1/3/3.3.1/mandelbrot/Client$ThePanel.class]§ - §[Client$MouseListener1.class, 05_ass/ip1/3/3.3.1/mandelbrot/Client$MouseListener1.class]§ - §[Client$MouseMotionListener1.class, 05_ass/ip1/3/3.3.1/mandelbrot/Client$MouseMotionListener1.class]§ - §[RemoteServer.class, 05_ass/ip1/3/3.3.1/mandelbrot/RemoteServer.class]§ - §[Server_Stub.class, 05_ass/ip1/3/3.3.1/mandelbrot/Server_Stub.class]§ Kör igång RMI-klientprogrammet med: - §java Client atlas.dsv.su.se§ Zooma i bilden genom att trycka ner vänster musknapp och dra ut en fyrkant. Ett exempel på ett program som dynamiskt hämtar stubben §[Server_Stub.class, 05_ass/ip1/3/3.3.2/space/Server_Stub.class]§ vid körning: Hämta filerna: - §[Client.class, 05_ass/ip1/3/3.3.1/dynamic/Client.class]§ - §[Client$L.class, 05_ass/ip1/3/3.3.1/dynamic/Client$L.class]§ - §[RemoteServer.class, 05_ass/ip1/3/3.3.1/dynamic/RemoteServer.class]§ - §[policy, 05_ass/ip1/3/3.3.1/dynamic/policy]§ Kör igång RMI-klientprogrammet med: - §java -Djava.security.policy=policy -Djava.rmi.server.codebase=http://atlas.dsv.su.se/~pierre/i/05_ass/ip1/3/3.3.1/dynamic/ Client atlas.dsv.su.se§ __ Tips Var väldigt noga och tänk minimalistiskt, det blir lätt fel annars. Se [The Coffee Break: Introduction to Java RMI, http://www.javacoffeebreak.com/articles/javarmi/javarmi.html]. Använd inte §SecurityManager§ och §Registry§ och så vidare utan använd istället följande för att få en referens till ett objekt på serversidan: § String url = "rmi://" + host + "/"; RemoteServer remoteServer = (RemoteServer)Naming.lookup(url + "server"); § RMI-klientprogrammet är givetvis trådat och i §run§-metoden kan man exempelvis ha: § while(true) { // Hämtar först till en tmp-vektor för att slippa blinkandet Vector ballsRawTmp = null; try { ballsRawTmp = remoteServer.getBalls(); } catch(RemoteException re) { System.out.println("Exception generated: " + re.getMessage()); } // Sudda de tidigare bollarna Graphics g = getGraphics(); g.setColor(getBackground()); for(int i = 0; i < ballsRaw.size(); i = i + 3) { int x = (Integer)ballsRaw.elementAt(i); int y = (Integer)ballsRaw.elementAt(i + 1); int r = (Integer)ballsRaw.elementAt(i + 2); g.fillOval(x, y, r, r); } // Rita de nya bollarna ballsRaw = ballsRawTmp; for(int i = 0; i < ballsRaw.size(); i = i + 3) { int x = (Integer)ballsRaw.elementAt(i); int y = (Integer)ballsRaw.elementAt(i + 1); int r = (Integer)ballsRaw.elementAt(i + 2); int blue = r * 255 / rMax; if(blue > 255) blue = 255; if(blue < 0) blue = 0; g.setColor(new Color(0, 0, blue)); g.fillOval(x, y, r, r); } setTitle("Antal bollar: " + ballsRaw.size() / 3); try { Thread.sleep(50); } catch(Exception e) {} } § Här är: § int xLim = 500, yLim = 500, rMax = 70; § Man kan givetvis vända på det här med att köra krävande processer på serversidan. Man kan exempelvis göra en distribuerad beräkning genom att konstruera ett äpple som beräknar en del av en krävande process och där serversidan enbart organiserar de olika processerna. Har man många besökare på sin webbplats så kan man på så sätt få tillgång till enormt mycket datakraft, men man bör givetvis informera besökarna om att man använder deras datorer (speciellt om man använder dolda äpplen) och även göra äpplet så att det inte förbrukar alla resurser på besökarnas datorer. Om man vill hämta stubben dynamiskt så måste RMI-klientprogrammet använda en §RMISecurityManager§ och startas med en §codebase§ som pekar på det ställe där stubben §[Server_Stub.class, 05_ass/ip1/3/3.3.2/space/Server_Stub.class]§ finns. Vill man få detta att fungera med äpplen så måste man, som tidigare, lägga äpplet på samma ställe som §[Server_Stub.class, 05_ass/ip1/3/3.3.2/space/Server_Stub.class]§ ligger på. Se vidare [Oracle: Dynamic code downloading using RMI, http://download.oracle.com/javase/1.5.0/docs/guide/rmi/codebase.html]. Slutligen några tips om [Mandelbrots mängd, 03_material/docs/mandel/ip1.txt] för de som vill implementera uppgiften på detta sätt. __ Hjälp ~ 05_ass/help/01.txt > [Klicka här för hjälp, helper.dsv@gmail.com, Prog Internet: 3.3.1 RMI på klientsidan: http://people.dsv.su.se/~pierre/i/i.cgi?href=05_ass/ip1/3.3.1.txt] ½===system_tutoring_message===½ < ~ 05_ass/help/02.txt