1 - CORBA2 3 Inhoudsopgave Hoofdstuk 1.RMI Inleiding De remote Het remote De server De server opstarten De client applicatie De stub en skeleton en De...
2.1.CORBA..............................................................................................................20 2.2.JAVA IDL...........................................................................................................21 2.2.1.De interface definiëren..............................................................................22 2.2.2.De interface vertalen naar JAVA bestanden.............................................22 2.2.3.De server ontwikkelen...............................................................................24 2.2.4.De client ontwikkelen.................................................................................25 2.2.5.Client en server opstarten.........................................................................26 2.3.RMI-IIOP...........................................................................................................27 2.3.1.De code......................................................................................................28 2.3.2.Compilatie en generatie van de stubs/skeletons......................................32 2.3.3.Het opstarten van de applicaties...............................................................33 2.3.4.IDL genereren............................................................................................33
Copyright 2012 Noël Vaes
-1-
www.noelvaes.eu
RMI
Hoofdstuk 1. RMI 1.1. Inleiding RMI is de afkorting van Remote Method Invocation. Het is een technologie waarbij het mogelijk is dat een object in de ene virtuele machine een methode aanroept van een ander object in een andere virtuele machine. Deze technologie wordt gebruikt bij gedistribueerde applicaties voor de communicatie tussen client en server. De client en de server bevinden zich in een verschillende virtuele machine en doorgaans ook op een verschillend systeem. De communicatie tussen beide JVM's gebeurt hierbij via het netwerk op basis van JRMP (Java Remote Method Protocol) dat gebaseerd is op TCP/IP.
Client machine
Server machine
JVM
JVM
Client object
Remote object
JRMP TCP/IP netwerk In bovenstaande tekening wordt op eenvoudige wijze weergegeven hoe het ene object een methode oproept van een ander object (remote object) in een andere virtuele machine. De parameters worden hierbij door het RMI-subsysteem over het netwerk doorgestuurd naar de andere virtuele machine waar de methode door het het remote object wordt uitgevoerd. Eventuele resultaten worden op dezelfde manier via het netwerk teruggegeven aan het oproepende object. We gaan nu deze communicatie en de achterliggende systemen wat meer in detail bekijken. Een remote object is een object dat zijn functionaliteit van op afstand (remote) ter beschikking stelt. Dit wil zeggen dat dit object een aantal methoden heeft die opgeroepen kunnen worden door een object in een andere virtuele machine. Deze methoden moeten gedefinieerd worden in een afzonderlijke interface die afgeleid is van java.rmi.Remote. Het remote object dient deze interface te implementeren. Aan de client zijde krijgt het client-object een stub-object ter beschikking dat dezelfde interface implementeert. Dit stub-object dient als proxy om de methode-aanroep over het netwerk door te sturen naar de server. De server beschikt over een skeleton-object dat communiceert met het stub-object Copyright 2012 Noël Vaes
-2-
www.noelvaes.eu
RMI
en de meegegeven parameters in ontvangst neemt. Het stub-object zal op zijn beurt de methode van het remote object oproepen. Eventuele teruggegeven waarden worden door het skeleton-object teruggegeven aan het stub-object dat deze op zijn beurt aflevert aan het client-object.
JVM
JVM
Client object
stub
skeleton
interface
Server machine
interface
Client machine
Remote object
JRMP TCP/IP netwerk
Voor de communicatie tussen client en server zijn dus volgende elementen nodig: 1. De remote interface die bepaalt welke functionaliteit door het remote object ter beschikking wordt gesteld. Deze interface wordt geïmplementeerd door het remote object en het stub-object. 2. Een remote object dat deze interface implementeert en de concrete implementatie voorziet. 3. Een skeleton-object dat de oproep van het stub-object in ontvangst neemt en de methode van het remote object aanroept. 4. Een stub-object dat de remote interface implementeert en de methode-aanroep via het netwerk doorstuurt naar het skeleton-object. 5. Een client-object dat een methode van het stub-object oproept. De remote interface, het remote object en het client-object moeten door de programmeur ontwikkeld worden. Het stub-object en skeleton-object worden ofwel gegenereerd door de RMI compiler ofwel dynamisch aangemaakt door de JVM (vanaf Java 5). Nu rijst de vraag hoe het client-object een referentie kan bekomen naar een stubobject dat overeenkomt met een skeleton-object op de juiste server. Zo'n referentie kan op twee manier bekomen worden: 1. Via een return-waarde van een of andere methode. Eens een referentie naar een stub-object in een JVM beschikbaar is, kan die als parameter doorgegeven worden. Blijft dan de vraag hoe de eerste keer deze referentie bekomen wordt. 2. De eerste referentie naar een stub-object wordt bekomen via het RMI register. Dit RMI register is een applicatie die doorgaans draait op de server waar het remote object zich bevindt. Dit remote object moet zich in dit register registreren. Vervolgens kan een remote client een referentie opzoeken in dit register. Het RMI Copyright 2012 Noël Vaes
-3-
www.noelvaes.eu
RMI
register stelt vervolgens een juist geconfigureerd stub-object ter beschikking.
Server machine RMI register
opzoeken
Client machine
interface
Client object
stub
skeleton
interface
JVM registreren
JVM
Remote object
JRMP TCP/IP netwerk In het vervolg van dit hoofdstuk zullen we aan de hand van een voorbeeld de details van RMI onder de loep nemen.
1.2. De remote interface De eerste stap in het ontwikkelen van een client-server applicatie is het definiëren van de remote interface. Deze interface bepaalt welke methoden beschikbaar worden gesteld door remote objecten. Remote interfaces moeten aan de volgende voorwaarden voldoen: 1. Ze moeten afgeleid zijn van java.rmi.Remote. Dit is een marker-interface zonder methoden. Ze dient enkel om aan te geven (te markeren) dat objecten die deze interface implementeren remote objecten zijn. Dit zorgt ervoor dat deze objecten op een speciale manier behandeld kunnen worden door het RMI subsysteem. We komen hier later nog op terug. 2. Iedere methode van de remote interface moet een java.rmi.RemoteException gooien. De reden hiervoor is dat iedere methodeaanroep via het netwerk gebeurt en dat er steeds het risico bestaat dat er communicatieproblemen optreden. Dergelijk problemen worden steeds gemeld via deze RemoteException. 3. Alle parameters van de methoden moeten ofwel serialiseerbaar zijn, ofwel zelf remote objecten zijn. Serialiseerbare objecten worden immers via het serialisatie-mechanisme over het netwerk doorgestuurd van de stub naar het skeleton. In het skeleton wordt het object terug gedeserialiseerd. Dit impliceert overigens dat de server steeds werkt met een gedeserialiseerde kopie van het originele object dat als parameter werd meegegeven. Men noemt dit om deze reden ook call-by-value. Voor remote objecten liggen de zaken anders. Hier wordt het object niet geserialiseerd maar wordt een nieuw stub-object (op de server) en skeleton-object (op de client) gecreëerd. De server krijgt m.a.w. een referentie naar een stubCopyright 2012 Noël Vaes
-4-
www.noelvaes.eu
RMI
object. Iedere methode-aanroep wordt bijgevolg doorgestuurd naar het remote object op de client. We noemen dit daarom ook call-by-reference. 4. Ook alle return-waardes van de methoden moeten ofwel serialiseerbaar zijn, ofwel remote objecten zijn. Als voorbeeld gaan we een chat-applicatie ontwikkelen met een chat-server en chatclient. Als eerste stap moeten we een remote interface definiëren voor een chatbox. Maar eerst definiëren we een interface voor de boodschappen die we naar de chatbox sturen: package be.noelvaes.chat; import java.io.Serializable; public interface Message extends Serializable{ public String getText(); public String getUserName(); }
Vermits een boodschap over het netwerk geserialiseerd wordt, leiden we de interface af van de interface Serializable. Alle implementerende klassen zijn daardoor in principe ook serialiseerbaar. In deze interface voorzien we enkel methoden om de boodschap en de naam van de gebruiker op te vragen. Voorts definiëren we de remote interface voor de chatbox: package be.noelvaes.chat; import java.rmi.*; public interface ChatBox extends Remote { public void sendMessage(Message msg) throws RemoteException; }
Deze interface is afgeleid van java.rmi.Remote en tevens gooit de enige methode een java.rmi.RemoteException.
Opdracht 1: De remote interface definiëren Maak in je IDE een nieuw JAVA-project met de naam ChatBox. Voorzie een folder src voor de broncode en een folder build/classes voor de gecompileerde klassen. Stel de IDE ook op de juiste wijze in. Maak de interface Message en compileer. Maak de interface ChatBox en compileer.
1.3. Het remote object Het remote object moet de functionaliteit van de remote interface implementeren. Op dit moment houden we deze functionaliteit heel eenvoudig. We laten de chatbox de ontvangen boodschap gewoon afdrukken in de console. Later gaan we dit uitbreiden zodat alle aangemelde gebruikers een boodschap ontvangen.