Lotus Notes / Domino Sonstiges > Java und .NET mit Notes/Domino

wann brauchen wir SOAP Webservices und wann nicht?

<< < (2/4) > >>

flaite:
Als nächstes werde ich mich ein wenig auf den Server Part konzentrieren, der als LotusScript implementiert ist.
Also: Der Agent bekommt die String Darstellung eines xml Dokuments rein und schickt die String Darstellung eines xml-Dokuments raus.
Das in-Dokument wird mit NotesXMLSaxParser geparsed.
Das out-Dokument wird mit NotesXMLDOMParser generiert.
Aber dazu später.
Scheint aber zu funktionieren.

flaite:
Ich hab mir überlegt, das auch der client als Lotus Notes Agent implementiert wird. Das ist realistischer. LS2J bringt ein paar wenige Komplexitäten mit sich, die für das Beispiel nicht nötig sind.
Wenn ihr in der realen Welt den Client für einen Webservice, der z.B. mit einer php Anwendung kommuniziert, dann werdet ihr das am wahrscheinlichsten in einem Agenten machen.

Was soll jetzt der Webservice inhaltlich tun. Stock Quotes wie sonst immer  ??? Nein.  ;D
Ich implementiere das als Math-Service für simple Rechenoperationen mit beliebig vielen Termen (spelling?), Klammern aber ohne Division. Auf vielen Blogs (z.B. bileblog, basicthinking) wird man heute schon mit solchen Fragen als spamschutz konfrontiert.
Z.B.:

--- Zitat ---Berechne [zehn] + [neun](ohne Taschenrechner)

--- Ende Zitat ---
Der business Nutzen des Webservice ist zugegeben nicht sehr hoch, aber als Beispiel sehr brauchbar.
 
Die einzelnen wiederverwendbaren Teile werden so aussehen. Das ist ein highlevel Überblick über die einzelnen Teile des POX Webservice.

ClientServer1. Client liest Daten aus einem Notes Dokument und erzeugt daraus ein xml Dokument (Java) 2. Client sendet das erzeugte xml Dokument per HTTP an den Server (Java) 3. Server nimmt xml entgegen (LotusScript Agent) 4. Server parst das xml mit der SAX API und erzeugt daraus Datenstruktur für die Weiterverarbeitung (LotusScript)5. Server verarbeitet die Daten und generiert daraus seinerseits xml, das an den Client zurückgeschickt wird (mit LotusScript print statements) 6. Client parst seinerseits das vom Server zurückgesendete xml mit der SAX Api (Java) und erzeugt daraus aplikationsspezifische Datenstrukturen als Ergebnis7. Client schreibt das Ergebnis in das Notes Dokument
Das auszutauschende xml wird etwa diese Struktur haben (Beispiel):
client sendet an server:

--- Code: ---<?xml version="1.0"?>
<math-in>
<number parentesis="left">8</number>
<operator>+</operator>
<number parentesis="right">2</number>
<operator>*</operator>
<number>4</number>
</math-in>

--- Ende Code ---

server sendet zurück:

--- Code: ---<?xml version="1.0"?>
<math-out>
40
</math-out>

--- Ende Code ---

flaite:
Julian Robichaux sieht es übrigens genau so wie ich:
POX oder REST Webservices sind für eine Menge Fälle die bessere und einfachere Lösung:
http://www.nsftools.com/blog/blog-03-2007.htm#03-11-07 (s. Kommentare).

flaite:
Jeder der in dem Posting [20.03.07 - 07:04:28] beschriebenen Schritte besitzt einen definierten Input und einen definierten Output. Sie sind sehr unabhängig voneinander programmier- und testbar:

Schritt
InputOutput1. Client erzeugt das zu sendende xml Dokument
Notes Maske, Dokumente etc. xml Dokument als String2. Client sendet das xml Dokument an den Server
xml Dokument als Stringxml Dokument gepackt in ein HTTP-Post Request auf dem Server3. Server wandelt das einkommende xml Dokument in einen String um
HTTP Post Request, in dem ein xml-Dokument gepackt istxml Dokument als String4. Server parst das xml in eine Datenstruktur
xml Dokument als StringDatenstruktur in LotusScript (hier wirds erstmal ein Array aus Types sein)5. Server macht etwas mit der Datenstruktur (Businesslogik)
Datenstruktur in LotusScricptxml Dokument als String gepackt in eine ausgehenden HTTP-Response6. Client empfängt zurückgesendete xml Dokument und macht damit etwas (Businesslogik)
xml Dokument Ergebnisse in Client Programm

Die einzelnen Schritte funktionieren unabhängig voneinander. Das ist ein großer Vorteil von Webservices. Die einzelnen Schritte lassen sich in beliebiger Reihenfolge oder sogar paralell entwickeln. Ich fang hier mit Punkt 4 an.

flaite:
Im Agent "poxServer" der unten angehängten Datenbank ist  Punkt "4. Server parst das xml in eine Datenstruktur" mit SAX Parsing implementiert. Als LotusScript. Die SAX-API eignet sich sehr gut, um xml zu lesen. Man kann damit nicht xml schreiben oder editieren. Die SAX-API wurde in sehr vielen Programmiersprachen implementiert. Wenn man SAX-Parsing in LotusScript kann, ist es ein kleiner Schritt das auch in C#, Java, C++, Ruby oder was auch immer zu beherrschen.

SAX ist eine eventgesteuerte API. Man kann sich das so ähnlich vorstellen wie Lotus Notes ein Dokument verarbeitet. Öffnest du ein xml Dokument im Notes Client, dann werden:
Eine Menge Maskenevents aufgerufen (QueryOpen, PostOpen) und die Formeln der einzelnen Felder von links oben nach rechts unten werden berechnet.
So ähnlich verhält es sich mit dem Handler eines xml Parsers.
Es gibt verschiedene Events, die man anmelden kann. Zum Beispiel:

--- Code: ---On Event SAX_StartDocument from saxParser Call SAXStartDocument
On Event SAX_StartElement From saxParser Call SAXStartElement
On Event SAX_Characters From saxParser Call SAXCharacters
On Event SAX_EndElement From saxParser Call SAXEndElement

--- Ende Code ---
Die komplette Liste findet ihr irgendwo in der Notes Designer Dokumentation.

Im Parsingprozess werden dann die angemeldeten Unterroutinen aufgerufen.
(z.B. Sub SAXEndElement (Source As Notessaxparser, Byval ElementName As String))
Also das ist ein xml Dokument:

--- Code: ---<?xml version="1" encoding="UTF-8"?>
<math-in>
<number parentesis="left">8</number>
<operator>+</operator>
<number parentesis="right">2</number>
<operator>*</operator>
<number>4</number>
</math-in>

--- Ende Code ---
Der SAX Parser geht das von oben bis unten durch und ruft bei definierten "Stellen" angemeldete Subroutinen auf. Er macht das automatisch. Wir müssen nur auf ihn in den angemeldeten Subroutinen reagieren.
 
Mit den oben Beispielhaft angegebenen Events, sieht das so aus:
1. Parsing beginnt-> Ruft Call SAXStartDocument auf.
2. kommt an den öffnenden Tag <math> -> Ruft SAXStartElement auf
3. Kommt an den öffnenden Tag <number> -> Ruft SAXStartElement auf
4. Findet Text zwischen den öffnenden und schliessenden Tags <number> und </number>-> Ruft SAXCharaters auf.
5. Findet den schliessenden Tag </number> -> Ruft SAXSEndElement auf
3. Kommt an den öffnenden Tag <operator> -> Ruft SAXStartElement auf
4. Findet Text zwischen den öffnenden und schliessenden Tags <operator> und </operator>-> Ruft SAXCharaters auf.
5. Findet den schliessenden Tag </operator> -> Ruft SAXSEndElement auf

Und so weiter. Bis zum letzten schliessenden Tag </math>

Nun gibt es z.B. in den <number> tags Attribute. Was ist damit?
<number parentesis="left">
Nun die einzelnen angemeldeten Event-Subroutinen besitzen definierte Parameter.
Zum Beispiel:

--- Code: ---Sub SAXStartElement (Source As Notessaxparser,_
Byval elementname As String, Attributes As NotesSaxAttributeList)
...
End Sub

--- Ende Code ---
In jedem Subroutinenaufruf von SAXStartElement wird
a) der Name des Tags als String übergeben (bei <math> wäre das math.
b) die Attribute des Tags als NotesSaxAttributeList übergeben, wobei NotesSaxAttributeList ein einfaches LotusScript Objekt ist. In der angehängten Datenbank könnt ihr euch anschauen wie das genauer verarbeitet wird.

Es ist zugegeben ein bischen gewöhnungsbedürftig, aber zum Lesen von xml Dokumenten ist die SAX Api oft einfacher als die DOM-Api oder traditionelles String-Parsing. Und zwar bedeutend.         

Ich beschreibe jetzt noch ein wenig konkrete Implementierung des Agenten poxParser in der angehängten Datenbank:

Der Agent holt sich von der Funktion getStrMockIn() as String ein XML-Dokument als String zum Testen. Dieser String wird in einen NotesStream geladen (sehr einfach)

--- Code: ---Set stream = session.CreateStream
stream.WriteText(strIn)

--- Ende Code ---
Dann wird die Funktion

--- Code: ---Function xmlProcessIn (streamIn As NotesStream) As Variant

--- Ende Code ---
aufgerufen, die das SAXParsing steuert.
Das eigentlich SAXParsing findet dann in

--- Code: ---Class MySaxContentHandler

--- Ende Code ---
in den Declarations statt.

Ein Objekt dieser Klasse wird von xmlProcessIn erzeugt. Der Konstruktor

--- Code: ---Sub new (streamIn As NotesStream)

--- Ende Code ---
wird aufgerufen. Dort wird ein saxParser as NotesSAXParser Objekt erzeugt, die events werden angemeldet.

--- Code: ---Sub new (streamIn As NotesStream)
' the data to be retrieved later is saved here
Redim Preserve mathElem(0)


Set sAXParser = session.CreateSAXParser(streamIn)

' the events to be observed during parsing. calls the subroutines below.

On Event SAX_StartElement From saxParser Call SAXStartElement
On Event SAX_Characters From saxParser Call SAXCharacters
On Event SAX_EndElement From saxParser Call SAXEndElement

On Event SAX_Error From saxParser Call SAXError
On Event SAX_FatalError From saxParser Call SAXFatalError
On Event SAX_Warning From saxParser Call SAXWarning
End Sub

--- Ende Code ---
von xmlProcessIn wird dann als nächstes der ParsingProzess gestartet.

xmlProcessIn:

--- Code: ---Set instMySaxContentHandler = New MySaxContentHandler(streamIn)
instMySaxContentHandler.process

--- Ende Code ---

In Class MySaxContentHandler:

--- Code: ---Function process () As Variant
saxParser.process
End Function

--- Ende Code ---
Die Kontrolle geht nun auf den SAXParser über. Er ruft nun die angemeldeten Event-Funktionen Call SAXStartElement, Call SAXCharacters, etc auf, sobald er während des Parsens von oben nach unten auf ein entsprechendes "Event" "stösst" (z.B. öffnender Tag, Text zwischen öffnenden und schliessenden Tags, schliessender Tag, etc).

In den aufgerufenen Subroutinen wird nun ein Array des ebenfalls in den Declaration definierten Types Math Element erzeugt

--- Code: ---Type MathElement
name As String
attribute As String
value As String
End Type

--- Ende Code ---
In der Instanz der Klasse MySaxContentHandler ist dieser Array eine Public Member-Variable:

--- Code: ---Class MySaxContentHandler
Public mathElem() As MathElement
[...]

--- Ende Code ---

Hat der SAXParser sämtliche Elemente von oben nach unten durchgearbeitet fällt die Programmkontrolle wieder zurück auf die oben erwähnte Function xmlProcessIn zurück, die den Parsing Prozess angestossen hat. Diese Funktion gibt dann noch die Werte des Arrays mathElem aus.

--- Code: ---For i= 1 To Ubound(instMySaxContentHandler.mathElem())
currentMathElement = instMySaxContentHandler.mathElem(i)
'Msgbox instMySaxContentHandler.arrValues(i), MB_ICONINFORMATION, instMySaxContentHandler.arrKeys(i)
strDebug = strDebug & Chr$(13) & Chr$(10) & |MathElement(| & Cstr(i) & |)-->name="| & currentMathElement.name &_
|" value="| & currentMathElement.value & |" attribute="| & currentMathElement.attribute & |"|
'& |"|

Next

Msgbox strDebug, MB_ICONINFORMATION, "result"

--- Ende Code ---

Interessierte sollten einfach den Agenten mal ausprobieren.

Das war Schritt 4:
4. Server parst das xml in eine Datenstruktur   
Input: xml Dokument als String   
Output: Datenstruktur in LotusScript (hier wirds erstmal ein Array eines Types sein)

Nicht für jeden der angesprochenen Schritte muss so viel Code geschrieben werden.
Gruß Axel

Navigation

[0] Themen-Index

[#] Nächste Seite

[*] Vorherige Sete

Zur normalen Ansicht wechseln