Første |
|
Remote Method Interface serie, Planche nr. 24 |
![]() |
Udskrift af : Remote Method Interface |
Formål at arbejde med metoder og variable på objekter, der ikke er lokale.
rmiregistry
RMI bruger webservere til at flytte bytecode med.
java.rmi.Remote
.throws java.rmi.RemoteException
javac
rmic
Der er kun en metode - executeTask() Task skal også defineres som interface:package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { Object executeTask(Task t) throws RemoteException; }
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.package compute; import java.io.Serializable; public interface Task extends Serializable { Object execute(); }
implements
interfacetpackage 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(); } } }
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
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
Den laves af 2 klasser, ComputePi og Pi
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(); } } }
Alle beregningsspecifikke ting er isoleret i denne klasse Den kunne udskiftes (i ComputePi) med en klasse, der lavede en anden numerisk beregning.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; } }
javac compute/Compute.java
javac compute/Task.java
javac engine/ComputeEngine.java
ogrmic -d . engine.ComputeEngine
(Det tager LIDT tid....)