# Java RMI - bitte ne kleine Einstiegshilfe



## emot (1. Nov 2004)

Hallo!
Also ich hab hier ein Java RMI Problem.

Ich muss eine Prüfungsverwaltung mittels Java RMI programmieren und steh hier schon mal ganz am Anfang an.

Die Server implementierung soll so aussehen das in dem Interface folgende Mehoden implementiert sind:


```
public interface PruefungsVerwaltung extends Remote {

public void pruefungAnlegen (Pruefung pruefung) throws RemoteException;
public Vector allePruefungenAusgeben () throws RemoteException;
public void studentAnmelden (String pruefungsName, Student student) throws RemoteException;
public void noteEintragen (String pruefungsName, String matNr, int note) throws RemoteException;
public int noteAusgeben (String pruefungsName, String matNr) throws RemoteException;
public Vector alleNotenAusgeben (String matNr) throws RemoteException;
public double notendurchschnittAusgeben(String matNr) throws RemoteException;
}
```

In muss nun 3 Klassen implementieren, eine PruefungsVerwaltungServerImpl Klasse mit der main methode und zusättzlich 2 klassen die "Pruefung" und "Student" heissen.
Das heisst ich implementieren eigentlich alle Methoden in diesen 2en?
Und wie greife ich dann von dem PruefungsverwaltungServerImpl dann drauf zu? 
Und im Client brauch ich dann eigentlich nurmehr die Methoden aufrufen nicht?
Hab mir das ca. so gedacht:

```
public class PruefungsVerwaltungServerImpl extends UnicastRemoteObject    
implements PruefungsVerwaltung {  
	
	public PruefungsVerwaltungServerImpl() throws RemoteException 
	{         
		super();    
	}
	
	public static void main(String args[]) { 
			String registryServer="";
		
			// use a Security Manager 
			if (System.getSecurityManager() == null) { 
				System.setSecurityManager(new RMISecurityManager()); 
			} 
		
			if (args.length == 1) {
				// get registryServer from command line arg
				registryServer = args[0];
			}
			else {
				try {
					// use local host as registryServer
					System.out.println("Using local host as registryServer.");            
					registryServer = InetAddress.getLocalHost().getHostName();
				}
				catch (java.net.UnknownHostException ex) {
					System.out.println("Failed to determine name of local host.");
					System.exit(1);
				}
			} 

			try 
			{
				// create instance of PruefungsVerwaltungImpl
				PruefungsVerwaltungServerImpl obj = new PruefungsVerwaltungServerImpl(); 
			
				// rebind obj in RMIRegistry on registryServer under the name
				// "PruefungsVerwaltungImpl" 
				Naming.rebind("//" + registryServer + "/" + "PruefungsVerwaltungImpl", obj); 
				System.out.println("Pruefungsverwaltung-Server bound in registry on " + registryServer); 
			} 
			catch (Exception e) 
			{ 
				System.out.println("PruefungsVerwaltungImpl err: " + e.getMessage()); 
				e.printStackTrace(); 
			} 
		}
	}
```

und dann für pruefung:


```
public class Pruefung extends UnicastRemoteObject  implements PruefungsVerwaltung 
{  
	
	public Pruefung() throws RemoteException 
	{         
		super();    
	}
	//	Varibalen für das Objekt Pruefung: Name der Prüfung (eindeutig), Beginn, Ende, Ort, Name des Prüfers
	 
	
	  private String myName;
	  private int myBeginn;
	  private int myEnde;
	  private String myOrt;
	  private String myNamePruefer;
	  
	  
	  //Hier der Konstrukter für ein Objekt vom Typ "Pruefung"
	  public Pruefung (String name, int beginn, int ende, String ort, String namePruefer)	 
	  {
	  myName = name;
	  myBeginn = beginn;
	  myEnde = ende;
	  myOrt = ort;
	  myNamePruefer = namePruefer;

	  }....

etc...
```

analog für student
muss ich dann auch für student und pruefung ein remote obj erzeugen?
und wie soll das aussehen?

Und noch ne kleine Frage: 
Gibts irgendein programm das es ermöglicht das RMI Ding einfach zu testen, ohne es mühsam zu compilieren und zu über einen server zu starten?

Bin für jede Hilfe dankbar, Grüße emot[/code]


----------



## Guest (1. Nov 2004)

Die Klassen 'Pruefung' und 'Student' brauchen/sollten das Interface 'PruefungVerwaltung' 
nicht implementieren, sondern nur 'java.io.Serializable' sein.
z.B.

```
public class Pruefung implements java.io.Serializable
```
Du kannst Dir eine Minimalimplementierung eines RMI-Servers erstellen und
neue "Service-Klassen" darin installieren.
Clientseitig wieder über einen einfachen Service-Locator (oder Proxy) darauf 
zugreifen.
Mach's aber am Anfang alles getrennt, damit Du den Umgang mit RMI lernst.


----------



## emo (1. Nov 2004)

Super, danke, okay, habe das korrigiert!

Nun implementier ich mal alle methoden, in "Pruefung" und "Student".
Dort habe ich ja 2 Konstruktoren.
Und im PruefungsverwaltungServerImpl erzeuge ich dann ein Pruefung, Student Obj?
Oder rufe ich den Konstruktor auf?

und vor allem wo, in der main methode wahrscheinlich nicht, also einfach in die Klasse?

Danke dir jedenfalls schon mal für die hilfe


----------



## Guest (1. Nov 2004)

Genau, die Klassen 'Pruefung' und 'Student' sind einfache Objekte,
die nur die Angaben zu Prüfungen und Stundenten enthalten.

Die Bussiness-Logik der ganzen Verwaltung steckt in der Implementierung
des Interface 'PruefungVerwaltung', also in 'PruefungVerwaltungImpl'.
In der Verwaltungsklasse stellst Du Methoden zur Verfügung, um die
zwei unterschiedlichen Sichten des Ganzen abzufragen. 
(Ist ja eine n:m Beziehung; Mehrere Studenten nehmen an mehreren Prüfungen teil)

- Prüfung und alle dazugehörigen Studenten abfragen
- Studenten einer Prüfung zuordnen bzw. sie abmelden
- Student und alle Prüfungen abfragen, zu denen der Student angemeldet ist
- etc.

Eine Instanz von 'PruefungVerwaltungImpl' wird dabei in RMI-Registry 'gebunden/exportiert'.

Du kannst es am Anfang so machen, dass Du clientseitig direkt 'PruefungVerwaltungImpl'
verwendest (gecastet auf 'PruefungVerwaltung'). 
Nur um die Benutzeroberfläche zu testen, ohne einen Server verwenden zu müssen. 
Klartext. Statt

```
PruefungVerwaltung pruefungVerwaltung = (PruefungVerwaltung)Naming.lookup("rmi://localhost/pruefungVerwaltung");
```
zuerst mal
	
	
	
	





```
PruefungVerwaltung pruefungVerwaltung = (PruefungVerwaltung)new PruefungVerwaltungImpl();
```

Danach stellst Du es auf die Serverversion um. Es sei dann, dass Du direkt auf irgendwelche 
Serverressourcen wie Datenbank auf "dem anderen PC" o.ä. angewiesen bist.
Der Vorteil ist, dass Du nicht jedesmal die Stubs generieren musst, wenn Du Änderungen
an den Serverklassen vornimmst.
Erst, wenn alles so läuft, wie es soll, wird's 'scharf' gestellt.


----------



## Guest (1. Nov 2004)

Noch eine Anmerkung zu dem oben.
Trenne am besten auch die RMI-Schicht von der Bussiness-Logik, damit diese auch austauschbar ist.
z.B.

```
/**
* Das Interface der Prüfungsverwaltung.
*/
public interface IPruefungVerwaltung
{
  public void addStudent(Student student) throws ApplicationException;
  ...
}

/**
* Die Implementierung der Schnittstelle der Prüfungsverwaltung.
*/
public class PruefungVerwaltungRMI extends UnicastRemoteObject implements Remote, IPruefungVerwaltung
{
  private PruefungVerwaltungImpl delegate = new PruefungVerwaltungImpl();
  ...
  public void addStudent(Student student) throws ApplicationException, RemoteException
  {
    // irgendein Preprocessing (Zeitmessung oder Transaction-Handling starten etc. )
    delegate.addStudent(student);
    // irgendein Postprocessing (Logging, Profiler-Logging, Transaction-Handling etc.)
  }
  ...
}

/**
* Die Implementierung der Prüfungsverwaltung.
*/
public class PruefungVerwaltungImpl implements IPruefungVerwaltung
{
  public void addStudent(Student student) throws ApplicationException
  {
    StudentValidator.checkAddStudent(student); // Prüfen der Daten
    StudentDB.addStudent(student); // Speichern der Daten
    ... etc.
  }
  ...
}
```
(ApplicationException ist irgendeine von Dir definierte Exception, die das Scheitern von addStudent signalisiert)
Zuerst mal ist nur das Interface und die reine Implementierung interessant.
Alles andere wird später mal drumherum eingebaut.


----------

