Netzprogrammierung: Java RMI - Remote Method Invocation (Teil 3) Robert Tolksdorf und Peter Löhr Überblick 1. Aktivierung und Deaktivierung von Objekten http://java.sun.com/javase/6/docs/technotes/guides/rmi/activation/overview.html Robert Tolksdorf und Peter Löhr 2 Aktivierung und Deaktivierung von Objekten Robert Tolksdorf und Peter Löhr Persistente Objekte Beachte: Ein fernaufrufbares Objekt braucht als „Träger“ eine aktive JVM - auch wenn es tagelang nicht aufgerufen wird. Wünschenswert: Persistente Objekte: ruhen meistens passiv im Dateispeicher und sind nur dann in einer JVM aktiv, wenn sie aktuell benutzt werden. Für die Benutzung müssen sie aktiviert werden, nach der Benutzung können sie deaktiviert werden. Robert Tolksdorf und Peter Löhr 4 Probleme Naiver Ansatz mit hypothetischem „persistenten Java“: Wurzelklasse Object verfüge über Methoden save und load ..... Mytype x, y; ..... x.save("myob"); ..... // Kopieren in Datei y = (Mytype) load("myob“); // Laden aus Datei ..... // Objekt hat normale Klasse: „Persistenzabstraktion“ Probleme: • • • • • Objektidentität ... vor allem bei Benutzung durch mehrere Prozesse Objektgeflechte (Transaktionen?) Speicherbereinigung entfernte Objekte?? Robert Tolksdorf und Peter Löhr 5 Persistenz in Java Reale Persistenz in Java: Java Persistence API: Objektspeicherung in relationalen Datenbanken mittels EJB 3.0 http://java.sun.com/developer/technicalArticles/J2EE/jpa/ Java RMI Object Activation: Persistente fernaufrufbare Objekte http://java.sun.com/javase/6/docs/technotes/guides/rmi/activation/overview.html Robert Tolksdorf und Peter Löhr 6 RMI Activation Framework • Aktivierung eines entfernten persistenten Objekts erfordert • das Hochfahren einer JVM am Ort des Objekts, die als Träger des aktiven Objekts dient (falls nicht schon vorhanden). Dies setzt wiederum voraus, dass am Ort des Objekts ein Prozess installiert ist, der den JVM-Prozess erzeugen kann: rmid (RMI daemon) ist das einschlägige Programm. • Der rmid-Prozess verwaltet für jedes lokal aktivierbare Objekt • einen Objektdeskriptor (activation descriptor), der die Lokalisierung von Code und Daten des Objekts erlaubt und über eine Objektkennung (activation identifier) identifiziert wird. (ActivationID --> ActivationDesc) Verzögerte Aktivierung (lazy activation) wird praktiziert: der Vertreter eines passiven Objekts ist so beschaffen, dass ein Aufruf nicht direkt zum Objekt, sondern zum RMI daemon führt. Dieser nimmt die Aktivierung vor und liefert dem Vertreter die Daten für die Lokalisierung des aktiven Objekts. Robert Tolksdorf und Peter Löhr 7 Beispiel Counter Wiederaufnahme des einfachen Beispiels Counter : package activation; import java.rmi.*; interface Counter extends Remote { int inc(int i) throws RemoteException; void deactivate() throws Exception; // erlaubt das Deaktivieren } package activation; import java.io.*; import java.rmi.*; import java.rmi.activation.*; class CounterImpl implements Counter { int c = 0; public int inc(int i) { return c += i; } // synchronization ignored ..... Robert Tolksdorf und Peter Löhr 8 Konstruktor für aktivierbare Objekte // Obligatorischer Konstruktor, bei Aktivierung eingesetzt. // id und info (hier ein Dateiname) kommen vom rmid. ..... ActivationID id; public CounterImpl(ActivationID id, MarshalledObject info) throws ... { this.id = id; // memoriert für spätere Deaktivierung String filename = (String) info.get(); // info-Objekt deserialisieren c = getState(filename); // lokale Hilfsmethode // Objektzustand aus Datei laden - siehe unten Activatable.exportObject(this, id, 0); // Objekt über das Aktivierungssystem // fernaufrufbar machen (vgl. RMI-1, S.21) } ..... Robert Tolksdorf und Peter Löhr 9 ..... ..... RandomAccessFile raf; int getState(String name) throws Exception { File file = new File(name); boolean newfile = ! file.exists(); raf = new RandomAccessFile(file, "rw"); return newfile ? 0 : raf.readInt(); } Nebenbei bemerkt: leider keinerlei Persistenzabstraktion ! Robert Tolksdorf und Peter Löhr 10 Deaktivierung ..... public void deactivate() throws Exception { raf.setLength(0); raf.writeInt(c); // Zustand wird in Datei gerettet raf.close(); Activatable.unexportObject(this, true ); // Objekt wird beim Fernaufrufsystem abgemeldet Activatable.inactive(id); // Objekt wird deaktiviert, ausführende // JVM wird beendet, falls dort keine weiteren // aktiven Objekte vorhanden } } // end class Robert Tolksdorf und Peter Löhr 11 ... und der Klient Der Klient wird z.B. mit java activation/Inc mycounter 10 aufgerufen und sieht so aus: package activation; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; public class Inc { public static void main(String[] arg) throws Exception { Registry registry = LocateRegistry.getRegistry(); Counter x = (Counter) registry.lookup(arg[0]); int i = x.inc(Integer.parseInt(arg[1])); // impliziert Aktivierung in neuer JVM! System.out.println("counter is " + i); x.deactivate(); // deaktiviert x und beendet die JVM } } Robert Tolksdorf und Peter Löhr 12 Einrichten eines aktivierbaren Objekts • Für die Aktivierung eines Objekts muss eine JVM bereitstehen • • • • bzw. bereitgestellt werden. Für die Konfigurierung dieser JVM müssen geeignete Properties vorgehalten werden. Die Konfigurierungsbeschreibung für die JVM wird als Gruppendeskriptor (activation group descriptor) bezeichnet (weil eine JVM für eine ganze Gruppe von aktivierbaren Objekten zuständig sein kann). Die Gruppendeskriptoren werden vom rmid verwaltet und dort über Gruppenkennungen (activation group identifiers) identifiziert (analog zu den Objektkennungen). Die Einrichtung eines aktivierbaren Objekts erfolgt hier mit einem separaten Programm Setup, z.B. so: java ... activation/Setup mycounter activation.CounterImpl count Optionen mnemonischer Name Robert Tolksdorf und Peter Löhr Objektklasse Zustandsdatei 13 Einrichten eines aktivierbaren Objekts package activation; import java.rmi.*; import java.rmi.activation.*; import java.rmi.registry.*; import java.util.Properties; public class Setup { // Argumente: Name Klasse Datei (des Objekts) public static void main(String[] args) throws Exception { String implClass = args[1]; // Objektklasse String implBase = System.getProperty("activation.impl.codebase"); // Codebasis der Klasse ..... Properties props = new Properties(); // für die Objektgruppe props.put("activation.impl.codebase", implBase); props.put("activation.file", arg[2]); props.put("java.security.policy", "group.policy"); props.put("java.class.path", "no_classpath"); Robert Tolksdorf und Peter Löhr 14 Einrichten eines aktivierbaren Objekts ..... ActivationGroupDesc groupDesc= new ActivationGroupDesc(props, null); ActivationGroupID groupID = ActivationGroup.getSystem(). registerGroup(groupDesc); // Gruppe registrieren beim Aktivierungssystem MarshalledObject data = new MarshalledObject(arg[2]); ActivationDesc desc = new ActivationDesc(groupID, implClass, implBase, data); Remote stub = Activatable.register(desc); // Objekt registrieren beim Aktivierungssystem LocateRegistry.getRegistry().rebind(arg[0], stub); } // Objekt registrieren beim Registry } // end class Setup Robert Tolksdorf und Peter Löhr 15 Richtliniendateien 2 Richtliniendateien werden benötigt: group.policy: legt fest, was die Objektgruppe darf grant codeBase "${activation.impl.codebase}" { // permission to read and write object's file permission java.io.FilePermission "${activation.file}","read,write"; // permission to listen on an anonymous port permission java.net.SocketPermission "*:1024-","accept"; // permission to connect to rmid for deactivation permission java.net.SocketPermission "*:1098", "connect,resolve"; }; Robert Tolksdorf und Peter Löhr 16 Richtliniendateien rmid.policy erlaubt dem rmid das Starten von JVMs mit den angegebenen Properties, wie bei class Setup vorgesehen: grant { // no codebase means any code permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.security.policy=${activation.policy}"; permission com.sun.rmi.rmid.ExecOptionPermission "-Djava.class.path=no_classpath"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dactivation.impl.codebase=*"; permission com.sun.rmi.rmid.ExecOptionPermission "-Dactivation.file=*"; }; Robert Tolksdorf und Peter Löhr 17 endlich: der Test Dateien für lokalen Test mit aktuellem Verzeichnis /home/user/act: $ ls * | more group.policy rmid.policy activation: Counter.class CounterImpl.class Inc.class Setup.class $ Robert Tolksdorf und Peter Löhr 18 endlich: der Test Lokaler Test mit aktuellem Verzeichnis /home/user/act: $ rmiregistry & [1] 6034 $ rmid -J-Djava.security.policy=rmid.policy \ -J-Dactivation.policy=group.policy & [2] 6035 $ java -Dactivation.impl.codebase=file:/home/user/act/ \ activation/Setup mycounter activation.CounterImpl count $ java activation/Inc mycounter 5 counter is 5 $ java activation/Inc mycounter 3 counter is 8 $ Robert Tolksdorf und Peter Löhr 19 Zusammenfassung Robert Tolksdorf und Peter Löhr Zusammenfassung • Aktivierbares Objekt • ist entweder aktiv • oder passiv, d.h. technisch nicht als Objekt vorhanden, • kann persistenten Zustand im Dateisystem halten • rmid • verwaltet aktivierbare Objekte • benötigt Richtliniendateien • rmiregistry registriert aktivierbare Objekte genauso wie normale Objekte • (offen geblieben: Speicherbereinigung, Fehlerdetails, ... ) Robert Tolksdorf und Peter Löhr 21 Literatur http://java.sun.com/javase/6/docs/technotes/guides/rmi/activation/overview.html Robert Tolksdorf und Peter Löhr 22