und SOAP-Schnittstellen fuer den WebCal

Werbung
CORBA-/RMI- und SOAP-Interfaces zu WebCal
Julius Benkert
April 2005
Inhaltsverzeichnis
1 Einleitung
1.1 Voraussetzungen
2
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.2 Überlegungen zum Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2 Kurzreferenz
2
2.1 Start der Server und Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
2.2 Veränderungen der Socket-Schnittstelle abbilden . . . . . . . . . . . . . . . . . .
3
3 Session-Management
3
3.1 Die WebCalSession-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4
3.2 Die WebCalSessionHandler-Klasse . . . . . . . . . . . . . . . . . . . . . . . . . .
4
4 Der Socket-Client
4
5 Die RMI-, CORBA- und SOAP-RPC-Schnittstellen
5
5.1 Kommunikation über RMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
5.2 Kommunikation über CORBA . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
5.3 Kommunikation über SOAP . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
1
1
Einleitung
Die vorliegende Dokumentation beschreibt Design, Implementierung und Verwendung der
CORBA-, RMI- und SOAP-Schnittstellen für den WebCal-Dienst.
1.1
Voraussetzungen
Alle Schnittstellen wurden auf Basis des J2SE SDK in der Version 1.5.0 03 entwickelt und getestet. Dieser kann bei Sun microsystems unter http://java.sun.com/ heruntergeladen werden.
Die SOAP-Schnittstelle erfordert das Vorhandensein bzw. die Installation weiterer Software, eine Auflistung und Installationsanweisungen finden sich zu Beginn des entsprechenden Kapitels.
Der Java-CLASSPATH muss um das Implementierungsverzeichnis erweitert werden.
1.2
Überlegungen zum Design
Um die Migration zwischen verschiedenen Interfaces sowie die Kommunikation zwischen Client
und Server so einfach wie möglich zu halten, wurde versucht, soweit wie möglich Unterschiede
beim Methodenaufruf und der Fehlerbehandlung zu vermeiden. Der Methodenaufruf sowie die
Rückgabewerte sind bei allen Schnittstellen identisch, lediglich schnittstellenspezifische Fehler
müssen bei einem Wechsel der Schnittstelle zusätzlich abgefangen werden.
Da derzeit von der Socket-Schnittstelle im Fehlerfall ausschließlich Textmeldungen
zurückgegeben werden, findet keine Unterscheidung von Fehlertypen statt. Alle Fehler der
Socket-Schnittstelle werden auf eine WebCalException aus dem Paket de.lmu.ifi.WebCal mit
der vom Socket-Server gelieferten Fehlermeldung abgebildet. Eine Ausnahme hiervon ist wegen
einer notwendigen Vererbung bei der CORBA-Schnittstelle notwendig — jeder WebCal-Fehler
führt hier zu einer WebCalException aus dem Paket de.lmu.ifi.WebCal.CORBA.
2
Kurzreferenz
Der folgende Abschnitt behandelt kurz die notwendigen Schritte für die Verwendung bzw.
Anpassung der Schnittstellen.
2.1
Start der Server und Clients
Um die Kommunikation über die verschiedenen Schnittstellen zu testen, stehen im Hauptordner
die Dateien ”startServers” und ”runClients” zur Verfügung. Beide Skripte sind für die Verwendung unter Linux in der Shell bash vorgesehen. Im Ordner Software steht für 586-kompatible
Computer die in den Voraussetzungen genannte Software zur Verfügung. Befinden sich die
2
notwendigen Pakete in andere Ordnern, müssen die jeweiligen Pfade im Skript ”setPaths” angepasst werden. Der zu verwendende Socket-Server wird ebenfalls in diesem Skript spezifiziert.
Das Skript ”setPaths” wird in den oben genannten Skripten importiert.
Der Start der Serverprozesse über das Skript ”startServers” erfolgt ohne Parameter.
Beim Start der TestClients über das Skript ’runClients’ kann ein Server-Host angegeben werden,
wird die Parameter nicht übergeben, werden die Anfragen an den localhost gestellt.
2.2
Veränderungen der Socket-Schnittstelle abbilden
Diese Kurzreferenz behandelt nicht alle Einzelheiten der Schnittstellen und sollte nur nach der
Lektüre der ausführlichen Beschreibung verwendet werden.
Um die RMI-, CORBA- und SOAP-Schnittstellen an eine geänderte Socket-Schnittstelle anzupassen, müssen einige Dateien im Implementierungs-Ordner verändert bzw. neu generiert
werden:
1. Datei de/lmu/ifi/WebCal/Socket/WebCalClient.java:
Der Client für die Socket-Kommunikation dient als Grundlage aller anderen Schnittstellen
und sollte daher als erstes angepasst werden. Die SOAP-Schnittstelle basiert auf dieser
Klasse, die Serverseite wird daher automatisch mitgeändert.
2. Datei de/lmu/ifi/WebCal/RMI/WebCalClient.java:
Java-Schnittstelle für die RMI-Kommunikation.
3. Datei WebCal.idl:
IDL-Definition der CORBA-Schnittstelle. Anschließend müssen die Java-Bindungen neu
generiert werden mit ”idlj -fallTie WebCal.idl”.
4. Datei de/lmu/ifi/WebCal/CORBA/WebCalImpl.java:
Klasse zur Abbildung der allgemeinen WebCalException auf die CORBA-spezifische.
5. Kompilieren der geänderten Dateien:
Bitte nicht vergessen, die geänderten Java-Klassen neu zu übersetzen.
6. Neustart aller Dienste:
Die Änderungen werden erst nach einem Neustart der Dienste wirksam.
7. Java-Bindungen für SOAP-Clients:
Mit dem Befehl ”java org.apache.axis.wsdl.WSDL2Java -p de.lmu.ifi.WebCal.SOAP url ”
werden die SOAP-Java-Bindungen neu generiert.
3
Session-Management
Im Laufe der Realisation hat sich gezeigt, dass durch die unterschiedliche Fähigkeiten und die
unterschiedliche Transparenz der jeweils verwendeten Basissoftware keine zuverlässige, produkt3
unabhängige Isolation der verschiedenen Sessions realisierbar ist. Um eine Bindung an je ein
bestimmtes Produkt zu vermeiden, muss deshalb von allen Clients explizit eine Session gestartet
werden. Die von der dafür vorgesehenen Funktion startSession zurückgegebene id muss bei allen
folgenden Anfragen als erster Parameter angegeben werden und bewirkt durch die Zuordnung
zu einem eigenen Socket eine garantierte, vollständige Trennung der Sessions.
3.1
Die WebCalSession-Klasse
Die Klasse de.lmu.ifi.WebCal.WebCalSession besteht hauptsächlich aus Instanzvariablen und
den dazugehörigen Getter- und Setter-Funktionen. Eine Ausnahme hiervon ist die Variable
lastUsage, mit deren Hilfe die Methode hasExpired(int timeoutSeconds) bestimmt, ob die
aktuelle Session abgelaufen ist. Häufig verwendete Sicherheitschecks können ebenfalls in die
WebCalSession-Klasse integriert werden. Als Beispiel hierfür dient die Methode isHostValid(String host), die prüft, ob der die Session initiierende Host bekannt ist und in diesem
Falle gleich dem im Parameter host angegebenen ist. Zur empfohlenen Integration mehr bei der
WebCalSessionHandler-Klasse.
3.2
Die WebCalSessionHandler-Klasse
Die Grundfunktionen zum Sessionmanagement sind zusammengefasst in der Klasse de.lmu.ifi.
.WebCal.WebCalSessionHandler. Die Methoden createSession, getSession und destroySession
regeln die Erstellung, den Zugriff sowie das Beenden einer Session.
Um abgelaufene, nicht regulär beendete Sessions zu terminieren, wird beim Aufruf der Methode
createSession die Methode purgeExpiredSessions aufgerufen.
Beim Zugriff auf eine Session mithilfe der Funktion getSession und der sessionId wird zunächst
die Funktion checkSession aufgerufen. Über den boolschen Rückgabewert kann die Zugriffsberechtigung des Clients überprüft werden. Da abhängig von der verwendeten Kommunikationsform Informationen über den Client in unterschiedlichem Umfang und über verschiedene Zugriffsmethoden zu erhalten sind, kann die jeweilige Prüfung abhängig von diesen Gegebenheiten
für jede Kommunikationsform separat implementiert werden. Ist die Prüfung erfolgreich, wird
der Zeitstempel der letzten Benutzung der Session aktualisiert und die Session zurückgegeben.
Eine Beispielimplementierung einer erweiterten checkSession-Funktion findet sich in der Klasse
de.lmu.ifi.WebCal.RMI.WebCalServer. Für die RMI-Schnittstelle wird hier mittels der Funktion isHostValid überprüft, ob der aktuell anfragende Host identisch ist mit jenem, der die
Session gestartet hat.
4
Der Socket-Client
Die eigentliche Client-Funktionalität für die Socket-Kommunikation ist in der Klasse de.lmu.
.ifi.WebCal.Socket.WebCalClient enthalten. Diese Klasse erweitert die Klasse WebCalSessionHandler. Die Funktionen startSession und endSession rufen die Sessionhandling-Funktionen des
4
WebCalSessionHandlers auf, erweitert diese jedoch um den Auf- bzw. Abbau der Socketverbindung. Beim Aufbau des Sockets wird zunächst die Begrüßungszeile des Servers von der Funktion
parseGreeting ausgewertet, anschließend stehen die Versionsinformationen des Servers über die
Methoden getWebCalVersion und getProtocolVersion zur Verfügung. Der zu verwendende Host
mit dem zugehörigen Port kann entweder direkt über den Konstruktor mit zwei Parametern
angegeben werden oder durch Setzen der System-Eigenschaften de.lmu.ifi.WebCal.Socket.host
und de.lmu.ifi.WebCal.Socket.port.
Sämtliche Anfragen, die nach dem Frage-Antwort-Schema ablaufen, werden mithilfe der Methode execRequest ausgeführt. Diese Methode wirft bei auftretenden Fehlern in der Kommunikation oder fehlerhaften Anfragen — erkennbar an einer Antwort, die mit der Zeichenkette
ERROR beginnt — die bereits bekannte WebCalException. Die öffentlichen Funktionen müssen
bei Verwendung dieser Methode nur noch den Anfrage-String erstellen und den Antwort-String
parsen.
Ein Unterschied gegenüber dem Protokoll der Socket-Kommunikation ergibt sich bei
überladenen Funktionen wie z.B. der WebCal-Funktion shift. Diese kann in ihrer einfachsten
Form ein Intervall um eine gegebene Zeitspanne verschieben, über ein oder zwei optionale Parameter kann aber auch eine Rundung des Ergebnisses vorgenommen werden. Um Probleme bzw.
kryptische, schnittstellenabhängige Funktionsnamen in Client-Programmiersprachen ohne die
Fähigkeit des Overloadings zu vermeiden, wurde im Socket-Client bei öffentlichen Funktionen
auf Überladen verzichtet und es wurden eindeutige Funktionsnamen vergeben. Im angegebenen
Beispiel lauten diese shift, shiftAndAdjust sowie shiftAndAdjustWithType.
Als Beispiel für die Verwendung dieser Client-Klasse dient die Klasse TestSocket. Beim Aufruf
von TestSocket mit den Parametern Host und Port des WebCal-Servers werden einige Anfragen
an der Server gestellt und die resultierenden Intervalle ausgegeben. Das Kommando hierzu
lautet:
java TestSocket host port
5
Die RMI-, CORBA- und SOAP-RPC-Schnittstellen
Alle drei Schnittstellen benutzen zur Kommunikation mit dem WebCal-Server direkt den eben
beschriebenen Socket-Client. Jede Schnittstelle ist als Activator realisiert, d.h. die ServerProzesse werden bei Client-Anfragen gestartet bzw. wiederverwendet. Im Falle von CORBA
ist die gleiche Funktionalität automatisch durch das Threadmanagement des ORBs gegeben.
Dieses Design gewährleistet, dass der Dienst selbst bei mehreren simultanen Zugriffen über die
gleiche Schnittstelle verfügbar bleibt. Wie bereits beim Sessionmanagement beschrieben findet
dabei keine eindeutige Zuordnung eines Server-Objekts zu einer Session statt, vielmehr kann ein
Server-Objekt abwechselnd mehrere Sessions bedienen und existiert nach deren Ende weiter.
5
5.1
Kommunikation über RMI
Für die Kommunikation über RMI wird zunächst das Interface de.lmu.ifi.WebCal.RMI.
.WebCalClient benötigt. Zu beachten ist, dass dieses Interface java.rmi.Remote erweitern muss
und alle Funktionen zusätzlich die Ausnahme RemoteException deklarieren müssen.
Anmerkung: Wegen eines relativen Pfades in einer Policy-Datei (mehr dazu gleich) müssen die
folgenden Befehle im Arbeitsverzeichnis Implementierung gestartet werden.
Die Zuordnung der Dienstnamen zu den Stubs (Server-Objekten) wird von der rmiregistry
übernommen. Diese wird gestartet mit:
rmiregistry &
Für das verwendete Activator-Prinzip muss vorab der RMI-Dämon rmid gestartet werden.
Dieser benötigt eine sogenannte Policy-Datei, die angibt, welche Berechtigungen und Voreinstellungen die vom RMI-Dämon verwendete Virtual-Machine und damit auch die gestarteten
Objekte besitzen sollen. Eine entsprechende Datei namens rmid.policy befindet sich im Ordner
Policies. Die eigentlichen Server-Prozesse werden erst bei Client-Anfragen vom rmid generiert.
Der Befehl zum Start des rmid lautet:
rmid -J-Djava.security.policy=../Policies/rmid.policy &
Im nächsten Schritt muss der RMI-WebCal-Service bei der rmiregistry angemeldet werden und
der rmid so konfiguriert werden, dass er beim Aufruf des Dienstes ein Server-Objekt generieren kann. Dies geschieht in der Klasse de.lmu.ifi.WebCal.RMI.WebCalActivator. Beim Aufruf
der Klasse muss die Systemeigenschaft de.lmu.ifi.WebCal.codeBase auf den Implementierungsordner als Basis für die Activation-Group gesetzt werden. Host und Port des Socket-Dienstes
werden als Parameter übergeben. Der Befehl lautet also wie folgt:
java -Dde.lmu.ifi.WebCal.codeBase=file:/pfadZurImplementierung /
de.lmu.ifi.WebCal.RMI.WebCalActivator host port
Im main-Teil des WebCalActivators werden zunächst die Properties gesetzt, mit denen anschließend die Activation-Group erstellt wird. Nachdem die Gruppe registriert wurde und die
aufzurufende Klasse spezifiziert ist, wird nun die ActivationDesc unter dem Namen ”WebCal”
in der rmiregistry eingetragen. Ab diese Zeitpunkt wird bei einer Anfrage für den WebCalDienst an die rmiregistry vom rmid ein neuer Stub generiert oder ein bereits vorhandener
wiederverwendet und dem Client zugewiesen.
Die Klasse TestRMI dient als Beispiel eines Clients und führt die gleichen Befehle aus wie
die TestSocket-Klasse, diesmal allerdings über RMI. Über die optionalen Parameter host bzw.
host und port kann die Adresse der zu verwendenden rmiregistry angegeben werden. Ohne
6
Parameter versucht TestRMI, die rmiregistry auf dem lokalen Rechner zu kontaktieren. Der
Aufruf erfolgt mit:
java TestRMI host port
5.2
Kommunikation über CORBA
Anders als bei RMI dient für die Kommunikation über CORBA kein Java-Interface sondern eine
Datei in der Interface-Definition-Language (IDL) als Dienstbeschreibung. Diese befindet sich im
Implementierungs-Verzeichnis unter dem Namen WebCal.idl. Zusammengefasst im Modul de.
.lmu.ifi.WebCal.CORBA wird die WebCalException sowie das Interface WebCalClient mithilfe
der IDL-Datentypen deklariert. Um keine unnötigen Einschränkungen beim Design hervorzurufen wird das Tie-Prinzip verwendet, d.h. die das IDL-Interface implementierende Klasse muss
keine bestimmte Klasse erweitern. Der IDL-to-Java Compiler generiert mit folgendem Befehl
die für Client- und Server-Implementierungen nötigen Java-Bindungen:
idlj -fallTie WebCal.idl
Bei der Generierung der Java-Bindungen stößt man auf das Problem, dass CORBA-Ausnahmen
die Klasse org.omg.CORBA.UserException erweitern müssen, die WebCalException des SocketClients allerdings ist hierfür nicht ausgelegt. Dieses Problem kann gelöst werden, indem entweder die allgemeine WebCalException die CORBA-UserException erweitert oder die WebCalException in einer Zwischenklasse abgefangen wird und in eine CORBA-spezifische Ausnahme umgewandelt wird. Die vorliegende Implementierung geht letzteren Weg um die anderen
Schnittstellen frei von CORBA-Klassen zu halten. Diese Zwischenklasse namens WebCalImpl
befindet sich im Paket de.lmu.ifi.WebCal.CORBA. Bei einer Veränderung des Interfaces muss
diese daher zusätzlich zur IDL-Datei angepasst werden.
Analog zum rmid bei RMI muss zunächst ein Dämon gestartet werden, der die Client-Requests
an einen entsprechenden Stub delegiert. Bei CORBA übernimmt der orbd diese Funktion. Standardmässig belegt dieser den Port 900, um Root-Rechte unnötig zu machen wird im Folgenden
allerdings abweichend Port 1060 verwendet. Der Befehl zum Start lautet:
orbd -ORBInitialPort 1060 &
Die Registrierung des Stubs beim orbd übernimmt die Klasse de.lmu.ifi.WebCal.
.CORBA.WebCalServer. Der Host und Port des socketbasierten WebCal-Servers muss über
die Systemeigenschaften de.lmu.ifi.WebCal.Socket.host und de.lmu.ifi.WebCal.Socket.port gesetzt werden. Nach der Aktivierung des ORBs und des RootPOA (sozusagen der Wurzel aller
PortableObjectAdapter) wird ein neues WebCalImpl-Objekt erzeugt. Mit dem Eingangs beschriebenen Tie-Mechanismus wird nun ein Objekt der automatisch generierten Klasse Web7
CalClientPOATie erzeugt, dessen Servant-Referenz anschließend im NamingService unter dem
Namen WebCal registriert wird. Der Aufruf erfolgt mit:
java -Dde.lmu.ifi.WebCal.Socket.host=host
-Dde.lmu.ifi.WebCal.Socket.port=port de.lmu.ifi.WebCal.CORBA.WebCalServer
-ORBInitialPort 1060 &
Der orbd leitet nun passende Anfragen von Clients an der WebCalServer weiter und übernimmt
auch das Threadmanagement, eine explizite Behandlung konkurrierender Zugriffe ist deshalb
nicht nötig.
Alternativ zum gerade beschriebenen Vorgehen wäre auch die Verwendung von Suns RMI
over IIOP möglich, Tests hiermit haben aber gezeigt, dass die resultierende IDL-Beschreibung
der Schnittstelle unnötig kompliziert ist und alle Java-spezifischen Vererbungen eins zu eins
abbildet. Um eine gute Portierbarkeit auf andere Programmiersprachen zu gewährleisten wurde
deshalb der eben beschriebene Weg gewählt.
Für diese Schnittstelle gibt es wiederum einen Beispielclient. Über die Optionen ORBInitialHost und -ORBInitialPort können Host und Port des ORBs gesetzt werden:
java TestCORBA -ORBInitialHost host -ORBInitialPort port
5.3
Kommunikation über SOAP
Als Grundlage für die Implementierung der SOAP-Schnittstelle dient serverseitig Axis für
Java, derzeit in der Version 1.2. Download sowie Dokumentation hierzu findet sich auf
den Seiten des Apache-Projekts unter http://ws.apache.org/axis/. Für den produktiven Einsatz sollte Axis in einem Servlet-Container wie z.B. dem Apache Jakarta Tomcat
(http://jakarta.apache.org/tomcat/) installiert werden, genaue Installationsanweisungen
für die jeweilige Systemumgebung sind ebenfalls unter den eben genannten URLs verfügbar.
Alternativ ist für den Entwicklungseinsatz ein einfacher, undokumentierter HTTP-Server in
Axis integriert, der aufgrund seiner einfachen Verwendbarkeit im Folgenden eingesetzt wird.
Für den Betrieb von Axis sind weitere Komponenten notwendig, derzeit sind dies ein JAXP1.1-konformer XML-Parser (z.B. Xerces für Java, http://xml.apache.org/xerces-j/) und
der
bei
Sun
entwickelte
Java
Web
Services
Developer
Pack
1.5
(JWSDP, http://java.sun.com/webservices/jwsdp/). Bei der Verwendung von Tomcat als
Application-Container muss außerdem das Java Activation Framework (JAF, momentan Version 1.0.2, http://java.sun.com/products/javabeans/glasgow/jaf.html ) verfügbar sein.
Das Verzeichnis ”Axis” ist bereits für den Start des Axis-Servers vorbereitet. Die Erweiterung
der Datei mit dem Java-Quellcode muss für eine Benutzung mit Axis ”jws” statt ”java” lauten.
Die in der Datei WebCalClient.jws definierte Klasse WebCalClient erweitert die WebCalClientKlasse für die Socket-Kommunikation, der Konstruktor mit Host- und Port-Angabe wird sicherheitshalber deaktiviert. Für die Ausführung der jws-Dateien notwendige Klassen werden
8
von Axis automatisch im Ordner jwsClasses gesucht. Da sich das Implementierungsverzeichnis
wie zu Beginn beschrieben bereits im CLASSPATH befinden sollte, stehen aber bereits alle
notwendigen Klassen zur Verfügung. Zusätzlich müssen allerdings noch einige Shell-Variablen
gesetzt und Pakete zum CLASSPATH hinzugefügt werden:
export AXIS HOME=pfadZuAxis
export JWSDP HOME=pfadZuJwsdp
for packagePath in $AXIS HOME/lib/*.jar
$JWSDP HOME/jwsdp-shared/lib/activation.jar
$JWSDP HOME/jwsdp-shared/lib/mail.jar; do
export CLASSPATH=$CLASSPATH:$packagePath
done
Anschließend kann nun im Arbeitsverzeichnis ”Axis” der SimpleAxisServer (im folgenden Beispiel auf Port 8080) gestartet werden mit:
java org.apache.axis.transport.http.SimpleAxisServer -p 8080
Zur Überprüfung des Dienstes bietet sich an, sich die WSDL-Definition des Socket-Clients durch
den Aufruf der Adresse http://localhost:8080/WebCal.jws?wsdl im Browser anzeigen zu
lassen. Um nun einen Java-Client für dieses Interface zu erstellen, kann man mit den Bordmitteln von Axis automatisch die nötigen Hilfsklassen erstellen. Im Ordner ”Implementierung”
muss hierzu lediglich das Tool WSDL2Java aufgerufen werden, die Option -p legt dabei den
Namen des Zielpakets fest:
java org.apache.axis.wsdl.WSDL2Java -p de.lmu.ifi.WebCal.SOAP
http://localhost:8080/WebCalClient.jws?wsdl
Analog zu den anderen Schnittstellen ist die Klasse TestSOAP ein Beispiel für die Verwendung
der generierten Klassen in einem Java-Client. Beim Aufruf muss als Parameter die URL des
WebServices übergeben werden, für das bisherige Beispiel lautet der Befehl:
java TestSOAP http://localhost:8080/WebCalClient.jws
9
Herunterladen