Start PageIntegration von WebServices in AS/400 Anwendungen
Schnittstellen zwischen unterschiedlichen Anwendungen sind immer wieder eine
Herausforderung, insbesondere wenn unterschiedliche Rechner Technologien
beteiligt sind. Sind diese rein asynchron wird dies meistens durch
standardisierte Formate abgebildet, EDI ist hierbei ein Beispiel für einen
nahezu allen bekannten Standard. Wenn vor dem Bezug einer Datenübertragung
eine Anforderung mit der Spezifizierung der gewünschten Daten
benötigt, oder eine unmittelbare Antwort erwartet, dann ist das mit
asynchronen Methoden nicht oder nur mit Einschränkungen abbildbar. Was
dann benötigt wird, ist ein Programmaufruf auf einem anderen Rechner
inklusive Parameter Übergabe und Rückgabe, wobei die
Parameterschnittstellen oft auch Variabilitäten beinhalten. Auch für
diesen Fall haben sich Standards herausgebildet, IBM setzt hier traditionell
auf MQ Series, das für alle Plattformen des Herstellers angeboten wird, im
AS/400 Bereich aber keine besondere Rolle spielt, da werden eher noch Beta
Tester gesucht. Mit CORBA wurde versucht da einen offenen Standard zu setzen,
der aber auf der AS/400 nicht unterstützt wird, da dies für IBM eine
Mainframe Domäne darstellt.
In der Java Welt sind hier Enterprise Java Beans als Standard etabliert, dies
wird zwar auf allen relevanten Plattformen unterstützt, ist aber nur in
Java implementierbar. Was Java hat, darf Microsoft nicht fehlen und so hat man
für .NET WebServices vorgesehen, die sich mittlerweile als
übergreifender Standard etabliert haben und spätestens seit sie von
Java unterstützt werden erste Wahl für funktionale Schnittstellen
darstellen.
Was sind WebServices ?
Web Services werden ähnlich wie HTML Seiten über das Internet
transportiert, aber im Unterschied zu diesen nicht von Menschen mit einem
Browser angesehen, sondern dienen zur Kommunikation zwischen Programmen.
Hiermit stellen sie die Grundlage automatisierbarer Dienste dar und können
sowohl öffentlich über das Intranet, oder intern im Intranet oder VPN
eingesetzt werden. Die Grundlagen von WebServices sind Hersteller
übergreifend
standardisiert mit den Spezifikationen SOAP (Simple Object Access Protocol),
WSDL (Web Services Description Language) und UDDI (Universal Description,
Discovery and Integration), die alle auf XML basieren. Die zentrale Komponente
ist dabei die WSDL Beschreibung, die in XML Notation einen verfügbaren
Service
und dessen Bedienung beschreibt. Jeder WebService benötigt eine solche
Beschreibung, um ihn zu publizieren und wenn man einen WebService verwenden
will, benötigt man diese WSDL zur Implementierung des Zugriffs. SOAP
regelt den
Transport der Nachrichten, die für einen WebService ausgetauscht werden und
beschreibt dabei die Verpackung, Adressierung und den Versand einer Nachricht;
der eigentliche Transport erfolgt meistens über HTTP oder alternative
Möglichkeiten. Mit UDDI beabsichtigt man eine Art Telefonbuch für WebServices bereit zu stellen. Ohne WSDL und SOAP kann man weder einen
WebService bereit stellen, noch nutzen, UDDI ist eine optionale
Möglichkeit und
damit auch weniger verbreitet, es geht ja auch ohne.Ein kleines Beispiel
Es gibt mittlerweile eine ganze Reihe von öffentlich verfügbaren
WebServices,
die sich auch hervorragend zum testen eignen. Um ein wenig ein Gefühl zu
vermitteln, was da auf einen zukommtmöchte ich mal exemplarisch ein kleines
Beispiel zeigen. Bei dem Beispiel handelt es sich um einen WebService, der
für
größere Städte die Wetterdaten liefert. Ausgangspunkt ist dabei
immer die WSDL,
die ich hier (hoffentlich fehlerfrei) auf den verwendeten Aufruf gekürzt
habe, im richtigen leben ist diese Beschreibung des recht einfachen Web
Services um einiges umfangreicher. <wsdl:definitions xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:tns="http://www.webserviceX.NET"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
targetNamespace="http://www.webserviceX.NET" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
<wsdl:types>
<s:schema elementFormDefault="qualified" targetNamespace="http://www.webserviceX.NET">
<s:element name="GetWeather">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="CityName" type="s:string"/>
<s:element minOccurs="0" maxOccurs="1" name="CountryName" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
<s:element name="GetWeatherResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetWeatherResult" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
</s:schema>
</wsdl:types>
<wsdl:message name="GetWeatherSoapIn">
<wsdl:part name="parameters" element="tns:GetWeather"/>
</wsdl:message>
<wsdl:message name="GetWeatherSoapOut">
<wsdl:part name="parameters" element="tns:GetWeatherResponse"/>
</wsdl:message>
<wsdl:portType name="GlobalWeatherSoap">
<wsdl:operation name="GetWeather">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
Get weather report for all major cities around the world.</wsdl:documentation>
<wsdl:input message="tns:GetWeatherSoapIn"/>
<wsdl:output message="tns:GetWeatherSoapOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:portType name="GlobalWeatherHttpGet">
<wsdl:operation name="GetWeather">
<wsdl:documentation xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">
Get weather report for all major cities around the world.
</wsdl:documentation>
<wsdl:input message="tns:GetWeatherHttpGetIn"/>
<wsdl:output message="tns:GetWeatherHttpGetOut"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="GlobalWeatherSoap" type="tns:GlobalWeatherSoap">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="GetWeather">
<soap:operation soapAction="http://www.webserviceX.NET/GetWeather" style="document"/>
<wsdl:input>
<soap:body use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="GlobalWeather">
<wsdl:port name="GlobalWeatherSoap" binding="tns:GlobalWeatherSoap">
<soap:address location="http://www.webservicex.net/globalweather.asmx"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions> |
Zur Anforderung von Wetterdaten wird ein Soap Request an den WebServer
gesendet, der der Beschreibung der WSDL genügen muss und den
gewünschten Aufruf adressiert, sowie die Parameter enthält. In dem
vorliegenden Beispiel werden die aktuellen Wetterdaten von Frankfurt
angefordert, wobei dei Parameterschnittstelle sehr einfach gehalten ist, da
lediglich der Ort und das Land übergeben werden.<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:q0="http://www.webserviceX.NET"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<q0:GetWeather>
<q0:CityName>Frankfurt</q0:CityName>
<q0:CountryName>Germany</q0:CountryName>
</q0:GetWeather>
</soapenv:Body>
</soapenv:Envelope> |
Als Antwort kommt dann wieder ein SOAP Dokument zurück, das die Antwort in
dem in der WSDL beschriebenen Format enthält. Auch die Antwortparameter
sind relativ einfach gehalten, es werden eine feste Menge an Wetterdaten
zurück gegeben. Die WDSL ist da wesentlich mächtiger, da könnten
auch Listen, gestaffelte oder geschachtelte Strukturen, oder auch Grafiken als
Anhänge als Übergabe- oder Rückgabeparameter auftreten.<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<GetWeatherResponse xmlns="http://www.webserviceX.NET">
<GetWeatherResult> <?xml version="1.0" encoding="utf-16"?>
<CurrentWeather>
<Location>Frankfurt / M-Flughafen, Germany (EDDF) 50-03N 008-36E 113M</Location>
<Time>Feb 04, 2010 - 10:50 AM EST / 2010.02.04 1550 UTC</Time>
<Wind> from the NNE (020 degrees) at 6 MPH (5 KT):0</Wind>
<Visibility> greater than 7 mile(s):0</Visibility>
<Temperature> 42 F (6 C)</Temperature>
<DewPoint> 39 F (4 C)</DewPoint>
<RelativeHumidity> 86%</RelativeHumidity>
<Pressure> 29.91 in. Hg (1013 hPa)</Pressure>
<Status>Success</Status>
</CurrentWeather>
</GetWeatherResult>
</GetWeatherResponse>
</soap:Body>
</soap:Envelope> |
Anforderungen zur Integration von WebServices
WebService aufrufen
Häufig ist die erste Konfrontation mit WebServices die, dass ein bereits
existierender WebService in eine vorhandene Applikation eingebunden werden
soll. Ausgangspunkt ist dann die in WSDL Form vorliegende Beschreibung des
WebServices. Gerade der Anfänger (und manchmal nicht nur dieser) ist in
dieser Situation bereits überfordert davon aus dieser Beschreibung zu
entnehmen wie dieser Service bedient werden soll. Für Java und .NET
Umgebungen kann man hier Unterstützung bekommen, so kann der Java
Programmierer hier auf das Open Source Framework AXIS 2 zurück greifen,
das in Zusammenhang mit entsprechenden Plugins in Eclipse aus einer WSDL Datei
ein Java Rahmenprogramm generiert, das bereits fertige aufrufbare Methoden
für jeden Service der entsprechenden WSDL enthält. Dabei stellt AXIS
2 einen defacto Standard dar, der weitgehend sicherstellt, dass dieser
Mechanismus für alle Konstellationen fehlerfrei funktioniert und bei
Problemkandidaten findet man zumeist leicht per Websuche eine Lösung. AXIS
generiert dabei auch die benötigten Schnittstellenobjekte, sodass der
Programmierer sich nicht mit zu sendenden XML Dokumenten und zurück
kommenden XML Strukturen befassen muss; selbst von dem eigentlichen
Transportweg über HTTP oder welches Protokoll auch immer, sieht der
Programmierer nichts, die Basis ist in Java ohnehin vorhanden und den Rest
erledigt wieder AXIS. In alle verwendeten Modulen wird log4j zur
Protokollierung eingesetzt und wenn man das in seinen Teil ebenfalls einbaut,
hat man auch einen durchgängigen Mechanismus der Protokollierung, der bei
der Fehlersuche im Problemfall hilfreich ist.Würde man das mit RPG Mitteln machen wollen, sind da ein paar Hürden
zu überwinden. Für die WSDL Hürde gibt es hier noch
Unterstützung von WSDL2RPG, einem Open Source Teil von Thomas Raddatz, das einem die Analyse der WSDL
Beschreibung abnimmt und einen RPG Adapter generiert. Durch die geringere
Verwendungsbreite darf man natürlich nicht die Maßstäbe an
dieses Teil legen, denen AXIS genügt, zumal man hier auch
berücksichtigen muss, dass WSDL2RPG von einem einzigen Programmierer
betreut wird, diese Bemerkung soll Thomas Leistung nicht schmälern,
sondern stellt ein Lob dar. Es bleiben aber noch genügend Probleme, als da
sind die fehlende Einbindung in die Entwicklungswerkzeuge, das HTTP
Geschäft, die Erstellung der XML Anforderungsdokumente und die Auswertung
der zurück kommenden XML Dokumente. Selbst unter Verwendung des HTTP APIs
von Scott Klement, einer weiteren Open Source Komponente und des darin mit
verteilten XML Parsers, bricht man sich mit diesem Instrumentarium die Finger,
wenn man das mit dem Java Weg vergleicht, aber es gibt ja in der RPG Gemeinde
Leute, die vor lauter RPG Begeisterung sich selbst mit sogenannten Bordmitteln
an solchen Aufgaben versuchen. Ich habe da schon Beispiele gesehen, wo mit
Stringoperationen XML Dokumente aus Konstanten und Variablen zusammen gezimmert
werden, dann mit C-APIs Socket Verbindungen zu HTTP Servern geöffnet
werden und das Bastelwerk dann versandt wird, die zurück empfangene
Antwort wird dann wieder mit String Operationen durchgewurschtelt, um die darin
erhofften Informationen rauszuklabustern. Spätestens wenn man dann die
ganze Leistungsfähigkeit von WebServices auch nur annähernd nutzt,
ist dann der RPG-Traum ausgeträumt, bei dem Bastelwerk recht früh,
bei der etwas solideren Variante später, spätestens wenn da
komplexere Objektbäume zurück kommen, oder Konsistenzbedingungen
eingehalten werden müssen, ist es soweit.
WebService bereit stellen
Die Implementierung eines WebServices erfordert zunächst mal einen
Webserver, im einfachsten Falle reicht da eine Tomcat Installation, die ja
sowohl auf einer AS/400 oder auf jeder anderen Java fähigen Plattform
erfolgen kann, wer sich partout mit Websphere auf der AS/400 plagen will, der
kann seine WebServices auch über diesen anbieten. Geht man wieder den
einfachsten Weg macht man seine Implementierung dann mit Java. In diesem Fall
übernimmt wieder das AXIS 2 Framework in Verbindung mit einem Standard
Plugin von Eclipse den größten Teil der Arbeit. Man kann entweder
ausgehend von der WSDL die Implementierung mit leeren Methoden, die dann noch
zu füllen sind, generieren, oder man startet bei den Methoden zur
Implementierung und lässt sich dann die WSDL erstellen. Der Anfänger
tendiert eher dazu sich die WSDL generieren zu lassen, da das auf den ersten
Blick leichter erscheint, man gewinnt jedoch Flexibilität, wenn man mit
der WSDL startet, da die Schnittstellenbeschreibung dann mehr
Möglichkeiten bietet. Bei beiden Wegen
wird das komplette XML Geschäft wieder von AXIS 2 übernommen. Beim
Deployment wird dann AXIS2 einfach mit in die Installation des WebServers
deployed und damit ist die ganze Sache erledigt. Auch in diesem Fall hat man
mit dem kompletten XML Geschäft und der HTTP Geschichte nichts zu
schaffen, das übernehem wieder komplett Java und AXIS 2.Die Fraktion der grenzenlos RPG begeisterten benötigt hier zwar kein HTTP
API,
dafür wird dann mit CGI Programmen rumhantiert, die XML Problematik bleibt
dieselbe und zu einer passenden WSDL muss man hier ja auch noch kommen. Auf
diesen Pfaden kann man sich mit Hallo World Exempeln vielleicht noch
Erfolgserlebnisse schaffen, an denen man sich dann ergötzt bis berauscht,
je nach Temperament, aber die Zukunft der Anwendungsentwicklung ist das in
meinen Augen jedenfalls nicht. Die Welt des weiten Webs spricht Java oder
programmiert mit .NET und wer wirklich beide Seiten kennt, würde hier sein
Java oder C# nicht gegen RPG tauschen wollen, auch nicht wenn er noch eine
Flasche besten Medoc oben drauf bekäme.
Was ist nun mit RPG?
Auf der einen Seite ist es abenteuerlich, im engeren Sinn des Wortes, sich mit
Sockets Kommunikation, CGI Programmierung und mehr oder weniger händischem
XML Geschäft die neue Welt des Webs für grün-schwarzes Denken zu
erobern, auf der anderen Seite macht es wenig Sinn, produktiv eingesetzte
Programme nur deshalb neu zu schreiben, weil externe Schnittstellen andere
Technologien verwenden. Wenn es nun also um die Bereitstellung vorhandener RPG
Funktionalitäten als WebService, oder um die Nutzung von WebServices in
RPG Anwendungen geht, dann fehlt jetzt natürlich noch die Brücke
zwischen der alten und der neuen Welt.RPG Funktionalität als WebService
Ausgangspunkt ist in diesem Fall die vorhandene RPG Funktionalität, wobei
es nur eine geringfügige Rolle spielt, ob diese als Programm oder als
Procedure vorliegt. Wenn man den Informationsfluss analysiert, dann kann man
das als eine Blackbox betrachten, die eine Datenstruktur erhält, diese
Informationen verarbeitet und eine andere Datenstruktur zurück liefert.
Wenn man das in SQL formulieren würde, könnte man diese Funktion auch
als SQL Procedure beschreiben.CREATE PROCEDURE MyProc
(
IN input1 char(76)
, IN input2 dec(15, 5)
, ...
, IN inputn ...
, OUT output1 ...
, ...
, OUT outputm ...
)
LANGUAGE RPG
EXTERNAL NAME MyWrapper
PARAMETER STYLE GENERAL |
In diesem skizzierten Beispiel sind die Datentypen und die Anzahl der Parameter
nur angedeutet. Wenn man sich noch einen kleinen Wrapper schreibt, der das
Programm einpackt und eventuell Parameter umsortiert, oder Datenstrukturen in
Felder auflöst, kann man das vorhandene Programm dann mit der SQL
Anweisung CREATE PROCEDURE in der Datenbank registrieren. Für einen
Datenbank kundigen Java Programmierer ist es nunmehr eine seiner leichtesten
Übungen aus dieser create procedure Anweisung zwei Java Objekte zu
erstellen, das eine stellt die Eingabe Parameter dar und das andere die Ausgabe
Parameter und in einer weiteren Java Klasse wird eine Methode angelegt, die das
Eingabe Objekt erhält, per SQL die stored Procedure aufruft und das
Ausgabeobjekt zurück gibt, aus dieser Methode lässt man sich dann mit
Hilfe von AXIS 2 vollständig den WebService automatisiert erstellen. Nach
deployment der erstellten Java Klassen, AXIS 2 und der ebenfalls generierten
WSDL Beschreibung des WebServices auf den Application Server seiner Wahl, ist
der WebService fertig implementiert.RPG Anwendung nutzt WebService
Wie bereits oben gezeigt, bekommt man mit Hilfe von AXIS aus der vom Anbieter
des Dienstes bereit gestellten WSDL Beschreibung nahezu im Handumdrehen eine
Java Klasse mit aufrufbaren Methoden erzeugt, die den WebService aufrufen und
das Ergebnis als Java Objekt zurück erhalten. Für den Aufruf dieser
Java
Methoden aus RPG ist meist eine Anpassung der Schnittstellen erforderlich, da
Web Services und Java hier die ungleich gößere Mächtigkeit wie
RPG haben. Wenn
zum Beispiel ein WebService eine komplette Stücklistenauflösung
zurück gibt,
dann kriegt man die in keiner RPG Schnittstelle unter, weder von der schieren
Größe, noch von der Variabilität und man braucht dann
verschiedene Aufrufe und
Schleifenlogik, um die Informationen zu transportieren. War die Integration von
RPG in Java über stored Procedures noch glatt und einfach, so ist der
umgekehrte Fall ein wenig tückischer (ausführlich diskutiert findet
man das in
meiner JavaAS400FAQ), aber mit Hilfe meines Open Source Frameworks AppServer4RPG bekommt man das relativ leicht in den Griff. Ein Java Adapter löst
gegebenen Falls den Java Aufruf in mehrere RPG nach Java Aufrufe auf und
übernimmt die Aufbereitung und Konvertierung der Daten in RPG
Datenstrukturen. Dieser Adapter wird dann in das Framework eingeklinkt, das die
Kommunikation zum RPG Teil des Frameworks abwickelt, die über DataQs
implementiert ist. Nach Start des Serverjobs von AppServer4RPG ruft dann die
RPG Anwendung über das RPG Schnittstellenprogramm des Frameworks die Java
Methoden des Adapters und damit den WebService auf. Der Serverprozess kann
wieder auf jeder beliebigen Java Plattform laufen, also auf der AS/400 selber,
oder auf nahezu jedem beliebigen verfügbaren Rechner. Performance und
Skalierbarkeit liegen deutlich über den Werten, die mit anderen Varianten,
wie Java Unterstützung des RPG Compilers, Java stored Procedures, oder
Java native Interface erreicht werden, die zusätzliche Last durch den
Serverprozess von AppServer4RPG kann im Verhältnis zu den Antwortzeiten
eines WebServices vernachlässigt werden.