Hi,
wichtiger Hinweis: Ich bemühe mich, verständlich zu bleiben. Nur ist es schwierig jedes Detail von Operationen wo ich nicht selber immer ganz genau weiss was ich da gerade tue haarfein zu erklären. Sollte Interesse bestehen und Unklarheiten auftauchen, bitte eine Frage posten.
thx Axel
nachdem ich nun erfolgreich eine Version von Domino 7 installiert habe, versuche ich mich an Domino Webservices.
Hier ist z.B. ein ganz sinnvoll aussehendes Tutorial:
http://www-128.ibm.com/developerworks/edu/i-dw-ls-domino7ws-i.html
(die IBM ID erhält man, indem man sich registriert, keine Kosten, keine Probleme).
1. Wofür gibt es Webservices?
Was mir zunächst auffällt ist, dass die Einführungssektion "What are Webservices" ein paar Lücken hat.
Man findet Sätze wie
The basic components of Web services are based on a series of technology standards.
Hier ein Versuch einer ein bischen allgemeinverständlicheren Definition:
Die Idee hinter Webservices besteht darin, dass man verschiedenste Internetprotokolle und Standards für den Austausch von Daten zwischen Computern verwendet.
Die traditionelle Interaktion mit dem Internet sieht so aus:
Ein Mensch bedient einen Browser und kommuniziert damit mit einem Programm auf einem Webserver.
Die Idee hinter Webservices ist, dass sich Programme austauschen können. Und zwar Programme unterschiedlichster Plattformen. Ich versuche z.B. jetzt mit einem Java1.5 Programm auf einen Domino-Webservice zuzugreifen. Python, Perl, Objective C, Assembler, C++, C#, Ruby, Ruby on Rails uvam ginge aber auch.
Webservice ist also wieder so eine weitere Integrationsgeschichte wie z.B. COM/OLE. Irgendwie vergleichbar auch mit Remote Procedure Calls (RPC) über die z.B. der Domino Client mit dem Domino Server interagiert.
Hier liegt vielleicht auch ein psychologische Verständnishürde. Bei Web denkt man unwillkürlich an Frontend/User Interface Technlogien wie html, css oder dhtml. Webservices ist aber eine Backendtechnologie für Systemintegration.
Webservices ist so etwas wie COM. Nur wird die ausgetauschte Information nicht in binärer Form enkodiert sondern als Text als xml.
2. Lotus favorisiert unter den verschiedenen Webservice Standards SOAP
Lotus favorisiert als Webservice Standard den sogenannten SOAP Standard. Dieser Standard wurde vor allem auf Grund der Komplexität kritisiert. Es existieren konkurrierende Standards wie z.B. die REST-Architektur oder Hessian & Burlap. But wait: Komplexität heisst hier nicht unbedingt, dass es für den Entwickler kompliziert wird. Es ist Tradition bei SOAP, dass die komplexen Deskriptoren-Dateien wie z.B. die WSDL Dateien von Tools erzeugt werden (so ist das auch bei Lotus Notes 7). Zumindest mit Webservices des Typs RPC bekommt man als Entwickler noch nicht einmal xml zu sehen.
Auch wenn man als Anwendungsentwickler vielleicht erstmal nichts von der Komplexität mitbekommt, wirkt sie sich natürlich aus. SOAP gilt aufgrund der hohen internen Komplexität als im zweifelsfall nicht besonders performant. Für viele Anwendungsfälle kann es aber ausreichend sein und attraktiv dürfte v.a. der reichhaltige Tool-Support sein.
Eine andere Stelle, an der die unterliegende Komplexität ihren hässlichen Kopf erhebt sind Datentypen, va. komplexere. Wenn ein Microsoft.NET Client von einem Lotus Webservice Daten in Form eines Lotus Datentypen List erhält, weiss der MS-NET Client vielleicht nicht, wie er diesen Datentyp zu verstehen hat. Komplexere Datentypen sind aber teilweise von Lotus SOAP konform definiert worden. Aber das hat natürlich Grenzen. Z.B. wird sowas noch viel komplexeres wie Notes-Document niemals in SOAP definiert.
UDDI ist erstmal nicht so wichtig.
3. Kurzes Beispiel (serverseitig)
Erstmal teste ich mit verschiedenen im Java Umfeld vorhandenen dedizierten Webservice Testtools, ob ein Zugriff auf Domino Webservices mit Java möglich ist und wenn ja, welche Probleme auftreten.
In einer realen Anwendung wird man diese Testtools selbst nicht einbinden. Aber sie benutzen dieselben openSource Komponenten, die man bei seinen eigenen auf Webservices zugreifenden Java Code auch verwenden wird (jakarta-axis).
Später erstelle ich noch eine kleine Swing-Gui als reale Mini-Beispielanwendung. Vielleicht auch eine Web-Anwendung auf Tomcat.
Wie sieht jetzt so ein Webservice aus. Im Tutorial ist ein Beispiel. Ich hab auch eins.
Es ist eigentlich alles ganz einfach.
Man kann als Webservice scheinbar nur Klassen verwenden. Ist aber nicht so schlimm. Hier ist die Klasse.
Class Land
Private ses As NotesSession
Private db As NotesDatabase
Private vwLand As NotesView
Public Sub New
Set ses = New NotesSession()
Set db = ses.currentDatabase
Set vwLand = db.getView("land")
End Sub
Public Function getHauptstadt (land As String) As String
Dim docLand As NotesDocument
Set docLand = vwLand.GetDocumentByKey(land)
If docLand Is Nothing Then
getHauptstadt = "LAND <" & land & "> kann in der Datenbank nicht gefunden werden."
Else
getHauptstadt = docLand.Hauptstadt(0)
End If
End Function
End Class
Dann gibt es noch in der Eigenschaftenbox 3 Tabs die man füllen kann:
Im ersten Tab gibt man den Namen und den Namen der Klasse an.
Der 2. Tab enthält Security Zeugs wie "run on behalf of" und Security Levels. Um mich selber nicht zu verwirren habe ich das offenste Security Level und run on behalf of Server gewählt.
Der 3. Tab ist ein bischen komisch. Man kann dort Messaging Model und Message Format wählen. Ich habe mich für RPC/encoded und RPC entschieden. Ich vermute stark, dass man für die anderen Typen mehr eigene xml-Programmierung braucht.
Unten sind dann noch 3 seltsame Felder "Port Type Name", "Service Element" und "Service Port Name". Das sind Grüße von der komplexen SOAP Spezifikation und diese Felder werden beim ersten Speichern automatisch gefüllt.
Man kann das ganze speichern.
Dann gibt es noch oben WSDL buttons (import/show/export). Dieses WSDL wird automatisch generiert. Ich versuche damit später mit dem jakarta axis 1.0 Paket einen Client zu generieren.
Dort kann nämlich - soweit ich mich erinnere - aus einem WSDL File automatisch die Zugriffs-Klassen für diesen Webservice generiert werden.
Das WSDL (Webservice description Language) File ist länger als die Klasse selber, aber na gut. Lotus hat es generiert. Normal finde ich das nicht.
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:DefaultNamespace" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<wsdl:message name="GETHAUPTSTADTResponse">
<wsdl:part name="GETHAUPTSTADTReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="GETHAUPTSTADTRequest">
<wsdl:part name="LAND" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="Land">
<wsdl:operation name="GETHAUPTSTADT" parameterOrder="LAND">
<wsdl:input message="impl:GETHAUPTSTADTRequest" name="GETHAUPTSTADTRequest"/>
<wsdl:output message="impl:GETHAUPTSTADTResponse" name="GETHAUPTSTADTResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DominoSoapBinding" type="impl:Land">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GETHAUPTSTADT">
<wsdlsoap:operation soapAction="GETHAUPTSTADT"/>
<wsdl:input name="GETHAUPTSTADTRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:input>
<wsdl:output name="GETHAUPTSTADTResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="LandService">
<wsdl:port binding="impl:DominoSoapBinding" name="Domino">
<wsdlsoap:address location="http://localhost"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Der Soap Standard wurde von Microsoft und IBM gemeinsam entwickelt.
Vermutlich wollten die sich gegenseitig mit irgendwelchen coolen Spec-Features übertrumpfen, die kein Mensch nachvollziehen kann.
Jedenfalls brachte jetzt der mitgelieferte Testclient des Webtools Projekt von Eclipse die Rettung (die Webservices Abteilung von WSAD ist ähnlich).
Ich hab einfach das von Domino generierte wsdl file in diesem Tag ein bischen erweitert (
<wsdl:service name="LandService">
<wsdl:port binding="impl:DominoSoapBinding" name="Domino">
<wsdlsoap:address location="http://localhost/webservices/FirstTest.nsf/FirstTest?openWebservice"/>
</wsdl:port>
</wsdl:service>
(interessierte mögen das mit oben vergleichen.
Dann ein eclipse (3.1) mit installierten Web Tools Platform Plug-ins.
Einfach das wsdl reinimportieren.
Rechte Maustaste auf das wsdl. Webservice / Test with webservice explorer.
Und voila. Man kann sich da dann durchklicken. Man bekommt ein Ergebnis und poppt auch noch unten ein netter Monitor auf, der die ausgetauschten SOAP Messages anzeigt (von Byte auf xml wechseln).
Offenbar hat sich in den Webservices unter Domino 7 seit den Beta Releases auf denen sich das Tutorial bezieht einiges geändert. Probiere weiter.
Die Response Zeit von 4.5 Sekunden bestätigt sämtliche meine Vorurteile gegen SOAP. Jedoch ist natürlicher dieser von Eclipse Web Tools Platform generierte Client wohl auch sehr inperformant.
(vergl. Rückgabe mit Klasse Land oben:
Zeile:
getHauptstadt = "LAND <" & land & "> kann in der Datenbank nicht gefunden werden."
Das Tool (s. Screenshot) finde ich Klasse, zumindest wenn man das nicht jeden Tag ist.
Ganz oben in Navigation kann man navigieren und Testwerte einfügen.
Im Panel Status wird der Rückgabewert angezeigt.
Unten sieht man die ausgetauschten Soap Messages.
Eclipse hat die linke geschickt und Domino hat die rechte zurückgesendet.
bleib weiter am Ball.
Axel
1 Maschine. Tomcat läuft standardmässig auf port 8080, Domino auf 80.
Wichtig ist Eclipse mit Webtools Plattform Plugin.
Das wtp-all-in-one-0.7 auf dieser Seite (da ist eclipse dabei).
http://download.eclipse.org/webtools/downloads/drops/R-0.7-200507290654/
Das zip vermutlich einfach nur auspacken.
wtp-all-in-one-0.7-win32.zip(md5)
Ein JSDK 1.4 sollte installiert sein.
Und Tomcat. Ich hab Tomcat 5 genommen.
http://tomcat.apache.org/download-55.cgi#5.0.28 (für windows user die windows executable. Ist ein einfaches Installationsskript dabei.
In Eclipse muss noch Tomcat angemeldet werden.
Erste Aktion in Eclipse:
File / New Project / Dynamic Web Project. In dem Dialog advanced Klicken und dort kann man Tomcat eintragen (Target Server drop down).
Dem Projekt muss dann noch ein beliebiger Name gegeben werden (ohne Leerzeichen).
Dann File / Import und im Eclipse Menü auf das vorher aus Domino exportierte .wsdl File. In das Projekt.
Die Änderung im WSDL ist absolut notwendig.
Sieht so aus:
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:DefaultNamespace" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="urn:DefaultNamespace" xmlns:intf="urn:DefaultNamespace" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="">
<wsdl:message name="GETHAUPTSTADTResponse">
<wsdl:part name="GETHAUPTSTADTReturn" type="xsd:string"/>
</wsdl:message>
<wsdl:message name="GETHAUPTSTADTRequest">
<wsdl:part name="LAND" type="xsd:string"/>
</wsdl:message>
<wsdl:portType name="Land">
<wsdl:operation name="GETHAUPTSTADT" parameterOrder="LAND">
<wsdl:input message="impl:GETHAUPTSTADTRequest" name="GETHAUPTSTADTRequest"/>
<wsdl:output message="impl:GETHAUPTSTADTResponse" name="GETHAUPTSTADTResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DominoSoapBinding" type="impl:Land">
<wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GETHAUPTSTADT">
<wsdlsoap:operation soapAction="GETHAUPTSTADT"/>
<wsdl:input name="GETHAUPTSTADTRequest">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:input>
<wsdl:output name="GETHAUPTSTADTResponse">
<wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:DefaultNamespace" use="encoded"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="LandService">
<wsdl:port binding="impl:DominoSoapBinding" name="Domino">
<wsdlsoap:address location="http://localhost/webservices/FirstTest.nsf/FirstTest?openWebservice"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
Dann einfach rechte Maustaste auf das WSDL File und Webservices / Test with Webservices Explorer.
Im WSDL file wird in Eclipse ein Fehler angezeigt. Scheint aber nicht zu stören.
Ich such dann noch nach einer Möglichkeit den Client Code einfach als Java Code zu erzeugen. Ich kann das dann mit Ant oder Maven Build Umgebung posten. Dann werden die Pakete automatisch runtergeladen. Kann aber noch ein paar Tage dauern.
Diese Eclipse WTP Geschichte ist sehr WSAD/Rational Developer ähnlich.
WSDL: Geändert ist wie gesagt der untere Tag.
<wsdlsoap:address location="http://localhost/webservices/FirstTest.nsf/FirstTest?openWebservice"/>
Notes erzeugt:
<wsdlsoap:address location="http://localhost"/>
Und das funktioniert nicht. (Imho kann das nicht funktionieren = bug).
Mein Fehler. Ich weiss nicht wie ich das mit den Eclipse WTP Tools anders machen soll als eine lokale Kopie der WSDL Datei zu laden. Wie unten zu sehen ist, funktioniert alles, sobald man das WSDL File per Url anspricht: In meinem Fall ist das: http://localhost/webservices/FirstTest.nsf/FirstTest?WSDL
Im WSDL Element erzeugt WTP immer dieses name="" Attribut. Keine Ahnung warum. Stört aber wie gesagt nicht.
Axel
Der Zugriff geht über Web Tools Platform auf Eclipse auch mit
1. Projekt - Web - Dynamic Web Project
2. Server auswählen (Tomcat sollte auf Rechner installiert sein. Es gibt noch "Generic Versions" von verschiedenen Servern u.a. Websphere und Bea Weblogic, hab aber auf eigenes Vertraut).
3. Web Services - Web Services Client
4. Eclipse fragt dann nach der WSDL. Man muß dafür die Domino URL angeben. In meinen Fall ist das: http://localhost/webservices/FirstTest.nsf/FirstTest?WSDL
5. Eclipse erzeugt dann 5 Klassen und deployed sie in einem Tomcat Projekt. Auf der Web Tools Platform Oberläche liegen sie im Source-Ordner Java Source.
6. Tomcat kann gestoppt werden (falls er läuft).
6. In die Klasse *Proxy Klasse (in meinem Fall LandProxy) muß unten die folgend static main hinzugefügt werden.
public static void main (String [] args) {
try {
System.out.println(new LandProxy().GETHAUPTSTADT("Chile"));
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
7. Klasse einfach starten.
8. Axis meldet erst - Unable to find required classes (javax.activation.DataHandler and javax.mail.internet.MimeMultipart). Attachment support is disabled.
Das ist eigentlich kein Fehler sondern eine Warnung, die hier auch fehlplaziert ist.
9. ... und dann das Ergebnis.
Werd das mal ein bischen ausarbeiten und noob-freundlich machen.
Jedenfalls ist das möglicherweise eine ganz attraktive Möglichkeit, um Daten zwischen Domino und Java Umgebungen (als Beispiel) auszutauschen.
Hier ein sehr einfacher Client seitiger Webservice von Notes, der einen Service aufruft, der 20 min. verzögerte Aktienkurse zurückgibt.
Sub Initialize
Const urlWSD = "http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl" ' This is the URL of the server hosting this web service
Dim result As Double
Dim stockSymbol As String ' liste: http://stocks.tradingcharts.com/stocks/symbols
'Create a new MSSOAP client object
Dim client As Variant
Set Client =CreateObject("MSSOAP.SoapClient")
'Initialize connection to the WSDL file and get WSDL structure
Call Client.mssoapinit (urlWSD)
stockSymbol = "IBM"
' calling the SOAP function
result = Round(Client.getQuote(stockSymbol), 2)
'output result to message box
Messagebox result, 48, "20 min verzögerter Aktienkurs von " & stockSymbol
End Sub