Første
Remote Method Interface serie, Planche nr. 24
Kursus Indhold

Udskrift af : Remote Method Interface

Planche 1 : Remote Method Interface

En client/server-teknik, hvor man distribuerer objektet over nettet.

Formål at arbejde med metoder og variable på objekter, der ikke er lokale.

Planche 2 : Distribueret objektprogram

Skal kunne

Planche 3 : Oversigt over RMI

RMI bruger webservere til at flytte bytecode med.

Planche 4 : Hvorfor RMI mulig

Planche 5 : RMI forskellen

Istedet for at lave en ny kopi af et distribueret objekt, sørger RMI for, at der laves stubs - "håndtag" til objektet, som kan kaldes udefra.

Planche 6 : Designfaser

Planche 7 : Designfaser 1

(De to sidste kan foregå sideløbende)

Planche 8 : Designfase 2

Oversæt og dan stubs: Den dannede stub-klasse fungere som "stedfortræder" overfor klient-objekterne.

Planche 9 : Designfase 3 og 4

Planche 10 : Eksempel

Eksemplet er et fjernt objekt, der foretager en beregning på en server. The compute engine

Planche 11 : The Compute Engine

Planche 12 : Interface

Føglende definerer interfacet.
package compute;

import java.rmi.Remote; 
import java.rmi.RemoteException;

public interface Compute extends Remote {
    Object executeTask(Task t) throws RemoteException; 
}
Der er kun en metode - executeTask() Task skal også defineres som interface:
package compute;

import java.io.Serializable;

public interface Task extends Serializable {    
    Object execute(); 
}
Dette er ikke et fjernt objekt - derimod kan det serializeres - det kan sendes over en stream. Bemærk at begge metoder returnerer objekter. Når det implementers og bruges må man altså ikke bruge primitive typer.

Planche 13 : Implementere fjernobjekt

Fjernobjekt == serverobjekt En server skal desuden (RMI har en sådan register-service - men også andre kan bruges)

Planche 14 : Compute Engine

package engine;

import java.rmi.*; 
import java.rmi.server.*;
import compute.*;

public class ComputeEngine extends UnicastRemoteObject
                           implements Compute 
{
    public ComputeEngine() throws RemoteException {
        super();
    }
    public Object executeTask(Task t) {
        return t.execute();     
    }

    public static void main(String[] args) { 
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());                        
        }
         String name = "//localhost/Compute";         
         try {
            Compute engine = new ComputeEngine();
            Naming.rebind(name, engine);
            System.out.println("ComputeEngine bound");
        } catch (Exception e) {
            System.err.println("ComputeEngine exception: " +  e.getMessage());
            e.printStackTrace();
        }
    }
}

Planche 15 : Noter

public class ComputeEngine extends UnicastRemoteObject
                                       implements Compute

UnicastRemoteObjekt er en klasse i java.rmi.server, velegnet til serverobjekter. Den overskriver en række Object-metoder, så de kan bruges over nettet.

public ComputeEngine() throws RemoteException {
                super();
            }
Metode for at oprette objektet.
public Object executeTask(Task t) {
                return t.execute();
            }
Klienter leverer objektet, der indeholder opgaven - serveren udfører det og returnerer resultatet.

Serveren bekymrer sig ikke om objektets type - det er klientens problem

Planche 16 : Typer, der kan overføres

RMI tillader overførsler af objekter af typen: (sidstnævnte klasser implementere java.io.Serializable) I sidste tilfælde føres ændringer ikke tilbage til kalder

Planche 17 : Resten af Compute Engine

		if (System.getSecurityManager() == null) {
                System.setSecurityManager(new RMISecurityManager());
            }
      Compute engine = new ComputeEngine();
	String name = "//localhost/Compute";
	Naming.rebind(name, engine);
PS: Hostnavn skal hos os være IP-adresse

Planche 18 : Klientprogram

I eksemplet er klients opgave at beregne Pi

Den laves af 2 klasser, ComputePi og Pi

Planche 19 : ComputePi

 
package client;

import java.rmi.*;
import java.math.*;
import compute.*;

public class ComputePi {
    public static void main(String args[]) {
        if (System.getSecurityManager() == null) {
            System.setSecurityManager(new RMISecurityManager());
        }
        try {
            String name = "//" + args[0] + "/Compute";
            Compute comp = (Compute) Naming.lookup(name);
            Pi task = new Pi(Integer.parseInt(args[1]));
            BigDecimal pi = (BigDecimal) (comp.executeTask(task));
            System.out.println(pi);
        } catch (Exception e) {         
            System.err.println("ComputePi exception: " + e.getMessage());
            e.printStackTrace();
        }
    } 
}

Planche 20 : Hvad laver ComputePi?

Planche 21 : Pi

Selve "opgaven" - implementeringen af Task
 
package client;
import compute.*;
import java.math.*;

public class Pi implements Task {

    /** constants used in pi computation */
    private static final BigDecimal ZERO = 
        BigDecimal.valueOf(0);
    private static final BigDecimal  ONE = 
        BigDecimal.valueOf(1);
    private static final BigDecimal FOUR = 
        BigDecimal.valueOf(4);

    /** rounding mode to use during pi computation */
    private static final int roundingMode = 
        BigDecimal.ROUND_HALF_EVEN;

    /** digits of precision after the decimal point */
    private int digits;
    
    /**
     * Construct a task to calculate pi to the specified
     * precision.
     */
    public Pi(int digits) {
        this.digits = digits;
    }

    /**
     * Calculate pi.
     */
    public Object execute() {
        return computePi(digits);
    }

    /**
     * Compute the value of pi to the specified number of 
     * digits after the decimal point.  The value is 
     * computed using Machin's formula:
     *
     *          pi/4 = 4*arctan(1/5) - arctan(1/239)
     *
     * and a power series expansion of arctan(x) to 
     * sufficient precision.
     */
    public static BigDecimal computePi(int digits) {
        int scale = digits + 5;
        BigDecimal arctan1_5 = arctan(5, scale);
        BigDecimal arctan1_239 = arctan(239, scale);
        BigDecimal pi = arctan1_5.multiply(FOUR).subtract(arctan1_239).multiply(FOUR);
         return pi.setScale(digits, 
                          BigDecimal.ROUND_HALF_UP);
    }

    /**
     * Compute the value, in radians, of the arctangent of 
     * the inverse of the supplied integer to the speficied
     * number of digits after the decimal point.  The value
     * is computed using the power series expansion for the
     * arctangent:
     *
     * arctan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + 
     *     (x^9)/9 ...
     */   
    public static BigDecimal arctan(int inverseX, 
                                  int scale) 
    {
        BigDecimal result, numer, term;
        BigDecimal invX = BigDecimal.valueOf(inverseX);
        BigDecimal invX2 = 
            BigDecimal.valueOf(inverseX * inverseX);

        numer = ONE.divide(invX, scale, roundingMode);

        result = numer;
        int i = 1;
        do {
            numer = 
                numer.divide(invX2, scale, roundingMode);
            int denom = 2 * i + 1;
            term = 
                numer.divide(BigDecimal.valueOf(denom),
                             scale, roundingMode);
            if ((i % 2) != 0) {
                result = result.subtract(term);
            } else {
                result = result.add(term);
            }
            i++;
        } while (term.compareTo(ZERO) != 0);
        return result;
    }
}
Alle beregningsspecifikke ting er isoleret i denne klasse Den kunne udskiftes (i ComputePi) med en klasse, der lavede en anden numerisk beregning.

Planche 22 : Oversættelse

Hver af pakkerne skal gemmes i et separat underkatalog Derefter skal de oversætte: (Normalt ville man putte interfaces i en jar-file og distribuere den til udviklerne...)

Planche 23 : Køre programmerne

(I korte træk) Klient-host hedder 'ford' og server-host 'zaphod'

Planche 24 : Prøve?

Download tutorial fra java.sun.com og følge RMI-trail

(Det tager LIDT tid....)