lesen pt. 1

Werbung
inkl.
JAVA Mag
Java Magazin 3.2010
Y spoke. We listened.
You
Introducing Liferay Enterprise Edition.
CD
Konzepte nebenläufiger Programmierung
Liferay 5.1 Enterprise Edition
Platinum Support (24x7)
19.950 EUR / server / year
Compare Oracle WebCenter Suite: 125.000 EUR / processor, support 27.500 EUR / yr, as of 6 / 2008
®
Mashups mit Flex
For more information, email us at [email protected].
Amazon Web Services
Maintenance Subscription
2.950 EUR / server / year
Generational Garbage Collection
And with version 5.1, get the latest in SOA, Social Networking, and Collaboration
technology, all at a fraction of the cost of Oracle ® or IBM ®.
Java EE 6
Liferay Enterprise Edition gives you all the benefits of open source with the stability,
security, and reliability of an enterprise subscription.
LIFERAY GMBH — ROBERT - BOSCH - STRASSE 11, 63225 LANGEN, GERMANY
TEL: +49 - (0) 6103 - 3018570 Ý FAX: +49 - (0) 6103 - 3018571
Österreich € 9,80 Schweiz sFr 16,80
Java t Architekturen t SOA t Agile
From Java to
Groovy
Video von der
W-JAX 2009
in voller Länge
HIGHLIGHT
3.2010
JSR 330
www.javamagazin.de
Grails 1.2
Wie weit geht die Standardisierung wirklich? 34
»
Welche Features einen Blick
wert sind 14
»
Alle Infos im Heft
Concurrency
Konzepte für nebenläufige
Programmierung »
42
in-Step Scrum Edition
WEITERE INHALTE
GPars
Java EE 6 ausgepackt
Enterprise JavaBeans 3.1
» 85
BlazeDS
Jet Profiler
Amazon Web Services
Get into my Cloud
Alle CD-Infos ab Seite 3
EUROPEAN HEADQUARTERS - LANGEN, GERMANY
Deutschland € 8,50
magazin
CD-INHALT
Now get the best of both worlds.
» 54
Mashups mit Flex: Implementierung eines Editors
» 16
Generational Garbage
Collection
Memory-Management
» 26
Enterprise Web Services mit Spring WS
Zu Ihren Diensten,
Monsieur
Für den Datenaustausch oder das Anbieten von Diensten zwischen Anwendungen werden oft Web Services verwendet. Um einen Web Service anzubieten oder
zu verwenden, gibt es sehr viele Möglichkeiten und Vorgehensweisen. Dieser
dreiteilige Artikel stellt Ihnen die Möglichkeiten vor, die Spring WS Ihnen bietet.
von Thorsten Kamann
as Spring Framework [1] bietet
nativ eine Unterstützung für die
Verwendung von Web Services.
Sie können dabei das zugrunde liegende
Framework selbst bestimmen, z. B. Axis
[2] oder Apache XCF [3].
Artikelserie
Quellcode
auf CD
Teil 1: Basics zu Spring WS
Teil 2: Spring WS und JaxB
Teil 3: Spring WS und Spring
Security
66 javamagazin 3|2010
Spring WS [4] ist ein Projekt aus dem
SpringSource-Umfeld und hat das Ziel,
die Entwicklung von Web Services zu
vereinfachen. Dabei werden viele der etablierten JAXP-Frameworks, z. B. DOM,
SAX und StAX, aber genauso JDOM,
dom4j und XOM unterstützt. Darüber
hinaus existiert innerhalb von Spring WS
ein Modul, das für das XML-Mapping
(O/X Mapper) verantwortlich zeichnet.
Dieses Modul unterstützt JAXB 1/2,
Castor, XMLBeans, JiBX und XStream.
Das OXM-Modul ist inzwischen in
das Spring Framework übernommen
worden und steht somit auch für andere Anwendungen zur Verfügung. Alle
Features des Spring Frameworks können hier ebenfalls genutzt werden. Das
betrifft nicht nur die Konfiguration und
Dependency Injection, sondern auch
Sicherheitsaspekte, wenn Sie Spring Security verwenden wollen oder können.
Abgerundet wird die Featureliste mit der
Unterstützung für WS-Security, wenn
Sie die SOAP-Nachrichten ver- und entschlüsseln oder signieren wollen.
Die ganze Featureliste wird von
den Entwicklern als „Makes the Best
www.JAXenter.de
Web Services mit Spring WS Enterprise
Practice an Easy Practice“ bezeichnet.
Die Artikelserie wird zeigen, ob sie
Recht behalten. Der erste Teil der Serie
enthält die Basics zu Spring WS. Hier
werden wir ein kleines Projekt entwickeln, indem Sie einen Web Service implementieren, der die Funktionsweise
und Features von Spring WS beleuchtet.
Der zweite Teil der Serie knüpft nahtlos
an den ersten Teil an und diskutiert die
Schwachstellen der Lösung. Danach
werden wir gemeinsam eine bessere Lösung entwickeln.
Im dritten Teil werden wir den Web
Service mit Spring Security etwas sicherer machen, zusätzlich einen Blick auf
die Architektur von Spring-WS-Projekten werfen und das Thema Integrationstest betrachten.
Doch nun genug geredet, ...
... beginnen wir mit einem Beispielprojekt. Wir wollen in diesem Projekt
einen Web Service entwickeln, wie er
in Abbildung 1 dargestellt ist. Der ProductService enthält lediglich eine WebService-Methode. Diese findet Produkte anhand der Warengruppe (Category),
des Lieferanten (Supplier) und einer frei
konfigurierbaren Zeitspanne (DateRange).
Das dazu gehörende Domänenmodell ist in Abbildung 2 zu sehen. Die Warengruppe (Category) und der Lieferant
(Supplier) haben lediglich eine ID und
name-Property. Das gefundene Produkt
hält Referenzen auf den Lieferanten und
die Warengruppe. Auf diese beiden Re-
Abb. 1: Der ProductService
Abb. 2: Domänenmodell für den ProductService
ferenzen komme ich später noch genauer zu sprechen.
Schritt 1: Projekt erstellen
Spring WS bietet einen Maven-Archetypen, auf den wir hier aber bewusst
verzichten, um die Schritte besser
nachvollziehen zu können, die benötigt werden, um ein solches Projekt zu
erstellen. Als Erstes brauchen wir ein
Eclipse-Projekt. Da dieses später auf
einem Tomcat deployt werden soll, bietet sich als Projekttyp ein Dynamisches
Webprojekt an. Beenden Sie den Projekt-Wizard nicht mit Finish schon auf
der ersten Seite, sondern gehen Sie alle
drei Seiten mit Next durch. Auf der
zweiten Seite ändern Sie den Pfad zu
Contract First vs. Contract Last
Es gibt zwei Ansätze, wie Web Services entwickelt werden können. Entweder man
beginnt, eine WSDL zu definieren und erzeugt aus dieser den benötigten JavaQuellcode (Contract First), oder man schreibt zuerst den Java-Quellcode und
erzeugt daraus eine WSDL (Contract Last).
Doch welche Methode ist die bessere? Wie bei Vielem kann man das nicht abschließend beantworten. Doch es gibt einige Argumente für den Contract-FirstAnsatz. Definieren Sie zuerst die WSDL, dann haben Sie viel mehr Steuerungsmöglichkeiten, um die WSDL zu optimieren. Oft referenzieren Klassen ja andere
Klassen, die nicht in der WSDL definiert werden sollen. Dies kann besser in einer
WSDL umgangen werden. Ein anderer Punkt ist die Interoperabilität. Beschränkt
man sich bei den Datentypen auf die Typen, die in einem XML Schema definiert
werden können, dann wird es in den wenigsten Fällen zu Problemen in den verschiedenen Sprachen kommen, die den Web Service später konsumieren. Es gibt
noch einige andere Punkte zu diesem Thema, die die Spring-WS-Entwickler unter
[5] zusammengetragen haben.
www.JAXenter.de
dem Source-Verzeichnis auf src/main/
java und auf der dritten Seite das Verzeichnis für den Web-Content auf src/
main/web. Zusätzlich brauchen Sie
ein weiteres Source-Verzeichnis, das
weitere Ressourcen aufnehmen kann.
Nennen Sie das Verzeichnis src/main/
resources.
Schritt 2: Ein XML Schema
erstellen
XML Schema? Wofür das denn? Spring
WS geht streng nach dem Ansatz Contract-First (Kasten: „Contract-First vs.
Contract-Last“) vor. Deswegen benötigen Sie zuerst einen Vertrag. Dieser
Vertrag, der die Schnittstelle des Web
Service beschreibt, kann eine WSDL
sein oder in diesem Fall ein XML Schema. Der Vorteil eines XML Schemas gegenüber einer WSDL ist, dass man sich
bei der Definition des Vertrags auf die
eigentliche Schnittstelle konzentrieren
kann, ohne von den technischen Details
einer WSDL abgelenkt zu werden.
In Abbildung 3 sehen Sie eine Darstellung des Schemas. Da wir lediglich
eine Web-Service-Methode anbieten
wollen, brauchen wir auch nur ein Ele-
Abb. 3: Schematische Darstellung des verwendeten XMLSchemas
javamagazin 3|2010 67
Enterprise Web Services mit Spring WS
Abb. 4: Dialog
zum Aktivieren
des MavenDependencyManagements
benötigten Attribute (Abb. 2), und fertig
ist das Schema (Listing 1).
Das Schema speichern Sie am besten
unter src/main/resources/META-INF/
schema/Products.xsd.
Schritt 3: Domänenmodell und
Serviceklasse implementieren
ment. Im Sinne der Namensgebung in
WSDLs nennen wir das Element hier
ProductRequest. Wie in Abbildung 1 zu
sehen ist, benötigt dieser Request drei
Listing 1
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.itemis.de/hoa/
spring/ws/product"elementFormDefault="qualified"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:p="http://www.itemis.de/hoa/spring/ws/product">
<element name="ProductRequest">
<complexType>
<all>
<element name="Category" type="p:CategoryType" />
<element name="Supplier" type="p:SupplierType">
</element>
<element name="DateRange" type="p:DateRange">
</element>
</all>
</complexType>
</element>
<complexType name="CategoryType">
<sequence>
<element name="id" type="int"></element>
<element name="name" type="string"></element>
</sequence>
</complexType>
<complexType name="SupplierType">
<sequence>
<element name="id" type="int"></element>
<element name="name" type="string"></element>
</sequence>
</complexType>
<complexType name="DateRange">
<sequence>
<element name="startDate" type="date"></element>
68 javamagazin 3|2010
Parameter: Category, Supplier und DateRange. Diese werden in dem Schema als
anonyme komplexe Datentypen angelegt. Diese Typen bekommen noch die
<element name="endDate" type="date"></element>
</sequence>
</complexType>
</schema>
Listing 2
public class ProductService {
public List<Product> findProductsForSupplierAndCategory
InDateRange(
Category category, Supplier supplier, DateRange dateRange) {
List<Product> products = new ArrayList<Product>();
products.add(new Product(12345, "Product1", category,
supplier));
products.add(new Product(12346, "Product2", category,
supplier));
return products;
}
}
Listing 3
<dependencies>
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
<version>1.5.8</version>
</dependency>
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom</artifactId>
<version>1.1</version>
</dependency>
</dependencies>
Insgesamt müssen Sie dafür fünf Klassen
implementieren. Wir verzichten für dieses Beispiel komplett auf Interfaces. Die
vier Domänenklassen sind einfache POJOs mit Gettern und Settern. Diese finden
Sie natürlich schon implementiert in dem
mitgelieferten Beispiel. Die Serviceklasse
implementiert die eigentliche Businesslogik. In einem realen Projekt würde die
Servicemethode über Datenzugriffskomponenten auf eine Datenbank zugreifen
und die in Frage kommenden Produkte
dort abfragen. Für dieses Beispiel habe ich
es uns etwas einfacher gemacht und gebe
immer eine Liste mit zwei Produkten zurück (Listing 2).
Schritt 4: Maven konfigurieren
Bisher haben wir nur die Bordmittel der
JVM verwendet. Der nächste Schritt
ist allerdings die Implementierung des
Endpoints. Der Endpoint ist die Instanz, die die Anfragen von einem WebService-Konsumenten beantwortet. In
diesem Teil verwenden wir JDOM, um
die Anfrage zu analysieren und aus dem
SOAP-Body die benötigten Daten zu
extrahieren. Außerdem greifen wir zum
ersten Mal auf Spring-WS-Funktionen
zurück. Um die benötigten Bibliotheken
in das Projekt zu integrieren, verwenden wir Maven. Dazu aktivieren wir für
unser Projekt das Maven Dependency
Management (Rechtsklick auf Projekt
| Maven | Enable Dependency Management). Daraufhin erscheint ein
Dialogfenster, wie in Abbildung 4 zu sehen ist. Tragen Sie hier die gewünschten
Daten ein und klicken auf Finish.
Um den Endpoint zu implementieren, benötigen wir zuerst nur zwei Abhängigkeiten:
■ spring-ws-core
■ jdom
Mit Maven ist es sehr einfach, diese Abhängigkeit hinzuzufügen. Sie brauchen
www.JAXenter.de
Anzeige
Enterprise Web Services mit Spring WS
Abb. 5: Typhierarchie des Interfaces PayloadEndpoint
nur die pom.xml und in dem POM-Editor die Quellansicht zu öffnen (der rechte
Tab mit der Beschriftung pom.xml). Dort
fügen Sie den Inhalt aus Listing 3 ein.
Nun haben Sie alles beisammen, um
mit der Implementierung des Endpoints
zu beginnen.
Schritt 5: Implementierung des
Endpoints
Ein Endpoint wird benötigt, damit die
Anfragen beantworten werden können.
Listing 4
Der Endpoint muss den SOAP-Request
verarbeiten können und auch wissen,
was er mit den Daten anfangen soll. Damit Spring WS eine Klasse als Endpoint
erkennt, muss diese das Interface org.
spring framework.ws.server.endpoint.
PayloadEndpoint implementieren. Aber
Spring wäre nicht Spring (das gilt auch
für Spring WS), wenn es da nicht schon
was vorbereitet hätte. Es gibt schon einige abstrakte Implementierungen, die
Sie direkt verwenden können und die
Ihnen viel Arbeit ersparen. Abbildung 5
zeigt die verfügbaren Implementierungen.
Da wir für diesen Artikelteil jDOM
verwenden wollen, benutzen wir die
AbstractJDomPayloadEndpoint-Implementierung. Die einzige Methode, die
wir implementieren müssen, ist die protected Element invokeInternal(Element
requestElement) throws Exception {}. Listing 4 zeigt eine erste Implementierung
unseres Endpoints. Im Konstruktor
des Endpoints definieren wir schon die
Listing 5
public class ProductServiceEndpoint extends
AbstractJDomPayloadEndpoint {
private XPath categoryExpression;
private Namespace namespace;
private XPath supplierExpression;
private XPath dateRangeExpression;
public ProductServiceEndpoint () throws JDOMException {
namespace = Namespace.getNamespace("prod",
"http://www.itemis.de/hoa/spring/ws/product");
categoryExpression = XPath.newInstance("//prod:Category");
protected Element invokeInternal(Element requestElement)
throws Exception {
Category category = null;
Supplier supplier = null;
DateRange dateRange = null;
Element categoryElement = (Element) categoryExpression
.selectSingleNode(requestElement);
category = new Category();
category.setId(Integer.parseInt
(categoryElement.getChildText("id", namespace)));
category.setName(categoryElement.getChildText
("name", namespace));
categoryExpression.addNamespace(namespace);
supplierExpression = XPath.newInstance("//prod:Supplier");
supplierExpression.addNamespace(namespace);
dateRangeExpression = XPath.newInstance
("//prod:DateRange");
dateRangeExpression.addNamespace(namespace);
}
@Override
protected Element invokeInternal(Element requestElement){
return null ;
}
}
70 javamagazin 3|2010
Element supplierElement = (Element) supplierExpression
.selectSingleNode(requestElement);
supplier = new Supplier();
supplier.setId(Integer.parseInt
(supplierElement.getChildText("id", namespace)));
supplier.setName(supplierElement.getChildText("name",
namespace));
SimpleDateFormat dateFormat = new SimpleDateFormat
("MM-dd-yy");
Element dateRangeElement = (Element) dateRangeExpression
.selectSingleNode(requestElement);
dateRange = new DateRange();
dateRange.setStartDate(dateFormat.
parse(dateRangeElement.getChildText(
"startDate", namespace)));
XPath Expressions, mit denen wir später
den Body des SOAP-Requests parsen
wollen, um an die notwendigen Daten zu
kommen.
Die Methode invokeInternal bekommt als Parameter den Body des
SOAP-Requests. Mit den drei XPath
Expressions werden die Elemente für die
drei Parameter für die Servicemethode ermittelt. Doch halt! Wie rufen wir
diese Servicemethode überhaupt auf?
Wir haben noch keine Referenz auf die
Serviceklasse. Das erledigen wir schnell,
indem wir ein Feld und eine zugehörige
Setter-Methode für den ProductService
definieren. Nachdem dies erledigt ist,
können wir uns der Implementierung
der invokeInternal-Methode widmen.
Der eigentliche Serviceaufruf geschieht
mit Java-Mitteln, d. h. aus den Daten des
SOAP-Bodys müssen die entsprechenden Objekte erzeugt werden. In Listing
5 finden Sie eine mögliche Lösung dieser
Aufgabe.
Die Vorgehensweise ist einfach.
Erst wird das Element mit der XPath
Expression (z. B. Category) ermittelt.
Die Properties der zugehörigen Klasse werden dann mit der Funktion getChildText ermittelt. Etwas aufwändiger
ist die Erzeugung des DateRange-Objekts. Hier müssen wir den Inhalt der
Kindelemente in ein Datum wandeln.
Dazu können Sie am besten das SimpleDateFormat aus dem java.text Package
verwenden. Nun ist es an der Zeit, den
Service mit den frisch erstellten Objekten abzufragen:
List<Product> products = productService
.findProductsForSupplierAndCategoryInDateRange
(category, supplier, dateRange);
Jetzt ist das Meiste schon getan. Wir
haben eine Liste mit den gefundenen
Produkten. Allerdings stellt uns diese
Liste vor einige Probleme. Wenn Sie
sich das Klassendiagramm aus Abbildung 2 noch einmal ansehen, erkennen
Sie, dass die Klasse Product Referenzen
auf Category und Supplier hält. Da die
Methode invokeInternal ein jDOMElement als Rückgabe liefert, muss
der ganze Objektbaum, der an dem
Product hängt, in XML bereitgestellt
werden. Diesen Vorgang nennt man
www.JAXenter.de
Web Services mit Spring WS Enterprise
Marshalling. Spring WS liefert einen
leistungsfähigen O/X Mapper. Wie bei
Spring üblich, ist dies nur eine Abstraktionsschicht über vorhandene Frameworks:
JAXB 1 und 2
Castor
XMLBeans
JiBX
XStream
Um nun in unserem Endpoint einen
Marshaller zu verwenden, reicht es,
ein Feld vom Typ org.springframework.
oxm.Marshaller (ist ein Interface) und
die zugehörige Setter-Methode zu erstellen. Im nächsten Schritt erstellen wir
die zugehörige Spring-Konfiguration,
die eine konkrete Implementierung in
unseren Endpoint injiziert. Das Interface hat nur folgende interessante Methode:
Spiel. Einmal die abstrakte Klasse AbstractJDomPayloadEndpoint, mit der
wir unseren Endpoint erweitert haben.
Das andere Mal als wir den Marshaller
des Spring O/X Mappers verwendeten.
Doch nun ist es an der Zeit, sämtliche
Komponenten miteinander zu verdrahten. Es gibt zwei Klassen, die typische
Spring Beans sind: die ProductServiceund die ProductServiceEndpoint-Klasse. Der ProductServiceEndpoint hält
eine Referenz auf den ProductService.
Somit muss dies ebenfalls in der SpringKonfiguration abgebildet werden (Listing 7).
Diese Spring-Konfiguration können
wir als spring-ws-servlet.xml unter META-INF/spring abspeichern. Im nächsten Schritt wird die web.xml dahingehend konfiguriert, dass diese Datei beim
Start der Anwendung herangezogen
und der Spring-Kontext aufgebaut wird.
Zusätzlich ist bereits der Marshaller in-
jiziert worden. Der CastorMarshaller
kommt ohne jegliche weitere Konfiguration aus. Erst wenn das XML-Format,
in das der Marshaller die Objekte bereitstellen soll, angepasst werden muss,
kann der CastorMarshaller konfigurativ
angepasst werden.
Neben den beiden Klassen, die jetzt
miteinander verdrahtet wurden, müssen noch der Endpoint und die WSDLGenerierung konfiguriert werden. Die
Konfiguration des Endpoints ist recht
einfach mit einem Mapping zwischen
Namespace und der konfigurierten
Bean hergestellt. Optional können Sie
noch einen Logging Interceptor hinzufügen (Listing 8).
In Listing 9 sehen Sie die Konfiguration für die automatische WSDLGenerierung. Über die Properties portTypeName und locationURI können Sie
die generierte WSDL beeinflussen. Im
nächsten Schritt sehen Sie noch, wie die
void marshal(Object graph, javax.xml.transform.
Result result)
throws XmlMappingException, IOException;
Listing 6
Listing 8
protected Element invokeInternal(Element requestElement)
<bean class="org.springframework...mapping.
PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop
key="{http://www.itemis.de/hoa/spring/ws/product}
ProductRequest">
ProductServiceEndpoint</prop>
</props>
</property>
<property name="interceptors">
<bean
class="org.springframework...interceptor.
PayloadLoggingInterceptor"/>
</property>
throws Exception {
Um diese Methode aufzurufen, brauchen wir lediglich das Objekt, das in
XML bereitgestellt werden soll und eine
Implementierung des Interface javax.
xml.transform.Result. jDOM liefert bereits eine passende Implementierung
dieses Interface, sodass wir die Methode
nur um einige Zeilen erweitern müssen
(Listing 6).
Damit der Endpoint nun verwendet
werden kann, brauchen wir noch ein
paar weitere Bibliotheken. Die wichtigsten davon sind Castor und Jaxen. Castor
ist für das Marshalling zuständig und Jaxen wird für die Auswertung der XPath
Expressions benötigt. Allerdings ist die
pom.xml von Jaxen nicht sonderlich gut
gepflegt. Aus diesem Grund müssen einige Abhängigkeiten, die Jaxen definiert,
ausgeschlossen werden. Die vollständige
pom.xml kann auf der Heft-CD eingesehen werden.
Schritt 6: Spring konfigurieren
Bisher haben wir von Spring recht wenig gesehen. Die erstellten Klassen
waren allesamt POJOs. Lediglich zweimal kamen schon Spring-Artefakte ins
www.JAXenter.de
…
JDOMResult result = new JDOMResult();
marshaller.marshal(products, result);
return (Element) result.getResult().get(0);
}
Listing 7
<beans xmlns="http://www.springframework.org/schema/
beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/
schema/beans http://www.springframework.org/schema/
beans/spring-beans-2.5.xsd">
<bean id="ProductService"
class="de.itemis.hoa.spring.ws.service.ProductService"/>
<bean id="ProductServiceEndpoint"
class="de.itemis.hoa.spring.ws.endpoint.
ProductServiceEndpoint">
<property name="productService" ref="ProductService"/>
<property name="marshaller" ref="castorMarshaller"/>
</bean>
<bean id="castorMarshaller"
class="org.springframework.oxm.castor.CastorMarshaller"/>
</beans>
</bean>
Listing 9
<bean id="product"
class="org.springframework.ws.wsdl.wsdl11.
DefaultWsdl11Definition">
<property name="schema" ref="schema" />
<property name="portTypeName" value="ProductResource" />
<property name="locationUri" value="/productService/" />
<property name="targetNamespace"
value="http://www.itemis.de/hoa/spring/ws/product/
definitions" />
</bean>
<bean id="schema" class="org.springframework.xml.xsd.
SimpleXsdSchema">
<property name="xsd" value="classpath:META-INF/schema/
Product.xsd" />
</bean>
javamagazin 3|2010 71
Enterprise Web Services mit Spring WS
locationURI an die wirkliche Serverumgebung angepasst werden kann. Die
Klasse DefaultWsdl11Definition bietet
noch einige andere Konfigurationsparameter, die Sie im entsprechenden Javadoc nachlesen
können.
Schritt 7: Konfiguration
des Web Descriptors
Anwendung enthält noch keinen Clientcode. Wir können den Web Service
nicht ausprobieren. Jetzt kommt SoapUI
[6] ins Spiel. SoapUI ist ein Web-Service-Testing-Tool. Damit
können SOAP-Requests
abgesetzt werden und genau diese Funktion verwenden wir auch, um den
Web Service aufzurufen.
Im Beispielprojekt finden
Sie ein Verzeichnis soapui. Die dort enthaltene XML-Datei ist
ein SoapUI-Projekt. Wenn Sie dieses
Projekt öffnen, finden Sie links im Navigator einen vorbereiteten Request. Diesen können Sie ausführen und erhalten
einen Response mit zwei Products.
Mit dem Testing-Tool
SoapUI können SOAPRequests abgesetzt werden.
Der letzte Schritt ist es, den
Web Descriptor (web.xml)
zu konfigurieren. Die web.xml befindet sich im Verzeichnis src/main/web/
WEB-INF. In dieser web.xml werden nur
das MessageDispatcherServlet aus dem
Spring WS Framework und die zugehörigen Mappings konfiguriert (Listing
10). Das MessageDispatcherServlet hat in
unserem Beispiel zwei Parameter: contextConfigLocation und tarnsformWsdlLocations. Der erste Parameter gibt an,
wo die initiale Kontextkonfiguration zu
finden ist. In unserem Beispiel ist das
die spring-ws-servlet.xml, die wir im vo-
Listing 10
<web-app id="WebApp_ID" version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Product Catalogue Service</display-name>
rangegangenen Schritt erstellt haben.
Der zweite Parameter ist fast noch interessanter. Hiermit können Sie angeben,
ob die URIs, die in der WSDL enthalten
sind, so umgewandelt werden, dass der
aktuelle Servername, Port und Anwendungsname enthalten sind.
Schritt 8: Starten der Webanwendung und Testen des Web Service mit SoapUI
In den letzten 7 Schritten haben wir eine Anwendung erstellt, die einen Web
Service zur Verfügung stellt. Der letzte
Teil unseres Vorhabens besteht darin,
die Anwendung auf einem Tomcat zu
deployen. Mit Eclipse geht das sehr einfach mit Run as... | Run On Server.
Die Server-Runtime haben Sie bereits
bei der Erstellung des Projekts festgelegt.
Die Anwendung wird automatisch auf
dem Server deployt und gestartet. Nach
wenigen Sekunden ist das erledigt. Ein
Aufruf des URLs http://localhost:8080/
articles-spring-ws-dom/productService/
product.wsdl zeigt die von Spring WS
generierte WSDL. Doch was nun? Die
Zusammenfassung
In diesem ersten Teil der Artikelserie
haben wir bereits einen funktionsfähigen Web Service erstellt. Allerdings
sind viele Dinge noch nicht optimal.
Zum einen haben wir noch keinen richtigen Client. Zum anderen arbeiten wir
direkt auf dem SOAP-Body. Das ist bei
größeren Requests nicht zielführend.
Viel lieber wollen wir direkt mit JavaObjekten arbeiten. Deswegen werden
wir im nächsten Teil den Web Service
auf JAXB 2 umstellen und einen Client
implementieren, sodass wir SoapUI
nicht mehr für das Testen der Anwendung brauchen.
<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>
org.springframework.ws.transport.http.MessageDispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath:META-INF/spring/spring-ws-servlet.xml
</param-value>
Thorsten Kamann ist als Softwarearchitekt und als Coach bei itemis tätig.
Seine Schwerpunkte sind webbasierte Technologien, MDSD, leichtgewichtige und flexible Architekturen und Open Source. Er ist Project Lead bei
der Fornax Platform, einer Plattform für die Entwicklung von MDSD-related
Tools und Groovy Commiter. Darüber hinaus schreibt er Bücher, veröffentlicht
regelmäßig Artikel in Fachmagazinen und hält Vorträge auf Fachkonferenzen
zu obigen Themen.
</init-param>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
Links & Literatur
</init-param>
[1] http://www.springsource.org/
</servlet>
[2] http://ws.apache.org/axis/
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
[3] http://cxf.apache.org/
[4] http://static.springsource.org/spring-ws/sites/1.5/
[5] http://static.springsource.org/spring-ws/sites/1.5/reference/html/
why-contract-first.html
[6] http://www.soapui.org/
[7] http://www.thorsten-kamann.de/
72 javamagazin 3|2010
www.JAXenter.de
Herunterladen