# RMI unter Java 5



## Thomas Darimont (25. Dezember 2005)

Hallo!

    Hier mal ein kleines Beispiel zu RMI unter Java 5.
  Welche schicken Neuerungen es für RMI unter Java 5 gibt könnt ihr hier:
http://today.java.net/pub/a/today/2005/10/06/the-new-rmi.html
  oder hier:
http://java.sun.com/j2se/1.5.0/docs/guide/rmi/relnotes.html
  nachlesen.

  In diesem Beispiel verwenden wir zur Laufzeit erzeugte Dynamic Proxies als Client-Stubs.
    (D.h. wir werden keinen rmic Stub Compiler verwenden)

    In meinem Rechner habe ich mehrere Netzwerkkarten. Da ich die rmiregistry jedoch
    explizit an das Network Interface mit der IP 192.168.76.98 binde muss ich beim lookup
    der Registry die entsprechende IP Addresse mitgeben.

    Unser Service Interface:

```
package de.tutorials.rmi.service;
    
    import java.rmi.Remote;
    import java.rmi.RemoteException;
    
    public interface IRemoteService extends Remote {
    	String remoteOperation(String[] arguments) throws RemoteException;
    }
```
 
    Unsere Service Implementierung:

```
/**
     * 
     */
    package de.tutorials.rmi.service.impl;
    
    import java.rmi.RemoteException;
    import java.rmi.server.UnicastRemoteObject;
    import java.util.Arrays;
    
    import de.tutorials.rmi.service.IRemoteService;
    
    /**
     * @author Tom
     * 
     */
    public class RemoteServiceImpl extends UnicastRemoteObject implements
    		IRemoteService {
    	public RemoteServiceImpl() throws RemoteException {
    		super();
    	}
    
    	public String remoteOperation(String[] arguments) throws RemoteException {
    		String result = Arrays.toString(arguments);
    		System.out.printf("remoteOperation invoked @%s with arguments %s\n",
 				System.currentTimeMillis(), result);
    		return result;
    	}
    }
```
 
    Unser Server:

```
/**
     * 
     */
    package de.tutorials.rmi;
    
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    import de.tutorials.rmi.service.IRemoteService;
    import de.tutorials.rmi.service.impl.RemoteServiceImpl;
    
    /**
     * @author Tom
     * 
     */
    public class Bootstrap {
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) throws Exception {
    		Registry registry = LocateRegistry.getRegistry("192.168.76.98");
    		IRemoteService remoteService = new RemoteServiceImpl();
    		registry.rebind("remoteService", remoteService);
    	}
    }
```
 
    Unser Client:
    Der Client liegt in meinem Beispiel auf einem anderen Rechner. Auf Clientseite liegen nur die
    Interfaces unseres Services (IRemoteService) vor, nicht jedoch die Implementierung.
    (Man könnte den Client natürlich auch so konfigurieren, dass er sich die Interface Klassen selber
    lädt:
 Beispiel ... die Klassen liegen in einem Verzeichnis namens bin im htdocs Verzeichnis eines Apache Webservers.
 Unser Aufruf der RMI Registry sieht dann so aus:

```
C:\>rmiregistry -J-Djava.rmi.server.codebase=http://localhost/bin/ -J-Djava.rmi.server.hostname=192.168.76.98
```
).


```
/**
     * 
     */
    package de.tutorials.rmi.client;
    
    import java.lang.reflect.Proxy;
    import java.rmi.registry.LocateRegistry;
    import java.rmi.registry.Registry;
    
    import de.tutorials.rmi.service.IRemoteService;
    
    /**
     * @author Tom
     * 
     */
    public class Client {
    
    	/**
    	 * @param args
    	 */
    	public static void main(String[] args) throws Exception {
    		Registry registry = LocateRegistry.getRegistry("192.168.76.98", 1099);
    		IRemoteService remoteServiceProxy = (IRemoteService) registry
    				.lookup("remoteService");
    		System.out.println("Currently using a JDK Dynamic Proxy: "
   			 + Proxy.isProxyClass(remoteServiceProxy.getClass()));
    		System.out.println(remoteServiceProxy.remoteOperation(new String[] {
    				"a", "b" }));
    	}
    }
```
 
    Auf dem Server starte ich die rmiregsirty mit folgendem Kommando:

```
C:\>rmiregistry -J-Djava.class.path=E:\eclipse\3.1.1\eclipse\workspace\de.tutorials.rmi\bin -J-Djava.rmi.server.hostname=192.168.76.98
```
    Ich teile der rmiregistry also mit, wo sie unsere Service Interfaces finden kann und dass ich sie
    explizit an das Network Interface mit der IP 192.168.76.98 binde.

    Nun starten wir den Server über:

```
E:\eclipse\3.1.1\eclipse\workspace\de.tutorials.rmi\bin>java de.tutorials.rmi.Bootstrap
```
 

    Anschließend starten wir den Client auf dem anderen Rechner:

```
c:\eclipse\3.1.1\eclipse\workspace\de.tutorials.rmi.client\bin>java de.tutorials.rmi.client.Client
```
 
    Nun erhalten wir eine ähnliche Ausgabe:
    Auf dem Server:

```
remoteOperation invoked @1135529217000 with arguments [a, b]
```
 
    und auf dem Client

```
Currently using a JDK Dynamic Proxy: true
    [a, b]
```
 
    ich hoffe dieses Beispiel hat gezeigt, wie man einfache RMI Anwendungen unter Java 5 ohne
    umständliche Generierung von ClientsStubs etc aufsetzen kann.

    Gruß Tom


----------



## Tsa (10. Januar 2006)

Hey Tom,
Super Tutorial 
Zusammen mit meinem Buch hab ich einigermaßen Begriffen wie man entfernte Objekte schreibt und aufruft. 
Jedoch habe ich noch ein kleines Problem mit dem rmic und der rmicregistry! 
Ich habe in der Classpath den Path zu dem bin meiner JDK.
Nun habe ich es geschafft mit rmic meine Implementation zu compilieren, jedoch weiß ich nicht wie ich mit der rmiregistry umgehen soll. Könntest du bitte nochmal näher erläutern zu was welcher Schritt gut ist und wie man es am sinnvollsten aufruft?
Bei mir läuft es zwar dann, aber er wirft mir immer eine Exception NotBoundException :| 
Ich nehme an ich mache etwas bei diesen Schritten in der Registry was falsch...
Vielen Dank schonmal 
Tsa


----------



## Gast (23. Juli 2009)

Hallo,

ich habe ein Problem mit der rmiregistry unter Linux (auf VServer).

starte RMI

$ rmiregistry &

- läuft ohne Probleme
- danach kann ich kein Java mehr starten/ausführen

$ java --version
Error occurred during initialization of VM
Could not reserve enough space for code cache

Wenn ich RMI wieder kille, dann geht Java wieder.

Vielleicht reicht ja ein Xmx für RMI, aber wie Pflege ich den Parameter ein?

Debian System, Speicher nicht voll, sun-java5-jre, root-Zugriff.

--------------------------------------------------------------------------------------------------------
java version "1.5.0_10"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03)
Java HotSpot(TM) Client VM (build 1.5.0_10-b03, mixed mode)
--------------------------------------------------------------------------------------------------------
Memory 	
17.9 MB 		6.35%
	264.6 MB 	282.5 MB
Disk Usage
Resource 	Used 	Free 	Total
Disk Space 	
746.74 MB 		36.46%
	1.27 GB 	2.00 GB
Disk Inodes 	
57,795 		28.90%
	142,205 	200,000
--------------------------------------------------------------------------------------------------------

Grüße
zui

P.S. auf meinem lokalen Ubuntu geht alles ohne Probleme


----------



## Thomas Darimont (23. Juli 2009)

Hallo,

ist das ein VServer den du da verwendest?

Wieviel memory hast du denn noch frei, wenn du die RMIRegistry gestartet hast?

Versuch mal die RMI Registry bzw. den anderen Java Prozess mit einer kleineren Heap / PermGen Einstellung zu starten, beispielsweise mit -Xmx16m -XXermSize=16m. 

Dann solltest du die andere JVM starten können.

Gruß Tom


----------



## Gast (24. Juli 2009)

Hi,

naja deine Fragen sind doch schon in meinem ersten Posting beantwortet. 

XmX hat nix gebracht, aber ich glaube es liegt an Java, scheinbar sind da ein paar Bibliotheken auf dem Server die quer schlagen, bzw. ein zweites JRE.

Ich suche da erstmal, denn lokal funktioniert alles wunderbar.

Eine andere Frage:

Ich möchte die Remote Interfaces in eine eigene JAR auslagern, damit Server und Client die einbinden können. Derzeit muss ich das ganze Server.jar noch mit in den Client nehmen.
Dummerweise sind da Daten drin, die im Client nix zu suchen haben.

Eigenes JAR und einbinden in Classpath wird schwierig da die rmiregistry als "-J-Djava.class.path=" die Klassen des Interfaces und der Services brauch. Oder kann ich da 2 Pfade, bzw. später 2 JARs angeben?

Grüße
zui


----------



## Gast (24. Juli 2009)

btw. Super Tutorial! RMI rockt! 

Grüße
zui


----------



## Sunbird (1. Dezember 2009)

Ist es auch möglich aus seinem ServerProjekt ein .jar File zu machen und dieses dann auf den Server zu legen und dort zu starten?

Irgendwie weiss ich nicht wie ich da ansetzen soll...

Über Hilfe bin ich wirklich dankbar.

Gruß
Sunbird


----------



## Steff1 (7. Dezember 2009)

Hallo,
ich versuche im Moment, die Registry und den Dienstanbieter auf verschiedenen Servern unterzubringen. 
Verschiedene Server sollen ihre Dienste bei der zentralen Registry eintragen können.
Es tritt aber eine AccessException auf, wenn man versucht, von extern ein Objekt zu binden.
Lösungsansätze, die ich bis jetzt gefunden habe gingen nur in die Richtung, bei dem zentralen Server einen Verweis auf die Registry des zuständigen Servers zu erfragen. 
Das wäre mir aber eigentlich zu umständlich, da bei jedem lookup ein eigentlich unnötiger Schritt gemacht werden müsste. 

Hat hier vllt. jemand eine Idee wie man diese Sicherheitsvorkehrung ausschalten kann?


----------

