Der Einsatz von SOAP und WDSL am Beispiel von Limbas

Ein Fall für zwei
Kommentare

Mit SOAP ist es möglich, verschiedene Anwendungen über Schnittstellen miteinander zu integrieren und das unabhängig davon, welche Technologien und Programmiersprachen sie verwenden. WSDL vereinfacht unter anderem die Umsetzung von Clients, indem es z. B. die Generierung von SOAP-Requests ermöglicht. Da beide auf XML basieren, sind sie in Kombination sehr gut geeignet, um komplex strukturierte Daten wie Objekte oder Dokumente auszutauschen. Das wollen wir uns einmal genauer ansehen.

Es gibt gute Gründe, warum Unternehmen heute eine Vielzahl von stark differenzierten Anwendungen einsetzen. Wenn jede einzelne Anwendung auf ihrem Gebiet spezialisiert ist, bringt das in der Summe viele Vorteile. Auf der anderen Seite würde man sich natürlich auch eine Unternehmenssoftware wünschen, die alles am besten kann; auch wenn diese in der Realität nicht existiert. Denn häufig müssen verschiedene Anwendungen auf eine gemeinsame Datenbasis zurückgreifen oder gemeinsam übergreifende Geschäftsprozesse und Workflows umsetzen, was wiederum für einen hohen Integrationsaufwand verantwortlich ist.
Immerhin stellen Softwarehersteller – meistens über Middleware-Lösungen – Schnittstellen bereit, mit denen externe Anwendungen integriert werden können. Solche Schnittstellen werden heute häufig mit SOAP realisiert. In Verbindung mit SOAP hat sich der Standard WSDL etabliert.
In diesem Artikel wird die Funktionsweise von WSDL und SOAP am Beispiel von Limbas gezeigt. Limbas ist ein Open-Source-PHP-Framework, das für die Umsetzung von webbasierten Datenbankanwendungen, wie z. B. CRM, ERP, DMS geeignet ist.
Seit Version 2.6 ermöglicht es Limbas, über die WSDL-Schnittstelle grundlegende Datenbankoperationen durchzuführen.
Das für Demonstrationszwecke gedachte Limbas-CRM-System (Abb. 1) ist auf der Live-CD, VM-Version und dem Installationspaket enthalten. Es ist mit vielen Beispieldatensätzen gefüllt und daher gut geeignet, um Datenbankoperationen auf der WSDL-Schnittstelle mithilfe von SOAP-Clients durchzuführen. Dafür sind keine tiefergehenden Programmierkenntnisse notwendig. Abschließend wird gezeigt, wie über die Datenintegration von dem Limbas-CRM in Google Docs ein reales Anwendungsszenario für die WSDL-Schnittstelle umgesetzt werden kann.

Abb. 1: Das Limbas-CRM

WSDL

Die Web Service Description Language (WSDL) ist im Wesentlichen die Spezifikation eines XML-Schemas, das dazu gedacht ist, externe Schnittstellen von Anwendungen in XML zu definieren. Ein WSDL-Dokument enthält dazu die folgenden Informationen:

  • Ports/Endpoints: Adresse (URL) des Web Service, der die Schnittstelle bereitstellt.
  • Bindings: Funktionen, die ein Port besitzt und das Protokoll, das dieser einsetzt (i.d.R. SOAP).
  • Messages und (Complex) Types: Aufbau von Nachrichten zur Initiierung von Funktionsaufrufen und Definition der Parameter- und Rückgabewerttypen.

Limbas stellt für jede Datenbanktabelle eine separate, dynamisch erzeugte WSDL-Schnittstelle bereit. Diese folgen einem gängigen URL-Schema. So steht z. B. das WSDL-Dokument für die Tabelle Kunden hier bereit. Hierbei ist zu beachten, dass der Tabellenname mit großem Anfangsbuchstaben und im Folgenden klein geschrieben wird.
Aus der Port-Definition der Kunden-WSDL ergibt sich der URL der Web-Service-Schnittstelle wie folgt:

<wsdl:port name="KundenPort" binding="tns:KundenBinding">
<soap:address location="https://limbasurl/dependent/main_wsdl.php?Service=Kunden"/>
</wsdl:port>

Des Weiteren kann aus dem Binding entnommen werden, dass die WSDL-Schnittstelle als Protokoll SOAP verwendet (Listing 1).

<wsdl:binding name="KundenBinding" type="tns:KundenPortType">
  <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
  <wsdl:operation name="query">
    ...
  </wsdl:operation>
  <wsdl:operation name="getByPk">
    ...
  </wsdl:operation>
  <wsdl:operation name="delete">
    ...
  </wsdl:operation>
  <wsdl:operation name="insert">
    ...
  </wsdl:operation>
  <wsdl:operation name="update">
    ...
  </wsdl:operation>
  <wsdl:operation name="join">
    ...
  </wsdl:operation>
</wsdl:binding>

An dieser Stelle sollte noch erwähnt werden, das für SOAP verschiedene Styles existieren, die festlegen, wie ein Request aufgebaut sein muss (siehe Abschnitt „SOAP“). Limbas verwendet den RPC-Style, da dieser für den Entwickler am einfachsten zu handhaben ist.
Die WSDL-Schnittstelle stellt die Methoden query, getByPk, delete, insert, update und join bereit: Diese Funktionen ermöglichen das Abfragen, Löschen, Erstellen, Bearbeiten und Verknüpfen von Datensätzen in Limbas.
Ein besonderer Vorteil von WSDL ist die Möglichkeit, für Funktionen auch komplexe Typen als Parameter- und Rückgabewerte zu definieren, wie sie z. B. in der objektorientierten Programmierung oder für Datenbankschemas verwendet werden. Betrachten wir nun die Request und Response-Nachrichten, die von der Query-Funktion entgegengenommen bzw. zurückgegeben werden:

<wsdl:message name="queryRequest">
  <wsdl:part name="params" type="tns:KundenQuery"/>
</wsdl:message>
<wsdl:message name="queryResponse">
  <wsdl:part name="return" type="tns:KundenArray"/>
</wsdl:message>

Die Parameter eines queryRequest besitzen den Typ „KundenQuery„. Dieser ist wie in Listing 2 zu sehen aufgebaut.

<wsdl:types>
  <xsd:complexType name="KundenQuery">
    <xsd:sequence>
      <xsd:element name="q_orderby" type="xsd:string"/>
      <xsd:element name="q_page" type="xsd:string"/>
      <xsd:element name="q_rows" type="xsd:string"/>
      <xsd:element name="q_nolimit" type="xsd:string"/>
      <xsd:element name="ID" type="xsd:string"/>
      <xsd:element name="NAME" type="xsd:string"/>
      <xsd:element name="NAME_ZUSATZ" type="xsd:string"/>
      <xsd:element name="STRASSE" type="xsd:string"/>
      <xsd:element name="ORT" type="xsd:string"/>
      <xsd:element name="PLZ" type="xsd:string"/>
      <xsd:element name="LAND" type="xsd:string"/>
      ...
    </xsd:sequence>
  </xsd:complexType>
  <xsd:complexType name="...">
    ...
  </xsd:complexType>
</wsdl:types>

Eine Abfrage kann sich demnach auf beliebig viele Attribute der Kundentabellen beziehen (siehe auch Abschnitt „SOAP“). Außerdem kann das Ergebnis der Abfrage über folgende Parameter angepasst werden:

  • q_orderby: Die Datensätze können nach dem hier angegebenen Elementnamen sortiert werden.
  • q_rows: Gibt die Anzahl der Datensätze an, die pro Seite ausgegeben werden sollen. Standardmäßig sind dies dreißig.
  • q_page: Gibt die Seite/Seitenzahl der Datensätze an, die Limbas ausgeben soll.
  • q_nolimit: Falls dieser Parameter auf 1 gesetzt ist, gibt es keine Beschränkung in der Anzahl der abgefragten Datensätze.

Das Ergebnis der query-Funktion besitzt den Typ KundenArray. Er enthält die Elemente des Datensatzes.
Die Limbas-Rechteverwaltung ist vollständig in die WSDL-Schnittstelle integriert. Als Folge sind für einen Benutzer immer nur die Elemente eines Datensatzes sichtbar, auf die er autorisiert ist zuzugreifen. Entsprechend der Zugriffsrechte werden im WSDL-Dokument auch die Typen KundenQuery und KundenArray dynamisch erstellt.

Aufmacherbild: Two young Curious women listening through the wall. von Shutterstock / Urheberrecht: VGstockstudio

[ header = Seite 2: SOAP ]

SOAP

Mit SOAP können „Remote-Procedure-Calls“ über bestehende Netzwerkprotokolle wie z. B. HTTP durchgeführt werden. Der Standard basiert auf XML und ist deshalb offen, erweiterbar und plattformunabhängig. Aus diesem Grund wird SOAP häufig für die Umsetzung von externen Programmschnittstellen eingesetzt.
Mit dem Tool SoapUI (Abb. 2) können SOAP-Requests für die Limbas-WSDL-Schnittstelle auf einfache Weise generiert und ausgeführt werden. Es wird benötigt, um die folgenden Schritte durchzuführen.
Für die Einrichtung wird hierzu in SoapUI ein neues Projekt angelegt und das WSDL-Dokument für die Kundentabelle hinzugefügt. Um eine Datenabfrage umzusetzen, kann dann im Kunden-Binding die Funktion query ausgewählt und mit Rechtsklick ein neuer Request erstellt werden. Der SOAP-Request enthält nun ein Body-Element, in dem die Abfrageparameter angegeben werden (Listing 3).

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Kundenwsdl">
  <soapenv:Header/>
  <soapenv:Body>
    <urn:query soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <params xsi:type="urn:KundenQuery">
        <q_orderby xsi:type="xsd:string">?</q_orderby>
        <q_page xsi:type="xsd:string">?</q_page>
        <q_rows xsi:type="xsd:string">?</q_rows>
        <q_nolimit xsi:type="xsd:string">?</q_nolimit>
        <ID xsi:type="xsd:string">?</ID>
        <NAME xsi:type="xsd:string">?</NAME>
        <NAME_ZUSATZ xsi:type="xsd:string">?</NAME_ZUSATZ>
        <STRASSE xsi:type="xsd:string">?</STRASSE>
        <ORT xsi:type="xsd:string">?</ORT>
        <PLZ xsi:type="xsd:string">?</PLZ>
        <LAND xsi:type="xsd:string">?</LAND>
        ...
      </params>
    </urn:query>
  </soapenv:Body>
</soapenv:Envelope>

Abb. 2: SoapUI

Für jedes Attribut kann der Platzhalter „?“ durch einen Abfragewert ersetzt werden. Es ist auch möglich, Elemente aus der Query auszulassen. So wird z. B. eine Abfrage aller Kunden in Mannheim wie in Listing 4 dargestellt beschrieben.

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Kundenwsdl">
  <soapenv:Header/>
  <soapenv:Body>
    <urn:query soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <params xsi:type="urn:KundenQuery">
        <ORT xsi:type="xsd:string">Mannheim</ORT>
      </params>
    </urn:query>
  </soapenv:Body>
</soapenv:Envelope>

Bei der weit verbreiteten Kombination SOAP über HTTP (welche auch Limbas einsetzt) wird der in XML beschriebene Funktionsaufruf in einem HTTP-POST-Request an einen URL gesendet und von einem Web- oder Applikationsserver entgegengenommen.

Hinweis: Limbas setzt HTTP-Authentifizierung für SOAP-Requests voraus. In SoapUI müssen deswegen im Bereich „Request-Properties“ die Felder Username und Password gesetzt werden.

Auf den vorhergehenden Request zur Kundenabfrage würde Limbas alle gefundenen Datensätze in XML, wie in Listing 5 zu sehen, zurückgeben.

<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:Kundenwsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/">
  <SOAP-ENV:Body>
    <ns1:queryResponse>
      <return xsi:type="ns1:KundenArray">
        <items xsi:type="ns1:Kunden">
          <ID xsi:type="xsd:integer">6</ID>
          <NAME xsi:type="xsd:string">Blauer See Delikatessen</NAME>
          <NAME_ZUSATZ xsi:type="xsd:string"/>
          <STRASSE xsi:type="xsd:string">Forsterstr. 57</STRASSE>
          <ORT xsi:type="xsd:string">Mannheim</ORT>
          <PLZ xsi:type="xsd:string">68306</PLZ>
          ...
        </items>
      </return>
    </ns1:queryResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Limbas unterstützt auch Platzhalter in Abfragen. Hierzu kann das Zeichen „*“ als Wildcard an den Anfang und/oder an das Ende eines Suchbegriffs gestellt werden. Außerdem können die beiden logischen Operatoren UND und ODER jeweils mit den Zeichen „&&“ und „||“ verwendet werden. Das UND liefert die Schnittmenge der Datensätze, die alle Einschränkungen gleichzeitig erfüllen. Das ODER liefert im Gegensatz dazu die Vereinigungsmenge aller Datensätze, die zumindest jeweils eine der Einschränkungen erfüllen.
Wildcards und logische Operatoren sind im Allgemeinen für komplexere Abfragen notwendig. So können z. B. alle Kunden in den PLZ-Bereichen 6xxxx, 7xxxx, 8xxxx, 9xxxx mit dem Anfangsbuchstaben L und nach ihrem Name sortiert folgendermaßen abgefragt werden:

  <soapenv:Header/>
  <soapenv:Body>
    <urn:query soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
      <params xsi:type="urn:KundenQuery">
        <q_orderby xsi:type="xsd:string">NAME</q_orderby>
        <PLZ xsi:type="xsd:string"><![CDATA[6* || 7* || 8* || 9*]]></PLZ>
        <NAME xsi:type="xsd:string">L*</NAME>
     </params>
    </urn:query>
  </soapenv:Body>
</soapenv:Envelope>

[ header = Seite 3: Google-Docs-Datenintegration mit App Scripts und WSDL/SOAP ]

Google-Docs-Datenintegration mit App Scripts und WSDL/SOAP

Für die Limbas WSDL-Schnittstelle gäbe es denkbar viele Anwendungsfälle. Ein möglichst einfacher wäre der folgende: Will man einen Brief an einen Kunden senden und hat nur seine Kundennummer zur Hand, dann wäre es praktisch, aus der Textverarbeitung heraus mithilfe eines Skripts die Adresse automatisch in das Dokument einzufügen. In diesem Fall soll Google Docs als Beispiel eine Limbas-Datenintegration über WSDL dienen (Abb. 3).
Für Google Docs können eigene Erweiterungen in Google Apps Script – einer auf JavaScript basierenden Programmiersprache – implementiert werden. Die Besonderheit dabei ist, dass Skripte serverseitig ausgeführt werden. Als externes System kann Google Docs auf die Limbas Web-Service-Schnittstelle mit SOAP/HTTP-Post zugreifen.
Für viele Programmiersprachen stehen Bibliotheken zur Verfügung, mit denen der Zugriff auf eine Web-Service-Schnittstelle vereinfacht werden kann. Dies ist leider bei Google Apps Script nicht der Fall. Da aber bereits im Abschnitt „SOAP“ gezeigt wurde, wie ein SOAP-Request aufgebaut ist und mithilfe von SoapUI erzeugt werden kann, kann auch ein einfacher Client für die Abfrage selbst entwickelt werden.
Bei Google Docs können Skripte mithilfe des eingebauten Skripteditors entwickelt werden (im Kontextmenü unter TOOLS | SKRIPTEDITOR). Es ist auch möglich, die Skripte über eigene Kontextmenüs und Formulare in die Benutzerschnittstelle einzubinden. Das Google Doc mit dem fertigen Skript wird hier bereitgestellt.
In Listing 6 wird die Funktion zur Abfrage der Kundendaten über die WSDL-Schnittstelle gezeigt. Für die Umsetzung der Benutzerschnittstelle wird auf den vollständigen Quellcode des Google Doc verwiesen, der unter der zuvor genannten URL eingesehen werden kann.

function getCustomerAdress(kundennummer){
  // SOAP Request konstruieren
  var url="https://demo01.limbas.com/dependent/main_wsdl.php?Service=Kunden";
  var body= '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:Kundenwsdl">'+
    '<soapenv:Header/>'+
      '<soapenv:Body>'+
        '<urn:getByPk soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'+
          '<params xsi:type="xsd:long">'+kundennummer+'</params>'+
        '</urn:getByPk>'+
      '</soapenv:Body>'+
    '</soapenv:Envelope>';
  var httpUser="limbasUser";
  var httpPassword="limbasPassword";
  var options =
  {
    "headers" : {"Authorization": "Basic " + Utilities.base64Encode(httpUser + ":" + httpPassword), "Content-Type": "text/xml", "SOAPAction": "urn:Kundenwsdl#getByPk", "charset": "UTF-8"},
    "payload" : body,
    "method" : "post",
  };
  // SOAP Request senden
  var response = UrlFetchApp.fetch(url, options);
}

Abb. 3: Limbas in Google Docs

In den bereits zuvor für die KundenQuery generierten SOAP-Body wird die aus der Eingabemaske entnommene Kundennummer eingefügt. Dieser SOAP-Body wird dann als Inhalt des HTTP-Post-Requests mit der in Google App Scripts vorhandenen Funktion UrlFetchApp.fetch abgesendet. Dazu müssen nur noch die notwendigen HTTP-Header für SOAP und die bei Limbas notwendige HTTP-Authentifizierung ergänzt werden. Die Variable url ist spezifisch für eine Limbas-Installation und wird durch die im WSDL-Dokument unter dem Port des Kunden-Bindings angegebenen URL der SOAP-Schnittstelle ersetzt. Des Weiteren müssen die Variablen httpUser und httpPassword mit den Benutzerdaten von Limbas gesetzt werden. Ansonsten ist der Client auch schon fast fertig. Das Simple-Object-Access-Protokoll (SOAP) wird auf jeden Fall seinem Namen gerecht. Der SOAP-Response muss nun nur noch mithilfe eines XML-Parsers ausgewertet werden:

// SOAP Response parsen
  var document = XmlService.parse(response.getContentText());
  var root = document.getRootElement();
  var kunde = root.getChild("Body",  XmlService.getNamespace("http://schemas.xmlsoap.org/soap/envelope/")).getChild("getByPkResponse", XmlService.getNamespace("ns1","urn:Kundenwsdl")).getChild("return").getChild("items");
  var name=kunde.getChild("NAME").getValue();
  var strasse=kunde.getChild("STRASSE").getValue();
  var plz=kunde.getChild("PLZ").getValue();
  var ort=kunde.getChild("ORT").getValue();

Nachdem die einzelnen Adressbestandteile aus dem SOAP-Response entnommen wurden, können sie wieder zusammengesetzt und in das aktive Dokument geschrieben werden:

// Kundenadresse in aktives Dokument schreiben
var doc = DocumentApp.getActiveDocument();
var cursor=doc.getCursor();
if (cursor) 
  cursor.insertText(name + "n" + "n" + strasse +"n" + plz + " " + ort + "n" );

Fazit

Mit SOAP ist es möglich, verschiedene Anwendungen über Schnittstellen miteinander zu integrieren und das unabhängig davon, welche Technologien und Programmiersprachen sie verwenden, auf welchen Plattformen sie laufen und ob diese im lokalen Netzwerk oder über das Internet kommunizieren. WSDL vereinfacht unter anderem die Umsetzung von Clients, indem es z. B. die Generierung von SOAP-Requests ermöglicht. Da WSDL und SOAP auf XML basieren, sind sie in Kombination sehr gut geeignet, um komplex strukturierte Daten wie Objekte oder Dokumente auszutauschen. Nicht zuletzt durch die starke Anlehnung von XML-Schema an die objektorientierte Programmierung sind entsprechende Tools (wie Apache CXF) in der Lage, auf Basis eines WSDL-Dokuments den Quellcode für komplexe Server- und Clientschnittstellen in verschiedenen Programmiersprachen automatisch zu generieren und dadurch dem Entwickler viel Arbeit und Zeit zu übernehmen.
Limbas bietet nicht nur das Frontend, um große Datenbestände zu verwalten, sondern ermöglicht externen Anwendungen auch den Zugriff auf Daten über dynamische WSDL-Schnittstellen. Ein weiterer Vorteil für Entwickler ist, dass diese im Vergleich zu SQL wesentlich einfacher zu handhaben sind. Auch die Rechteverwaltung wurde hier integriert, sodass sichergestellt ist, dass Benutzer von außen nur nach Authentifizierung auf die Datenbanktabellen und die Elemente von Datensätzen zugreifen können, für die sie autorisiert wurden.
Für den Aufruf von verschiedenen Systemfunktionen, die für eine Prozessintegration notwendig wären, stellt Limbas derzeit zusätzlich noch eine umfangreiche SOAP-Schnittstelle bereit. In Zukunft soll diese Schnittstelle auch über WSDL standardisiert werden.

Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -