© John Visser, Arjan Besjis en Harry Broeders.
In deze practicum opdracht maak je gebruik van Java Remote Method Invocation, dit is een technologie waarmee een cliënt een remote object op een server kan benaderen. De methoden van dit serverobject kunnen dus vanuit een andere JVM (Java Virtuele Machine) worden aangeroepen. Om de communicatie tussen de server en de client werkend te krijgen wordt gebruik gemaakt van stub en skeleton objecten. De werking van RMI is behandeld bij ESWE1C2. Meer informatie over RMI kun je vinden op:
In de onderstaande figuur worden de stappen getoond, die uitgevoerd moeten worden om een RMI client- en serverclass te maken. Hierbij wordt gebuik gemaakt van de Java omgeving die je ook bij opdracht 3 hebt gebruikt.
We zullen aan het einde van deze opdracht ook het producer/consumer programma uit opgave 3 met behulp van RMI over verschillende machines verdelen.
Met behulp van het volgende stappenplan kun je methods van een object op de ene (server) machine aanroepen vanaf een andere (client) machine.
java.rmi.Remote
interface uit te breiden.
Elke method in een remote interface moet een
java.rmi.RemoteException
kunnen gooien. Als voorbeeld gebruiken
we een distributed applicatie waarbij een client een nummer ophaalt van de
server. De remote interface kan dan als volgt gedefinieerd worden:
import java.rmi.*; public interface RemoteInt extends Remote { public int haalnr() throws RemoteException; }
java.rmi.UnicastRemoteObject
. In de constructor wordt het
gecreëerde object op de server (localhost) gekoppeld aan de naam die
meegegeven wordt bij het aanroepen van de constructor. Dit gebeurt in de
aanroep: Naming.rebind(s, this);
import java.rmi.*; import java.rmi.server.*; import java.net.*; public class RemoteImp extends UnicastRemoteObject implements RemoteInt { public RemoteImp(String naam, int a) throws RemoteException, MalformedURLException { Naming.rebind("rmi://localhost/"+naam, this); nr=a; } public int haalnr() throws RemoteException { return nr; } private int nr; }
PATH
environment
variabele opneemt kun je de java tools eenvoudig vanuit een DOS box starten.
cd vul-hier-je-werkdirectory-in set PATH=c:\program files\java\jdk-vul-hier-de-versie-in\bin\;"%PATH%" javac RemoteImp.java
rmic
genoemd. Je moet
rmic
gebruiken om de client-stub en het server-skeleton voor
de remote class te genereren. De stub wordt in de client applicatie gebruikt
als stand-ins (proxy) voor het remote object. De stub verzendt remote aanroepen
naar de server. Het skeleton1 ontvangt de
aanroep, leest de parameters en roept vervolgens het door jou gedefinieerde
remote object aan. Je runt rmic
door de volgende opdracht te
typen:
rmic RemoteImp
De rmic
stubcompiler gebruikt dezelfde argumenten als
javac
. Zo kun je bijvoorbeeld met het opdrachtregelargument
-classpath
de locatie van je classes aangeven. De gegenereerde
stub en skeleton classes worden in de actieve directory geplaatst, tenzij
je met de optie -d
een andere locatie opgeeft.
1 In Java 1.1
is een aparte skeleton nodig. Vanaf Java 1.2 (ook wel Java 2 genoemd) is
een aparte skeleton niet meer nodig. Bij Java 2 wordt aan de serverkant ook
(net zoals aan de clientkant) gebruik gemaakt van de stub. Aan de serverkant
wordt de benodigde skeleton code dan dynamisch (tijdens run-time) aangemaakt
zodra deze code nodig is. Deze skeleton code wordt afgeleid van de stub.
In Java 2 is het ook mogelijk om aan de client kant te verwijzing naar de
stub die op de server staat (net zoals bij een applet). De client code zal
dan zelf de stub van de server ophalen. Details kun je vinden op:
http://developer.java.sun.com/developer/onlineTraining/rmi/RMI.html.
Als je het commando rmic -v1.2 RemoteImp
gebruikt wordt alleen
de stub gegenereerd.
start rmiregistry
start
is een DOS commando waarmee een applicatie in een nieuw
DOS venster wordt gestart. Je moet het registry starten in het directory
waar de sceleton staat (<= Java 1.1) of de stub staat (>=1.2).
De registry-database is leeg als de server wordt gestart. Je moet de registry zelf vullen met de remote objecten die je maakt. Het rmiregistry programma moet blijven draaien.
Server
.
public class Server { public static void main(String args[]) { int a=Integer.parseInt(args[0]); try { RemoteImp nt=new RemoteImp("remobj", a); System.out.println("Remote object geinstalleerd."); } catch (Exception e) { System.out.println(e.getMessage()); } } }
Je kunt nu als volgt (in een nieuwe DOS box) een remote object aanmaken met de waarde 123:
javac Server.java start java.exe Server 123
Dit programma moet ook blijven draaien.
bind
of
rebind
van de class java.rmi.Naming
om een naam
aan een remote object te verbinden. Deze naam wordt opgeslagen in de RMI
registry. Dit gebeurt in de constructor
van RemoteImp
. Het remote object kan nu door de client worden
aangeroepen.
java.rmi.Naming
gebruiken om een remote object
te lokaliseren. Je roept vervolgens via een stub die als proxy voor het remote
object dient de methoden ervan aan. Deze stub is door rmic
gegenereerd.
import java.rmi.*; public class Client { public static void main(String args[]) { try { RemoteInt obj =(RemoteInt)Naming.lookup("rmi://"+args[0]+"/remobj"); System.out.println("nr = "+obj.haalnr()); } catch (Exception e) { System.out.println(e.getMessage()); } } }
javac Client.java
java Client vul-hier-het-ip-adres-van-de-server-in
Opdracht 4a.
Haal de files Compileer de java files en maak de benodigde stub's aan. Ga hierbij volgens het bovengenoemde stappenplan te werk. Run de server en de client eerst op 1 machine (je kunt dan localhost of 127.0.0.1 als ip adres van de server gebruiken. Laat daarna de server en de client op verschillende machines lopen. Verwijder alle overbodige files van de server- en de clientmachine! |
Opdracht 4b.Het boundedbuffer programma uit opgave 3 kunnen we met behulp van RMI over meerdere machines verdelen.
Definieer een remote class import java.rmi.Remote; import java.rmi.RemoteException; public interface BoundedBuffer extends Remote { public void put(char c) throws InterruptedException, RemoteException; public char get() throws InterruptedException, RemoteException; } De class RemoteBoundedBuffer kan als volgt gedefinieerd worden: public class RemoteBoundedBuffer extends UnicastRemoteObject implements BoundedBuffer { // ... rest nog invullen ... }
Schrijf ook een
Schrijf een class |