javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen

19 RMI - objekter over netværk

Indhold:

Kapitlet forudsættes ikke i resten af bogen.

Forudsætter kapitel 12, Interfaces, kapitel 18, Serialisering og kendskab til netværk.

Med RMI (Remote Method Invocation) kan man arbejde med objekter, der eksisterer i en anden Java virtuel maskine (ofte på en anden fysisk maskine), som om de var lokale objekter.

19.1 Principper

Herunder er tegnet, hvad der sker, når en klient på maskine A laver et kald til et serverobjekt (værts-objekt), der er i maskine B.

Serverobjektet findes slet ikke på maskine A, i stedet er der en såkaldt RMI-stub, der repræsenterer det. Når der sker et kald til RMI-stubben på maskine A, sørger den for at transportere kaldet og alle parametre til maskine B, hvor serverobjektet bliver kaldt, som om det var et lokalt kald. Serverobjektets svar bliver transporteret tilbage til RMI-stubben, der returnerer det til klienten.

Denne proces foregår helt automatisk og er usynlig for klienten såvel som serverobjektet.

RMI benytter serialisering til at transportere parametre og returværdi mellem maskinerne, så man skal huske, at alle objekter, der sendes over netværket, skal implementere Serializable-interfacet og at variabler, der ikke skal overføres, skal mærkes med nøgleordet transient.

Der skal være defineret et interface (kaldet fjerninterfacet) til de metoder på serverobjektet, som skal være tilgængelige for klienten. Serverobjekt skal implementere dette interface.

19.2 I praksis

Lad os forestille os, at serveren har et konto-objekt, hvor man kan overføre penge, spørge om saldo og få bevægelserne. Disse metoder skal være tilgængelige over netværket, så vi definerer et fjerninterface til kontoen (her kaldt KontoI):

import java.util.ArrayList;

public interface KontoI extends java.rmi.Remote
{
  public void overførsel(int kroner) throws java.rmi.RemoteException;
  public int saldo()                 throws java.rmi.RemoteException;
  public ArrayList bevægelser()      throws java.rmi.RemoteException;
}

Fjerninterfacet skal arve fra interfacet java.rmi.Remote og alle metoder skal kunne kaste undtagelsen java.rmi.RemoteException.

19.2.1 På serversiden

På serversiden skal vi implementere Konto-interfacet og programmere den funktionalitet, der skjuler sig bag det i et serverobjekt, der skal arve fra UnicastRemoteObject. Klassenavnet ender normalt på Impl (for at vise, at det er implementationen af fjerninterfacet).

import java.util.ArrayList;
import java.rmi.server.UnicastRemoteObject;

public class KontoImpl extends UnicastRemoteObject implements KontoI
{
  public int saldo;
  public ArrayList bevægelser;

  public KontoImpl() throws java.rmi.RemoteException 
  {
    // man starter med 100 kroner
    saldo = 100;
    bevægelser = new ArrayList();
  }

  public void overførsel(int kroner)
  {
    saldo = saldo + kroner;
    String s = "Overførsel på "+kroner+" kr. Ny saldo er "+saldo+" kr.";
    bevægelser.add(s);
    System.out.println(s);
  }

  public int saldo()
  {
    System.out.println("Der spørges om saldoen. Den er "+saldo+" kr.");
    return saldo;
  }

  public ArrayList bevægelser()
  {
    System.out.println("Der spørges på alle bevægelser.");
    return bevægelser;
  }
}

Nu skal vi oprette et serverobjekt og registrere vores tjeneste under et navn i RMI:

import java.rmi.Naming;
public class Kontoserver
{
  public static void main(String[] arg) throws Exception
  {
    KontoI k = new KontoImpl();
    Naming.rebind("rmi://localhost/kontotjeneste", k);
    System.out.println("Kontotjeneste registreret.");
  }
}

Kontotjeneste registreret.
...

Programmet afslutter ikke, men venter på, at noget henvender sig, for at bruge tjenesten.

For at registreringen kan foregå, skal der køre en RMI-navnetjeneste, der holder styr på, hvilke tjenester, der udbydes under hvilke navne og formidler kontakten til dem. Det er et lille program, der hedder rmiregistry. Det skal kende definitionen af de klasser, der overføres, så man starter det ofte samme sted som selve RMI-tjenesten.

Når vi skal køre vores server, sker det i fire trin:

19.2.2 På klientsiden

På klientsiden skal vi slå serverobjektet op i RMI-tjenesten og derefter bruge det objekt, vi får retur, som om det var serverobjektet selv (i virkeligheden er det RMI-stubben):

import java.util.ArrayList;
import java.rmi.Naming;

public class Kontoklient
{

public static void main(String[] arg) { try { KontoI k =(KontoI) Naming.lookup("rmi://localhost/kontotjeneste"); k.overførsel(100); k.overførsel(50); System.out.println( "Saldo er: "+ k.saldo() ); k.overførsel(-200); k.overførsel(51); System.out.println( "Saldo er: "+ k.saldo() ); ArrayList bevægelser = k.bevægelser(); System.out.println( "Bevægelser er: "+ bevægelser ); } catch (Exception e) { e.printStackTrace(); } } }

Saldo er: 250
Saldo er: 101
Bevægelser er: [Overførsel på 100 kr. Ny saldo er 200 kr., Overførsel på 50 kr. Ny saldo er 250 kr., Overførsel på -200 kr. Ny saldo er 50 kr., Overførsel på 51 kr. Ny saldo er 101 kr.]

Sammen med Kontoklient skal ligge fjerninterfacet KontoI og KontoImpl_Stub.

Mens kontoklienten kører, kommer der følgende uddata fra Kontoserver:

Overførsel på 100 kr. Ny saldo er 200 kr.
Overførsel på 50 kr. Ny saldo er 250 kr.
Der spørges om saldoen. Den er 250 kr.
Overførsel på -200 kr. Ny saldo er 50 kr.
Overførsel på 51 kr. Ny saldo er 101 kr.
Der spørges om saldoen. Den er 101 kr.
Der spørges på alle bevægelser.

Herunder ses de enkelte klassers funktioner.

19.3 Opgaver

Prøv eksemplet på RMI. Oversæt .java-filerne og find ud af hvor .class-filerne ligger. Start tre terminalvinduer (DOS-vinduer i Windows). I hvert vindue skal du skrive

  cd <stedet hvor .class-filerne ligger>

Skriv derefter, i vindue 1:

  rmic KontoImpl
  rmiregistry

Skriv derefter, i vindue 2:

  java Kontoserver

Skriv derefter, i vindue 3:

  java Kontoklient

19.3.1 Server og klient to forskellige steder

Når ovenstående fungerer, så prøv at køre klienten i en anden mappe: Kopiér KontoI.class, Kontoklient.class og KontoImpl_Stub.class over i en anden mappe og prøv derfra.

Prøv derefter at rette i Kontoklient, sådan at klienten slår op i rmiregistry på en anden maskine. Er værtsmaskinens IP-nummer f.eks. 192.168.1.42, retter du i Kontoklient til:

    KontoI k =(KontoI) Naming.lookup("rmi://192.168.1.42/kontotjeneste");

19.4 Avanceret

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.

19.4.1 RMI og pakker

Dette afsnit er ikke omfattet af Åben Dokumentslicens.
Du skal købe bogen for at måtte læse dette afsnit.
Jeg erklærer, at jeg allerede har købt bogen
Jeg lover at anskaffe den i nær fremtid.
javabog.dk  |  << forrige  |  indhold  |  næste >>  |  programeksempler  |  om bogen
http://javabog.dk/ - af Jacob Nordfalk.
Licens og kopiering under Åben Dokumentlicens (ÅDL) hvor intet andet er nævnt (82% af værket).

Ønsker du at se de sidste 18% af dette værk (199974 tegn) skal du købe bogen. Så får du pæne figurer og layout, stikordsregister og en trykt bog med i købet.