Lotus Notes / Domino Sonstiges > Java und .NET mit Notes/Domino
wann brauchen wir SOAP Webservices und wann nicht?
flaite:
Hi,
--- Zitat ---SOAP is something I put on my balls.
--- Ende Zitat ---
von Charles "cowboyd" Lowell aus Austin in Texas im DrunkAndRetired Podcast, Folge 85.
das ist wirklich keine dumme Aussage.
Viele sagen zur Zeit, dass SOAP für die meisten Fälle einen völligen overkill darstellt, obwohl es zugegebnermassen eine gute Tool-Unterstützung hat.
Meistens möchte man:
- Daten in xml packen.
- Diese Daten über http oder https an einen Server schicken
- vom Server xml als Antwort zurückbekommen
Nur wird heute die SOAP Spec als etwas kritisiert, bei der alles denkbare konfigurierbar sein soll.
Und genau das führt natürlich zu sehr viel Komplexität.
Das zur Zeit fortschrittlichste und einfachste SOAP Framework generiert aus diesem unschuldigen remote Kommunikationsinterface.
--- Code: ---package de.kingmedia.daw.bo;
import java.util.Date;
import java.util.List;
/**
* @author Axel
*
*/
public interface DiscountService {
String requestDiscount(String idOffer, String nameAgent, int discountReq, boolean urgency, String note);
DiscountRequest retrieveRequestDiscountResponse(String idOffer);
List <DiscountRequest> retrieveRequestDiscountListing(Date beginDate, Date endDate, String status);
}
--- Ende Code ---
dieses Monster-WSDL:
--- Code: ---<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://kingmedia.de/DiscountService" xmlns:tns="http://kingmedia.de/DiscountService" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope" xmlns:ns1="http://bo.daw.kingmedia.de" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc11="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenc12="http://www.w3.org/2003/05/soap-encoding" xmlns:soap11="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://kingmedia.de/DiscountService">
<xsd:element name="retrieveRequestDiscountResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="in0" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="retrieveRequestDiscountResponseResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="ns1:DiscountRequest"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="requestDiscount">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="in0" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in1" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in2" type="xsd:int"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in3" type="xsd:boolean"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in4" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="requestDiscountResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="retrieveRequestDiscountListing">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="in0" type="xsd:dateTime"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in1" type="xsd:dateTime"/>
<xsd:element maxOccurs="1" minOccurs="1" name="in2" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="retrieveRequestDiscountListingResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element maxOccurs="1" minOccurs="1" name="out" nillable="true" type="ns1:ArrayOfDiscountRequest"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://bo.daw.kingmedia.de">
<xsd:complexType name="DiscountRequest">
<xsd:sequence>
<xsd:element minOccurs="0" name="m_beginDate" type="xsd:dateTime"/>
<xsd:element minOccurs="0" name="m_discountAllowed" type="xsd:int"/>
<xsd:element minOccurs="0" name="m_discountReq" type="xsd:int"/>
<xsd:element minOccurs="0" name="m_history" nillable="true" type="ns1:ArrayOfDiscountRequest"/>
<xsd:element minOccurs="0" name="m_idAgreeement" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="m_idOffer" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="m_nameAgent" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="m_note" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="m_status" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="m_urgency" type="xsd:boolean"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ArrayOfDiscountRequest">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="DiscountRequest" nillable="true" type="ns1:DiscountRequest"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="requestDiscountResponse">
<wsdl:part name="parameters" element="tns:requestDiscountResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="retrieveRequestDiscountResponseResponse">
<wsdl:part name="parameters" element="tns:retrieveRequestDiscountResponseResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="retrieveRequestDiscountListingResponse">
<wsdl:part name="parameters" element="tns:retrieveRequestDiscountListingResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="requestDiscountRequest">
<wsdl:part name="parameters" element="tns:requestDiscount">
</wsdl:part>
</wsdl:message>
<wsdl:message name="retrieveRequestDiscountResponseRequest">
<wsdl:part name="parameters" element="tns:retrieveRequestDiscountResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="retrieveRequestDiscountListingRequest">
<wsdl:part name="parameters" element="tns:retrieveRequestDiscountListing">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="DiscountServicePortType">
<wsdl:operation name="retrieveRequestDiscountResponse">
<wsdl:input name="retrieveRequestDiscountResponseRequest" message="tns:retrieveRequestDiscountResponseRequest">
</wsdl:input>
<wsdl:output name="retrieveRequestDiscountResponseResponse" message="tns:retrieveRequestDiscountResponseResponse">
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="requestDiscount">
<wsdl:input name="requestDiscountRequest" message="tns:requestDiscountRequest">
</wsdl:input>
<wsdl:output name="requestDiscountResponse" message="tns:requestDiscountResponse">
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="retrieveRequestDiscountListing">
<wsdl:input name="retrieveRequestDiscountListingRequest" message="tns:retrieveRequestDiscountListingRequest">
</wsdl:input>
<wsdl:output name="retrieveRequestDiscountListingResponse" message="tns:retrieveRequestDiscountListingResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="DiscountServiceHttpBinding" type="tns:DiscountServicePortType">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="retrieveRequestDiscountResponse">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="retrieveRequestDiscountResponseRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="retrieveRequestDiscountResponseResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="requestDiscount">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="requestDiscountRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="requestDiscountResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="retrieveRequestDiscountListing">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="retrieveRequestDiscountListingRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="retrieveRequestDiscountListingResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="DiscountService">
<wsdl:port name="DiscountServiceHttpPort" binding="tns:DiscountServiceHttpBinding">
<wsdlsoap:address location="http://127.0.0.1:8080/DAWProto1/services/DiscountService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
--- Ende Code ---
Klar. Das wird von Tools generiert. Aber es führt eine Komplexität in die Sache ein, die für sehr viele Fälle gar nicht nötig ist.
Warum nicht einfach selbst
- ein bischen xml generieren
- das gegen den Server senden (geht seit Notes5 mit Java oder anderen Mitteln, aber nicht mit Vanilla LotusScript)
- der Server sendet als Response xml zurück, das der Client verarbeiten kann.
Sowohl auf Client als auch auf Server Seite ist das mit Lotus Notes möglich. Mit Hilfe von Java oder anderen Mitteln. Nicht aber mit Vanilla LotusScript.
In der Folge (nicht heute) wird die Möglichkeit einer Alternativ-Implementierung ohne SOAP mit Notes7 dargestellt.
Gruß Axel
flaite:
Proof of concept mässig geht das nämlich ohne dieses ganze SOAP Gedöns über HTTP.
Ich werd das noch full cycle ausarbeiten.
Das heisst:
Vom Notes Client wird mit Hilfe von LS2J und apache.jakarta.HTTPClient basierend auf (erstmal) basic authentification ein Post Request mit HTTP gegen einen Domino Server gesendet, der dann die gewünschten Daten ausliest und der dann xml zurückliefert. Das xml ist eingepackt in html. Ich werd aber in die nsf nicht die benötigten jakarta apache jars dazupacken, weil die zu groß sind. Müssen dann interessierte schon selber machen. Ich erklär dann auch wie.
Hier erstmal das (funktionierende) Proof of Concept.
Der LotusScript Notes Agent poxProducer (sendet das eingesendete xml einfach zurück, Verarbeitung muss noch programmiert werden):
--- Code: ---Sub Initialize
Dim s As New NotesSession
Dim doc As NotesDocument
Set doc = s.DocumentContext()
'Print "remoteUser=" + doc.Remote_User(0)
Print doc.Request_Content(0) ' hier stehen die per HTTP-POST Request eingesandten Daten drinnen.
End Sub
--- Ende Code ---
Webservice Requester: (aus einem Eclipse Projekt):
--- Code: ---package de.aja.http.client;
import java.io.IOException;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpMethodParams;
public class WebConnector {
HttpClient client = new HttpClient();
PostMethod method = null;
public void initClient(String userName, String pwd) {
// basic authentification :-)
client.getState().setCredentials(
new AuthScope(null, 80, null),
new UsernamePasswordCredentials(userName, pwd)
);
}
public void createMethod(String url) {
method = new PostMethod(url);
method.setDoAuthentication( true );
//method.addParameter("foo", "bar");
method.setRequestEntity(new StringRequestEntity("<foo><bar>value</bar></foo>"));
}
public String connect() {
try {
// set per default -> retries 3 times when recoverable error is thrown
client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
new DefaultHttpMethodRetryHandler());
client.executeMethod(method);
// nicht die feine englische ... for domino its simpler but to process a stream or byte (get.
return method.getResponseBodyAsString();
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
// release the connection
if (method!= null) {
method.releaseConnection();
}
}
}
}
--- Ende Code ---
Der client code von dieser Klasse sieht so aus (ein mit Junit geschriebener Integrationstest). Da ist ziemlich viel Eclipse generierter Boilerplate code dabei wichtig ist die Methode testConnect:
--- Code: ---package de.aja.http.client;
import org.apache.log4j.Logger;
import junit.framework.TestCase;
public class WebConnectorTest extends TestCase {
/**
* Logger for this class
*/
private static final Logger logger = Logger.getLogger(WebConnectorTest.class);
WebConnector cut = new WebConnector();
public WebConnectorTest(String arg0) {
super(arg0);
}
protected void setUp() throws Exception {
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
public void testConnect() {
cut.initClient("admin Axel", "voll_geheim");
cut.createMethod("http://127.0.0.1/PoxServer.nsf/poxProducer");
String res = cut.connect();
logger.debug("retrieved-->\n" + res);
}
}
--- Ende Code ---
ssl liesse sich auch locker einbinden.
flaite:
Welchen Sinn macht es, sich über einen POX Webservice von einem Notes Client mit einem Notes Server zu verbinden, wenn das doch total viel einfacher mit Standard Notes Mitteln geht ???
Nun wenn man per HTTP Daten von einem Notes Client mit einem Notes Server austauschen kann, dann kann man zum Bleistift:
a) den Client Part verwenden, um sich mit einer PHP Anwendung, einer Java Webserver Anwendung oder einer ASP.NET Anwendung oder whatever auszutauschen
UND
b) den Server Part verwenden, um Anfragen von einer PHP Anwendung, einer Java Anwendung einer DOT.NET Anwendung oder whatever zu bedienen.
Und das alles mit Authentifizierung, bei Bedarf SSL und OHNE SOAP.
Man hat also quasi alle Fälle in einem Beispiel ;D
flaite:
In der realen Welt hab ich das der Domino Seite in einem budgetierten pitch vorgeschlagen und der Kollege vom Partnerunternehmen war sehr zufrieden damit. Im Sinne von echt total sehr.
Sie werden euch sagen. Hört nicht auf Hassen i Sabbah mit seinen kahlen POX Webservices.
Wir haben SOAP. Das time, life, fortune Monopol mit kübelweise Liebe.
SOAP verwandelt Autobahnen in Bahngleise.
Und Bahngleise in Fahradwege.
Und Fahradwege in Kanäle.
Und Kanäle in Flüsse.
Und Flüsse in Bobbahnen.
Traut denen nicht. ;)
flaite:
Um das ein wenig zu relativieren. Wenn sich natürlich eure Organisation zu einem nachhaltigen SOA Ansatz commitet hat und es da auch Leute gibt, die konzeptionell und im technischen Betrieb mit Enterprise Service Bus und so Middleware wirklich umgehen können, dann ists was anderes. Ich kann das nicht und ich behaupte, dass es in vielen Organisationen auch keiner kann.
http://www.theserverside.com/news/thread.tss?thread_id=44639
Nur wenn die Leute dann auf Grund von Marketing-Gewäschen glauben, dass mit der Verteilung wär ja ein Kinderspiel und sowieso dank SOAP transparent, dann ist das einfach nicht wahr.
Wenns einfach nur darum geht ein paar PHP- or whatever Anwendung mit 'ner Notes-DB zu verbinden, ist SOAP unnötiger overkill, der einfach nur verbrannte Arbeit darstellt. Jede selbstrespektierende Web Plattform hat sowas wie jakarta HTTPClient, mit dem man einen HTTP Client quasi emulieren kann, um so Kontakt mit einem Server einer anderen Plattform Kontakt aufzunehmen. SOAP bringt da keine Vorteile.
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln