JAXenter.de

Das Portal für Java, Architektur, Cloud & Agile

Das Traumpaar Java und XML

X

Lesetipp: Alles zum neuen Eclipse Luna Release im aktuellen Eclipse Magazin!

Workshop: Arbeiten mit XML in Java, Teil 2

Das Traumpaar Java und XML

Neal Ford

Java Entwicklern stehen heute eine ganz Reihe von Technologien und Schnittstellen zur Verfügung, die für die Verarbeitung von XML-Dokumenten entwickelt wurden. In unserem Workshop für Einsteiger wollen Ihnen einige dieser Technologien vorstellen und aufzeigen, wie XML und Java sich gegenseitig ergänzen können. Im ersten Teil des Workshops haben wir Sie in das XML-Parsing mit SAX und DOM eingeführt (Java Magazin 4.2002). Im zweiten Teil stellen wir Ihnen mit der Bibliothek JDOM eine Open Source-Alternative zur DOM API vor, die zudem Java-spezifische Features bietet. Im Anschluss werden wir uns dem Thema Web Services zuwenden und uns aus Java-Sicht mit dem SOAP-Protokoll befassen, wobei die SOAP-Implementierung von Apache zum Lesen und Schreiben von SOAP-Envelopes verwendet wird.

Hinweis:

Aus Platzgründen wurden in diesem Artikel die umfangreichen
Quellcodes nur auszugsweise abgepictureet. Sämtliche Quellcodes, auf die sich der
Autor bezieht, befinden sich aber auf der Heft-CD des Java-Magazins 5.2002. Zum
Nachvollziehen der Beispiele empfehlen wir, die Quellcodes vollständig auszudrucken.

JDOM

Einer der Vorteile der Standard-APIs in XML ist deren sprachenübergreifende Verfügbarkeit.
Vielleicht fällt Ihnen bei den Beispielen der vorigen Folgen dieser Serie auf,
dass die meisten Bibliothek-importe mit org.w3c.* oder org.xml.*
beginnen. SAX und DOM sind Standard-APIs, die vom World Wide Web Consortium (W3C)
und anderen Standardisierungsorganen entwickelt wurden. Das ist besonders angenehm,
wenn Sie Code in mehr als einer Sprache schreiben, der XML verarbeiten muss -
Sie können dann dieselbe API in Java verwenden, die Sie auch in C++ oder Perl
benutzen. Da sie von einem Standardisierungsorgan definiert werden, sind sie über
alle unterstützte Sprachen konsistent. Einer der größten Nachteile der Standard-APIs
ist jedoch deren sprachenübergreifende Verfügbarkeit! Das Problem dabei besteht
darin, dass jede der APIs ihre gesamten Datenstrukturen von Grundprinzipien aus
definieren muss. Anders ausgedrückt, das Standardisierungsorgan kann aus keinen
Standardmerkmalen der Sprache Vorteile ziehen, da sie sie auf diesen sprachenübergreifenden
Standard überschreiben. Dies zeigt sich besonders deutlich im DOM-API für Komponentensammlungen.
DOM definiert Datenstrukturen wie NamedNodeMap für die Handhabung von Sammlungen.
Wenn Sie Java verwenden, wäre es natürlich angenehm, wenn Sie die Java-Standardsammlungen
(wie Maps, Lists usw.) verwenden könnten. Jedoch kann die DOM-API nicht auf diese
Merkmale der Java-Sprache überschrieben werden. Hier ist eine Reihe von Klassen
erforderlich, die die Standard-APIs unterstützen, aber auch Java-Standardkonstruktionen
nutzen. Genau darum geht es bei JDOM. JDOM ist kein Akronym (genauso wie JDBC
technisch kein Akronym ist); es ist eine Open-Source-Bibliothek mit XML-Verarbeitungscode,
der die XML-Standard-APIs unterstützt, aber Java-spezifisch. In anderen Worten,
Sie können SAX und DOM nur mit Java-Standardsammlungen verwenden. JDOM ist über
die Internetadresse www.jdom.org erhältlich. Es ist ein Projekt mit offenem Quellcode,
das beim Abfassen dieses Artikels als Beta-Version vorlag. Die Autoren
versuchen damit, eine Alternative mit völlig offenem Quellcode zu den Standard-APIs
für Java-Entwicker zu schaffen. JDOM verwendet die gleiche Lizenz für offenen
Quellcode wie der Apache-Webserver (das bedeutet, jeder kann es verwenden, ohne
auch sein Produkt zu offenem Quellcode zu machen). Es unterstützt SAX, DOM, Validierungen,
XSLT-Konvertierungen und weitere XML-Merkmale.

Listing 1

Listing 2

package xmlconfig;


import java.io.*;
import java.util.*;
import java.net.*;

import org.w3c.dom.*;
import org.apache.xerces.dom.DocumentImpl;
import org.apache.xerces.dom.DOMImplementationImpl;
import org.w3c.dom.Document;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.Serializer;
import org.apache.xml.serialize.SerializerFactory;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xerces.parsers.DOMParser;


public class Configuration {

private Configuration() throws NoConfigFileException {
//-- load configuration info
loadConfig();
}

static public Configuration getConfiguration()
throws NoConfigFileException {
if (myConfig == null) {
myConfig = new Configuration();
}
return(myConfig);
}

private void loadConfig() throws NoConfigFileException {
System.out.print("Parsing XML File: " +
CONFIG_FILE_NAME + "...");

DOMParser parser = new DOMParser();
try {
parser.parse(CONFIG_FILE_URI);
Document doc = parser.getDocument();

recurseDOMTree(doc);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error in parsing: " +
e.getMessage());
}
System.out.println("Done.");
}

public void recurseDOMTree(Node node) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE:
String name = node.getNodeName();
NamedNodeMap attributes = node.getAttributes();
if (name.equalsIgnoreCase("position")) {
top = Integer.parseInt(
attributes.getNamedItem("top").getNodeValue());
left = Integer.parseInt(
attributes.getNamedItem("left").getNodeValue());
} else if (name.equalsIgnoreCase("visuals")) {
title = attributes.getNamedItem("title").getNodeValue();
} //else
break;
} //switch
//-- recurse on each child
NodeList children = node.getChildNodes();
if (children != null) {
for (int i=0; i

Hier finden Sie ein Beispiel, in dem JDOM
und DOM verglichen werden. Ich werde dasselbe Beispiel sowohl in DOM als auch
in JDOM implementieren, um den Unterschied zu veranschaulichen. Die Anwendung
liest Daten aus einer einfachen Konfigurationsdatei für Rahmentitel und Position.
Listing 1 zeigt das XML-Konfigurationsdokument. In Listing 2 ist die Konfigurationsklasse
aufgeführt, die DOM verwendet. Achten Sie hierbei besonders auf die Methode main().
Diese Methode enthält vordefinierten Code, um eine Standard-Konfigurationsdatei
zu schreiben, falls noch keine vorhanden ist. Die Erstellung des Dokuments erfolgt
auf direktem Wege - Sie können jeden DOM-Typ nach Bedarf erzeugen. Das Speichern
der Datei ist in DOM jedoch sehr umständlich. Wie Sie sehen können, müssen Sie
ein Objekt XMLSerializer erzeugen, auf dieses Methoden aufrufen und es anweisen,
das Dokument als String zu serialisieren, der bei Einsatz von Standard-Java dann
das Output ergibt. Der andere erwähnenswerte Code in diesem Beispiel ist die Methode
loadConfig(), der für DOM-Code in Java auch sehr typisch ist. Sie parsen
das Dokument unter Verwendung eines DOM-Parsers (in diesem Fall Xerces) und übergeben
das Dokument an eine Methode, um Informationen herauszuholen. Die Methode recurseDOMTree()
wird Ihnen sehr vertraut erscheinen, wenn Sie schon sehr viel mit DOM-Dokumenten
gearbeitet haben. Sie müssen den Baum rekursiv abarbeiten und dabei die Elemente
herausziehen, an denen Sie interessiert sind.

Listing 3

. . .
public static void main(String[] args) {
System.out.print("Building default configuration file at "
+ CONFIG_FILE_NAME + "...");
DOMBuilder builder = new DOMBuilder
(DEFAULT_DOM_ADAPTER_CLASS); Element root = new Element("Configuration"); Element posElem = new Element("Position"); posElem.addAttribute("left", "100"); posElem.addAttribute("top", "100"); root.addContent(posElem); Element titleElem = new Element("Visuals"); titleElem.addAttribute("Title", "Default Title"); root.addContent(titleElem); Document doc = new Document(root); FileOutputStream fos = null; try { fos = new FileOutputStream(CONFIG_FILE_NAME); XMLOutputter outputter = new XMLOutputter(); outputter.output(doc, fos); } catch (IOException ioe) { ioe.printStackTrace(); } finally { try { fos.flush(); fos.close(); } catch (IOException ignored) { } //catch } //finally System.out.println("done."); } . . . private void loadConfig() throws NoConfigFileException, JDOMException { DOMBuilder builder = new DOMBuilder
(DEFAULT_DOM_ADAPTER_CLASS); FileInputStream in = null; try { in = new FileInputStream(CONFIG_FILE_NAME); //build a DOM tree with the specified or default parser DOMAdapter domAdapter; Class parserClass = Class.forName
(DEFAULT_DOM_ADAPTER_CLASS); domAdapter = (DOMAdapter)parserClass.newInstance(); //-- Build the JDOM Document org.w3c.dom.Document w3cdoc = domAdapter.getDocument((InputStream)in, false); Document doc = builder.build(w3cdoc); //-- Print out entire set of attributes Element elem = doc.getRootElement(); java.util.List lst = elem.getChildren(); Iterator it = lst.iterator(); while (it.hasNext()) { Element e = (Element) it.next(); java.util.List child = e.getAttributes(); Iterator i = child.iterator(); while (i.hasNext()) { Attribute attr = (Attribute) i.next(); System.err.println(attr.getName() + " : " + attr.getValue() ); } } //-- get config info for properties top = Integer.parseInt( elem.getChild("Position").getAttribute("top").getValue()); left = Integer.parseInt( elem.getChild("Position").getAttribute("left").getValue()); title = elem.getChild("Visuals").getAttribute("Title"). getValue(); } catch (ClassNotFoundException e) { throw new JDOMException("Parser class " +
DEFAULT_DOM_ADAPTER_CLASS +
" not found"); } catch (IOException ioe) { ioe.printStackTrace(); } catch (Exception e) { throw new JDOMException("Parser class " + DEFAULT_DOM_ADAPTER_CLASS + " instantiation error"); } finally { try { in.close(); } catch (IOException ignored) { } //catch } }

Listing 3 enthält Code, der die selben Aufgaben mit JDOM anstatt mit DOM durchführt.
Dieses Listing enthält nur die Methoden main() und loadConfig()
- der gesamte übrige Code ist der gleiche. In der Methode main() wird das
Dokument fast in der gleichen Weise aufgebaut. Achten Sie jedoch darauf, wie viel
einfacher es ist, das Dokument zu schreiben. Da JDOM Java-sensibel ist, enthält
es eine Klasse XMLOutputter, die einen FileOutputStream als Parameter verwendet.
Zudem ist das Output viel schöner formatiert als das Ergebnis, das aus dem DOM-Serializer
kommt (der einen langen XML-String ausgibt). Die Methode loadConfig() leistet
hier mehr Arbeit als in der früheren Version mit viel weniger Code. Die zuerst
erledigte Aufgabe besteht im Laden des XML-Dokuments und dieser Prozess ist dem
DOM-Code sehr ähnlich. Als nächstes drucke ich die Liste aller Attribute aus.
Achten Sie hier auf den Einsatz einer java.util.List und eines java.util.Iterator.
JDOM-Sammlungen verwenden das System der Java-Standardsammlungen, um Aufgaben
wie das Iterieren durch alle Elemente eines Baumes zu vereinfachen. Zuletzt ermöglicht
JDOM es Ihnen, einen Direktzugriff auf die Elemente des Baums vorzunehmen. Anstatt
eine Parsing-Routine zu schreiben, können Sie also Code wie den folgenden verwenden:

elem.getChild("Position").getAttribute("top").getValue());

Mit diesem können Sie das Attribut top des Elements Position auslesen.
In Listing 4 (zu finden auf der beiliegenden CD) sehen Sie weiteres Beispiel dafür,
wie leicht der Einsatz von JDOM ist. Es handelt sich um eines der Beispiele, das
mit JDOM mitgeliefert wird. Es zeigt, wie man JDOM einsetzt, um Konfigurationsinformationen
aus dem XML-Konfigurationsdokument in einer WAR-(Webarchiv-)Datei zu lesen. Achten
Sie besonders in der Methode read() darauf, wie leicht es JDOM macht, spezifische
Elemente aus dem DOM-Baum zu lesen, ohne dass man Code schreiben muss, um durch
den Baum zu parsen. Zudem werden alle Elemente in Java-Standardsammlungen ausgegeben.
Wie bereits zuvor erwähnt, ist JDOM derzeit als Beta-Version verfügbar, was schon
seit längerer Zeit der Fall ist. Die Autoren können sich anscheinend nicht entscheiden,
wann die Merkmale von JDOM vollständig genug sind, um es tatsächlich auf den Markt
zu bringen. Zum Stand dieses Artikels läuft es in Beta 7. Da XML einem derart
raschen Wandel unterliegt, werden sie wohl nie eine Version auf den Markt bringen,
wenn sie es mit den aktuellsten APIs immer auf dem neuesten Stand halten wollen.
Sein Status hat jedoch nicht verhindert, dass es sowohl in Produktionsanwendungen
als auch in Entwicklungswerkzeugen verwendet wird. Tatsächlich wird die aktuelle
Version von JBuilder als eine der integrierten Bibliotheken mit JDOM mitgeliefert.
So wird es sogar im Beta-Status bereits häufig verwendet. Unsere Firma hat es
eingesetzt; man bewertete es dort als sehr stabil und seine Leistungsfähigkeit
als relativ hoch. Da JDOM noch als Beta-Version läuft, können Sie noch keine kompilierte
Jar-Datei herunterladen. Wenn Sie jedoch den Quellcode herunterladen, ist ein
Ant-Skript beigefügt, das die Jar-Datei und Beispiele für Sie aufbaut. Zur Zeit
gibt es einige Konfigurationsfragen, auf die Sie achten sollten, insbesondere
im Hinblick auf die Version des Xerces-Parsers, den Sie in Ihrem Klassenpfad installiert
haben. JDOM verwendet Xerces intern, und es erwartet SAX- und DOM-Parser, die
die Level-2-Version dieser APIs unterstützen. Wenn Sie eine ältere Xerces-Version
in Ihrem Klassenpfad haben, kann dies zu Problemen führen. Hierzu gibt es jedoch
eine einfache Arbeit, die in den Versionsmitteilungen für DOM beschrieben ist.

SOAP

SOAP steht für Simple Object Access Protocol. Es ist eine Methode mit offenem
Standard zur Ausführung von Fernprozeduraufrufen, die ein textbasiertes Transportmittel
(normalerweise HTTP) und XML verwendet. Es ist eine der Grundlagen von Web Services,
was derzeit bei verteilten Rechnersystemen ein topaktuelles Thema ist. Doch warum
ist SOAP so wichtig und warum sind alle so begeistert von dieser Art, Methodenaufrufe
durchzuführen? Letztlich steht es für einen einfachen Weg, sprachenübergreifend
ferngesteuerte Prozeduren aufzurufen. Das soll nicht heißen, dass dies lange Zeit
nicht möglich gewesen wäre. Schließlich geht es bei COM, CORBA und RMI genau darum.
Das Problem bei diesen Methodenaufrufverfahren liegt jedoch darin, dass es sich
bei allen um binäre Standards handelt. Dies funktioniert einfach und effizient
in lokalen Netzwerken, wird aber problematisch, wenn man es bei verteilten Rechnersystemen
im Internet versucht. Fragen Sie doch mal, wie viele Netzwerkadministratoren binäre
Ports an den Firewalls Ihrer Firma öffnen wollen! SOAP und Internetdienste sind
attraktiv, da die meisten Netzwerke den freien Durchgang von Text bereits zulassen
(normalerweise über den HTTP-Port). SOAP steht für eine sprachen- und plattformunabhängige
Technik zur Ausführung von Methodenaufrufen, indem die Daten innerhalb von XML
geordnet und dieses XML-Paket dann über HTTP transportiert wird. Ich möchte beschreiben,
wie man die SOAP-Implementierung von Apache einsetzt. Es ist keine Einführung
zu SOAP an sich (dies allein würde mindestens ein Buch füllen), doch ich werde
SOAP gerade so ausführlich behandeln, dass die Beispiele verständlich werden.
Beachten Sie, dass Sie SOAP ohne irgendeine Systemumgebung programmieren können
- wenn Sie einen XML-Parser haben, können Sie mit SOAP arbeiten. Es ist jedoch
immer angenehm, wenn schon ein anderer (wie Apache) den meisten Installationscode
für Sie geschrieben hat. Das SOAP Toolkit von Apache ermöglicht es Ihnen, entweder
SOAP-Dienste anzulegen oder Clients, die mit SOAP-Diensten kommunizieren. Wir
werden beides besprechen. Doch zunächst müssen Sie das System installieren.

Installation

Die Installation von SOAP läuft ähnlich wie die Installation von anderen Apache-Produkten.
Sie laden eine Zip-Datei herunter, die in ein Verzeichnis entpackt werden muss.
Jetzt sind nur noch einige wenige Schritte zu tun, dann ist SOAP installiert und
startbereit. Diese werden in der Dokumentation behandelt, die mit der SOAP-Implementierung
von Apache geliefert wird; ich erwähne sie hier deshalb nur kurz. Es gibt separate
Anweisungen für die Installationen der Client-Seite zur Server-Seite, doch der
Server ist dem Client übergeordnet. Für den Client müssen Sie zuerst Folgendes
besorgen:

  • den Klassenpfad aktualisieren, um die Datei soap.jar einzubinden

  • mail.jar, von der Sun-Internetadresse (java.sun.com/products/javamail/)

  • activation.jar, ein Bestandteil des JavaBeans Activation Framework (java.sun.com/products/beans/glasgow/jaf.html)

  • einen beliebigen JAXP-kompatiblen XML-Parser (ich selbst habe Xerces 1.4.0 eingesetzt). Wenn Sie einen älteren Parser (der Namespaces nicht unterstützt) in Ihrem Klassenpfad haben, müssen Sie sicherstellen, dass der neuere Parser im Klassenpfad vor dem älteren erscheint.

Um einen SOAP-Server einzurichten, sollte alles oben
Angegebene im Klassenpfad stehen. Wenn Sie außerdem Dienste in Skriptsprachen
(wie z. B. JavaScript) implementieren wollen, sollten auch die passenden JAR-Dateien
für die Skriptsprache in Ihrem Klassenpfad zur Verfügung stehen. Wenn Sie z. B.
den SOAP-Server in JavaScript implementieren wollen, sollten Sie die Datei js.jar
von Rhino (Bestandteil von Mozilla) unter www.mozilla.org/rhino/ herunterladen.
Die Installationsanleitung enthält auch nähere Angaben darüber, wie Sie die Apache
SOAP-Verwaltungswerkzeuge in Ihre Servlet-Maschine integrieren können. Es gibt
Verweise zu allen wichtigen Lieferanten von Servlet-Maschinen (WebLogic, WebSphere,
iPlanet usw.) und natürlich zu TomCat. Wenn Sie jedoch Servlet 2.2 oder eine höhere
Servlet-Maschine verwenden, können Sie die WAR-Datei in das Deployment-Verzeichnis
ziehen. Sobald Sie alle beweglichen Teile eingerichtet haben, sollten Sie Ihre
Servlet-Maschine starten und auf den lokalen URL http://localhost:8080/soap/servlet/rpcrouter
zugreifen können (natürlich können der Host-Name und Port in Ihrem Fall anders
lauten - dieser gilt für TomCat). Es erscheint dann folgende Meldung:

Sorry, I don't speak via HTTP GET- you have to use HTTP POST to talk to me.

Diese Meldung gibt an, dass der SOAP-Router richtig konfiguriert ist. Alternativ
können Sie die Adresse http://localhost:8080/soap eingeben und es erscheint
ein Begrüßungspictureschirm, von dem Sie entweder zum Admin-Client (siehe unten)
gehen oder einen Ping am Router durchführen können, was wir oben gemacht haben.

SOAP-Dienste

Ein SOAP-Dienst ist ein Software-Artefakt, das Abfragen empfängt und durch das
Senden von SOAP-Meldungen antwortet, die normalerweise eine Nutzinformation enthalten.
Das meiste SOAP-spezifische XML dient als Leitwegangaben und Metadaten für das
Thema der Nachricht (oder Nutzlast). Sie können sich SOAP als einen Umschlag vorstellen,
der das Dokument von irgendeinem Absender per Post zu Ihnen nach Hause trägt.
SOAP ist eigentlich nur ein Codierungsmechanismus, der es Ihnen ermöglicht, Methoden,
Parameter und Rückmeldungsarten anzugeben, die nicht an eine bestimmte Sprache
gebunden sind. Wenn Sie einen Dienst anlegen, müssen Sie entscheiden, welche Dienste
Sie anbieten wollen. Eines der Beispiele, die mit SOAP von Apache ausgeliefert
werden, ist ein Adressbuchdienst. Er ermöglicht es Ihnen, eine Adresse zu einem
Namen abzufragen, neue Adressen hinzuzufügen, das vorhandene Adressbuch anzuzeigen
und Listen hinzuzufügen. Die Implementierung dieses Dienstes speichert die Adressen
in Hashtable, doch für den Abnehmer des Dienstes spielt dies nicht die geringste
Rolle. Dies ist jedoch einer der Punkte, bei dem man ein Transportmittel wie SOAP
einsetzen kann. Die Art des Dialogs mit dem Dienst ist festgelegt, wobei die Einzelheiten
der Implementierung dem Entwickler des Dienstes überlassen bleiben. Beim Adressbuch
werden die Methoden, die aufgerufen werden können, während der Registrierung des
Dienstes beim Apache SOAP-Router definiert.

Listing 5

public Address getAddressFromName(String name)
throws IllegalArgumentException
{
if (name == null)
{
throw new IllegalArgumentException(
"The name argument must not be null.");
}

return (Address)name2AddressTable.get(name);
}

Im Adressbuch-Beispiel gibt es eine Java-Klasse mit der Bezeichnung AddressBook,
die Methoden zur Implementierung der Methoden des Dienstes enthält. Listing 5
enthält beispielsweise die Methode, eine Adresse auszugeben, wenn ein Name eingegeben
wird. Die Methode getAllListings() ist in Listing 6 aufgeführt. Sie gibt
alle Adressen im Adressbuch als XML-Dokument aus. Es ist erwähnenswert, dass das
SOAP Toolkit Klassen definiert, die das Anlegen von XML-Dokumenten leicht machen.
Sobald die Dienstklasse und ihre Hilfsklassen geschrieben sind, müssen Sie diese
beim SOAP-Router registrieren. Wenn Sie dies erledigen, legen Sie eine Ressource
an, die von einem Client aufgerufen werden kann, um Informationen auszugeben.
Es gibt zwei Wege, einen Dienst beim Apache SOAP-Router zu registrieren. Der erste
geht über den Admin-Client, der als Web-Anwendung läuft. Abpictureung 1 zeigt den
Admin-Client in Betrieb, mit seinen drei Optionen. Wenn Sie die Option Deploy
auswählen, können Sie alle Detailangaben zu Ihrem Dienst in das in Abpictureung 2
dargestellte Formular eingeben.



Abb. 2: Formular zum Einsatz von Diensten

Alternativ dazu enthält das SOAP
Toolkit auch Befehlszeilenwerkzeuge zur Ausführung der gleichen Aufgaben. Diese
Werkzeuge nehmen eine Router-URL und ein XML-Dokument, das den Dienst als Parameter
beschreibt. Das Beispiel AddressBook enthält das in Listing 7 aufgeführte
Einsatzdeskriptor-Dokument. Wie Sie sehen können, enthält dieses Dokument genau
dieselben Informationen, die Sie in die Admin-Anwendung eingeben würden. Achten
Sie besonders auf die Namen der Methoden, die vom Dienst angezeigt werden. Achten
Sie auch auf die Mappings zur Konvertierung von Java-Verweisen nach XML und umgekehrt.
Dies ist ein weiteres Hilfsprogramm, das im SOAP Toolkit enthalten ist, um JavaBeans
automatisch zu codieren. Natürlich müssen Sie für komplexere Typen eventuell maßgeschneiderte
Codierer schreiben. Sobald der Dienst beim Router registriert ist, kann ein Client
Methodenaufrufe auf den Dienst ausführen.

Listing 7


org.apache.soap.server.DOMFaultListener
package samples.addressbook;

import java.io.*;
import java.util.*;
import java.net.*;
import org.w3c.dom.*;
import org.apache.soap.util.xml.*;
import org.apache.soap.*;
import org.apache.soap.encoding.*;
import org.apache.soap.encoding.soapenc.*;
import org.apache.soap.rpc.*;

/**
* See \samples\addressbook\readme for info.
*
* @author Matthew J. Duftler (duftler@us.ibm.com)
*/
public class GetAddress
{
public static void main(String[] args) throws Exception
{
if (args.length != 2
&& (args.length != 3 || !args[0].startsWith("-")))
{
System.err.println("Usage:");
System.err.println("  java " + GetAddress.class.getName() +
" [-encodingStyleURI] SOAP-router-URL nameToLookup");
System.exit (1);
}

// Process the arguments.
int offset = 3 - args.length;
String encodingStyleURI = args.length == 3
? args[0].substring(1)
: Constants.NS_URI_SOAP_ENC;
URL url = new URL(args[1 - offset]);
String nameToLookup = args[2 - offset];
SOAPMappingRegistry smr = new SOAPMappingRegistry();
BeanSerializer beanSer = new BeanSerializer();

// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:xml-soap-address-demo", "address"),
Address.class, beanSer, beanSer);
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:xml-soap-address-demo", "phone"),
PhoneNumber.class, beanSer, beanSer);

// Build the call.
Call call = new Call();

call.setSOAPMappingRegistry(smr);
call.setTargetObjectURI("urn:AddressFetcher");
call.setMethodName("getAddressFromName");
call.setEncodingStyleURI(encodingStyleURI);

Vector params = new Vector();

params.addElement(new Parameter("nameToLookup", String.class,
nameToLookup, null));
call.setParams(params);

// Invoke the call.
Response resp;

try
{
resp = call.invoke(url, "");
}
catch (SOAPException e)
{
System.err.println("Caught SOAPException (" +
e.getFaultCode() + "): " +
e.getMessage());
return;
}

// Check the response.
if (!resp.generatedFault())
{
Parameter ret = resp.getReturnValue();
Object value = ret.getValue();

System.out.println(value != null ? "\n" + value : "I don't know.");
}
else
{
Fault fault = resp.getFault();

System.err.println("Generated fault: ");
System.out.println ("  Fault Code   = " + fault.getFaultCode());
System.out.println ("  Fault String = " + fault.getFaultString());
}
}
}

Ein SOAP-Client führt einen
Methodenaufruf durch, indem er die Teile eines SOAP-Aufrufs konstruiert. Das Apache-Toolkit
hat Methoden angelegt, um diese Teile zu definieren. Eine Client-Anwendung, die
die Methode getAddress() aus AddressBook aufruft, ist in Listing
8 dargestellt. Die wesentlichen Schritte für den Client lauten wie folgt: Zuerst
müssen Sie den URL für den SOAP-Router erhalten. In diesem Fall wird erwartet,
dass er über die Befehlszeile durchgegeben wird. Als Zweites müssen Sie Mappings
für die Objekttypen bereitstellen, die übermittelt werden. Dies ist ähnlich wie
die Bereitstellung von Schnittstellendeklarationen von Rückkehrarten für CORBA
und RMI:

// Map the types.
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:xml-soap-address-demo", "address"),
Address.class, beanSer, beanSer);
smr.mapTypes(Constants.NS_URI_SOAP_ENC,
new QName("urn:xml-soap-address-demo", "phone"),
PhoneNumber.class, beanSer, beanSer);

Beachten Sie bei obigem Code, dass sowohl die Klasse Address
als auch die Klasse PhoneNumber auf dem Bean-Serializer abgepictureet werden.
Dies ist die Utility-Klasse, die ein JavaBean nach XML serialisiert und umgekehrt.
Als Drittes müssen Sie den SOAP-Aufruf konstruieren:

// Build the call.
Call call = new Call();

call.setSOAPMappingRegistry(smr);
call.setTargetObjectURI("urn:AddressFetcher");
call.setMethodName("getAddressFromName");
call.setEncodingStyleURI(encodingStyleURI);

Vector params = new Vector();

params.addElement(new Parameter("nameToLookup", String.class,
nameToLookup, null));
call.setParams(params);

Diese Hilfsklassen
ermöglichen Ihnen, alle von Ihnen benötigten Informationen anzugeben, um den Dienst
aufzurufen, einschließlich der erforderlichen Parameter, die in einem Vektor dargestellt
werden. Zuletzt führen Sie den Methodenaufruf aus und halten die aus dem Aufruf
zurückgesandte Antwort fest (siehe Listing 9).

Listing 9

package xmlconfig;


import java.io.*;
import java.util.*;
import java.net.*;

import org.w3c.dom.*;
import org.apache.xerces.dom.DocumentImpl;
import org.apache.xerces.dom.DOMImplementationImpl;
import org.w3c.dom.Document;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.Serializer;
import org.apache.xml.serialize.SerializerFactory;
import org.apache.xml.serialize.XMLSerializer;
import org.apache.xerces.parsers.DOMParser;


public class Configuration {

private Configuration() throws NoConfigFileException {
//-- load configuration info
loadConfig();
}

static public Configuration getConfiguration()
throws NoConfigFileException {
if (myConfig == null) {
myConfig = new Configuration();
}
return(myConfig);
}

private void loadConfig() throws NoConfigFileException {
System.out.print("Parsing XML File: " +
CONFIG_FILE_NAME + "...");

DOMParser parser = new DOMParser();
try {
parser.parse(CONFIG_FILE_URI);
Document doc = parser.getDocument();

recurseDOMTree(doc);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error in parsing: " +
e.getMessage());
}
System.out.println("Done.");
}

public void recurseDOMTree(Node node) {
switch (node.getNodeType()) {
case Node.ELEMENT_NODE:
String name = node.getNodeName();
NamedNodeMap attributes = node.getAttributes();
if (name.equalsIgnoreCase("position")) {
top = Integer.parseInt(
attributes.getNamedItem("top").getNodeValue());
left = Integer.parseInt(
attributes.getNamedItem("left").getNodeValue());
} else if (name.equalsIgnoreCase("visuals")) {
title = attributes.getNamedItem("title").getNodeValue();
} //else
break;
} //switch
//-- recurse on each child
NodeList children = node.getChildNodes();
if (children != null) {
for (int i=0; i

Das ausgegebene Objekt Address wird als Java-Standardobjekt ausgelesen.
In diesem Fall verlassen wir uns auf die Methode toString() der Address-Klasse;
somit ist es nicht notwendig, es auf einen Typ festzulegen. Wenn wir darauf Address-spezifische
Methodenaufrufe vornehmen müssten, wäre eine Festlegung erforderlich. Dieses Beispiel
veranschaulicht auch, wie man mit Fehlern umgeht, die durch den Aufruf erzeugt
wurden. Die Fault-Klasse ermöglicht es Ihnen, mit vom Server generierten
Fehlern auf elegante Weise umzugehen. In diesem Beispiel werden die Fähigkeiten
des SOAP Toolkits nur oberflächlich behandelt. Es gibt auch Klassen, die es Ihnen
ermöglichen, auf eine niedrigere Abstraktionsebene zu gelangen und direkt mit
den SOAP-Headern und dem Envelope zu arbeiten. Wie Sie sehen, gibt es zahlreiche
Hilfemethoden, um das Arbeiten mit SOAP zu erleichtern.

Webdienste

Wenn
Sie nicht gerade in einer Höhle gelebt haben, haben Sie sicher den ganzen Medienrummel
um die Web Services mitbekommen. Eine der Technologien, die den Webdiensten zugrunde
liegt, ist SOAP: Es wird verwendet, um die Methodenaufrufe auszuführen. Web Services
werden von einigen weiteren, SOAP-externen Standards unterstützt, die über das
Thema dieses Artikels hinausgehen. Zum Beispiel verwendeten wir ein proprietäres
XML-Dokument oder ein Webformular, um unseren Dienst beim Apache-Server zu registrieren.
Um Aufrufe bei unserem Dienst zu tätigen, mussten wir vorab wissen, welche Methoden
zur Verfügung stehen und wie sie aufgerufen werden können. Web Services definiert
Leistungsmerkmale wie z. B. WSDL (Web Services Definition Language), bei dem es
sich um ein Verzeichnis handelt, das die Eigenschaften eines Webdienstes definiert
und wie er aufgerufen wird. Sicher können Sie das Apache SOAP-System verwenden,
um Webdienste anzulegen und mit anderen Webdiensten zu kommunizieren. Es muss
jedoch außer SOAP noch weitere Infrastruktur eingerichtet sein.

Zusammenfassung

Im zweiten Teil unseres Java-XML-Workshops haben wir Sie in die Open Source API
JDOM sowie in die SOAP-Implementierung von Apache eingeführt. JDOM ist für das
interaktive Arbeiten mit XML eine großartige Möglichkeit, wenn Sie Java-Entwickler
im engeren Sinne sind oder schnell etwas programmieren müssen. Wenn Sie Code in
anderen Sprachen schreiben, sind Sie wahrscheinlich gut bedient, wenn Sie die
DOM-APIs erlernen und sie überall einsetzen (was Ihre Lernkurve verkürzt).Wenn
Sie nur XML-Code in Java schreiben, ist JDOM eine bequeme Alternative zu den notwendigerweise
komplexen SAX- und DOM-APIs. Wenn Sie einen XML-Parser besitzen, können Sie direkt
mit SOAP arbeiten. Jedoch überlässt man die Details auf der niederen Ebene am
besten anderen Entwicklern. Das SOAP Toolkit ist ein elegant konstruiertes System
für das Arbeiten mit SOAP, für Server, die entweder in Java oder einer anderen
SOAP-fähigen Sprache geschrieben sind.
Neal Ford ist Vice President Technology
bei der in Atlanta ansässigen DSW Group. Er hat zu den Themen Java und Delphi
veröffentlicht und spricht regelmäßig auf internationalen Konferenzen, so auch
der JAX2002 oder der Entwickler Konferenz.

 

Kommentare

Ihr Kommentar zum Thema

Als Gast kommentieren:

Gastkommentare werden nach redaktioneller Prüfung freigegeben (bitte Policy beachten).