Aug 29

Dan Diephouse gibt eine Einführung in Apache CXF:

In this webinar, Dan will give an introductory view of building services with Apache CXF. He’ll look at the technologies CXF offers and how they can be used within the context of a service oriented architecture. First, he’ll walk through building a contract first SOAP web service with JAX-WS. Then, he’ll look at building RESTful XML and JSON web services with CXF. Along the way he’ll discuss topics such as how and when to use the WS-* standards, how to secure web services, and service design.

Die Teilnahme am Seminar ist kostenlos. Registrierung erfolgt hier.» » » » » » » » »

Aug 25

Logging Frameworks für Java:

Haben Sie Vorschläge zur Ergänzung der Liste?» » » »

Aug 24

In einem meiner früheren Artikel habe ich erläutert wie man mit Hilfe von Annotations unter Verwendung von JSR-181, JAXB sowie Apache CXF und Spring Framework ein Webservice implementieren kann. Dieser Artikel beschreibt wie man die Generierung der WSDL Datei mit Annotations beeinflussen und somit den Webservice Contract optimieren kann.

Update: Siehe auch Artikel zur WSDL-First Development.

Die Beispiele in diesem Tutorial basieren auf den Source Code aus dem vorangegangem Artikel. Der komplette Source Code aus diesem Artikel inklusive einem Maven Build Script steht zum Download bereit.

Schritt 1: Legen Sie den Namespace fest.

Bei der Generierung der WSDL-Datei verwendet Apache CXF den Java Package Namen als Standard-Namespace. Aus der Klasse Customer, die im Package com.mycompany.customerrelations liegt, wird standardmäßig das Element Customer im Namespace http://customerrelations.mycompany.com/ generiert. Oft ist es jedoch gewünscht dieses Verhalten zu verändern und z.B. zuerst den Domainnamen im Namespace zu verwenden. Der Namespache der Elemente lässt sich über die Annotations @XmlSchema und @WebService verändern. Dabei wird @XmlSchema für Datenstrukturen und @WebService für Service-Interfaces verwendet. Hier ein Beispiel:

@XmlSchema(namespace="http://www.mycompany.com/customerrelations")
@WebService(targetNamespace="http://www.mycompany.com/customerrelations", name="CustomerService")

Schritt 2: Definieren Sie die SOAP-Action für alle Operationen.

Anhand der SOAP-Action Property im Transport-Protokoll wird definiert wie eine SOAP-Nachricht interpretiert werden sollte bzw. welche Operation aufgerufen werden sollte. Apache CXF setzt standardmäßig den SOAP-Action Namen auf einen leeren String, also z.B: <soap:operation soapAction=""/>. Dies hat zur Folge dass die Bedeutung der SOAP-Nachricht anhand von HTTP Request URL interpretiert wird. Bei vielen Protokollen wie z.B. JMS oder SMTP ist diese Information jedoch nicht vorhanden und sollte daher im Header des Transport-Protokolls übergeben werden. Definieren Sie daher für jede Operation den SOAP-Action Namen. Verwenden Sie dazu die Annotation @WebMethod wie z.B.: @WebMethod(action = "getCustomer").

Schritt 3: Bestimmen Sie den Namen für alle Input-Parameter.

In Java kann bei einer kompilierten Klasse der Name eines Parameters aus der Signatur einer Methode nicht bestimmt werden. So ist es zwar möglich den Datentyp und die Reihenfolge der Parameter auszulesen, nicht jedoch den Namen des Parameters. Bei der Generierung der WSDL-Datei verwendet Apache CXF daher Parameter-Namen wie z.B. “arg0″. Für die Methode “public Customer getCustomer(String customerNumber)” im Service-Interface CustomerService wird z.B. folgende Schema-Definition generiert:

Array

Um die SOAP-Nachricht besser lesbar zu machen, sollten daher alle Input-Parameter mit einem Namen versehen werden. Dies kann mit der Annotation @WebParam erfolgen. Hier ein Beispiel:

@WebParam(targetNamespace="", name="customerNummber")

Schritt 4: Legen Sie den Namen für alle Output-Parameter fest.

Das Problem bei Input-Parametern (siehe Schritt 3) gilt natürlich auch für Output-Parameter. Der Name des Parameters lässt sich nicht aus der Java Klasse ermitteln. Apache CXF generiert in diesem Fall bei Response-Nachricht ein Element mit dem Namen “return”. Hier ein Auszug aus der WSDL-Datei:

Array

Die SOAP-Nachrichten sind in diesem Fall natürlich nicht besondern gut lesbar. Verbessern kann man dies mit der Annotation @WebResult. Dies könnte beispielweise so aussehen:

@WebResult(targetNamespace="", name="customers")

Schritt 5: Bestimmen Sie die Pflichtfelder.

Apache CXF definiert standardmäßig alle Elemente in der WSDL-Datei als optional, also z.B.:

<xs:element minOccurs=”0″ name=”lastname” type=”xs:string”/>

Ein guter Webservice Contract sollte jedoch unbedingt notwendige Datenelemente wie z.B. den Nachnamen bei einer Person als Pflichtfeld definieren. Dies kann über die Annotation @XmlElement beeinflusst werden. Ein Beispiel:

@XmlElement(required=true)

Schritt 6: Legen Sie fest, welche Datenelemente “nullable” sind.

In manchen Fällen ist es notwendig Null-Werte für bestimmte Elemente zu übermitteln. Wenn für den Vorname einer Person auch ein Null-Wert übermittelt werden darf, so könnte dies in der SOAP-Nachricht so aussehen:

<firstname xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>

Standardmäßig generiert Apache CXF die WSDL-Datei, dass Null-Werte nicht erlaubt sind. Für Datenelemente für die auch Null-Werte zulässig sind, muss dies daher expliziet definiert werden. Dies kann ebenfalls über die Annotation @XmlElement definiert werden. Hier ein Beispiel:

@XmlElement(required=true, nillable=true)

Schritt 7: Definieren Sie den Datentyp für das XML-Schema.

Bei der Generierung der WSDL-Datei werden Java Datentypen auf bestimmte XML-Schema Datentypen gemappt. Der Java-Datentyp java.lang.String wird beispielweise auf “xsd:string” gemappt. In manchen Fällen ist dieses Mapping jedoch nicht ganz sinnvoll. Der Nachname einer Person sollte beispielweise kein “Carriage Return” oder “Tab” als Zeichen enthalten. Hier wäre der XML-Schema Datentyp “token” die bessere Wahl.

Der Java-Datentyp java.util.Calendar wird standardmäßig auf den XML-Schema Datentyp “xsd:dateTime” gemappt. Beim Geburtsdatum einer Person ist jedoch in der Regel nur das Datum und nicht die Zeit von Bedeutung. Hier wäre der XML-Schema Datentyp “xsd:date” sinnvoller. Der XML-Schema Datentyp kann über die Annotation @XMLSchemaType festgelegt werden. Für das Geburtsdatum einer Person könnte dies folgendermaßen aussehen:

@XmlSchemaType(name="date")

Schritt 8: Legen Sie den Type-Adapter fest.

In manchen Fällen ist es notwendig den Marshalling-Prozess von Datenstrukturen zu beeinflussen. Dies ist mit der Annotation @XmlJavaTypeAdapter und mit der Implementierung eines XMLAdapters möglich. Siehe dazu auch den Artikel in Kohsuke Kawaguchi’s Blog.

Hat man sich beispielsweise entschieden den XML-Schema Datentyp “xsd:token” für ein Datenelement zu verwenden, so sollte der CollapsedStringAdapter für die Deserialisierung des Strings verwendet werden. Hier ein Beispiel dazu:

@XmlJavaTypeAdapter(CollapsedStringAdapter.class)

Schritt 9: Legen Sie die ID bei referenzierten Objekten fest.

Datenelemente über die auf bestimmte Datenstrukturen referenziert werden kann wie z.B. die Kundennummer eines Kunden sollte den XML-Schema Datentyp “xsd:ID” erhalten. Verwenden Sie zu diesem Zweck die Annotation @XmlID.

Schritt 10: Bestimmen Sie die Reihenfolge der Elemente.

Apache CXF definiert standardmäßig die Elemente im XML-Schema sortiert in alphabetischer Reihenfolge. Für die Datenstruktur “Adresse” mit den Datenelementen “line1″, “line2″, “postalCode”, “city” und “country” würde dies bedeuten, dass das Element “city” in der SOAP-Nachricht als erstes Element vor allen anderen Elementen übertragen wird. Die SOAP-Nachricht ist somit schlechter lesbar.

Die Reihenfolge der Datenelemente kann über die Annotation @XmlType beeinflusst werden. Für die Datenstruktur einer Adresse könnte dies beispielweise so aussehen:

@XmlType(name = "Address", propOrder = {
"line1", "line2", postalCode", city", country")

Abschließende Gedanken

Wenn Sie alle 10 Schritte auf Ihren Webservice angewandt haben, so werden Sie mit Apache CXF eine relativ qualitativ hochwertige WSDL-Datei generieren können. Wünschenswert wäre es die XML-Schema Definition für die Datenstrukturen noch detaillierter festlegen zu können und z.B. die minimale oder maximale Länge von Texten mit “minLength” und “maxLength” anzugeben. Nach meinem aktuellen Wissensstand ist dies jedoch mit Annotations momentan noch nicht möglich. Auch die Einschränkung eines String mit Hilfe von Regulären Ausdrücken funktioniert momentan noch nicht über Annotations. Dies spricht gegen die Implementierung von Webservices nach dem “Java Code First”-Ansatz. Ich bin jedoch zuversichtlich dass diese Funktionen bald über den JSR-Prozess spezifiziert und demnächst auch von Apache CXF implementiert werden.

Haben Sie Feedback oder weitere Vorschläge? Ich freue mich über Ihre Kommentare.» » » » » » » » » » »

Aug 23

Man ist auf der Suche nach einem Fehler im Programm und versucht dem Problem auf die Spur zu kommen in dem man verschiedene Ausgaben mit System.out.prinln() (oder Logging Framework) auf der Konsole ausgibt. Hat man schließlich den Fehler gefunden, müssen alle überflüssigen Logging-Ausgaben wieder aus dem Quellcode entfernt werden. Kennen Sie das Problem?

Eine alternative Möglichkeit für dieses Vorgehen sind Conditional Breakpoints in der Eclipse IDE. Schreiben Sie Ihre Logging-Ausgaben ins Conditional Breakpoint und geben am Ende “false” als Return-Wert zurück. Dies bewirkt, dass der Debuger an diesem Breakpoint nicht anhält. Die Logging-Statements werden jedoch trotzdem ausgegeben. Hier ein Beispiel:

Condition Breakpoint

Vorteile:

  • Der Quellcode wird nicht unnötig durch Logging-Ausgaben verunreinigt.
  • Dieses Vorgehen funktioniert auch mit Code, denn man nicht verändern kann.

» » » » » »

Aug 22

Lösungen für den Aufbau eines eigenen Maven Repositories:

Artikel: Setting Up a Maven Repository

Haben Sie Vorschläge zur Ergänzung der Liste?» » »

Aug 17

Bei der Entwicklung von Eclipse Plugins lasse ich die Eclipse Logging Ausgaben immer auf der Eclipse Console ausgeben. Dazu muss man beim Start der Eclipse Anwendung zusätzlich das Argument “-consoleLog” übergeben. Hier ein Beispiel:

Eclipse RCP Conlose Log

Vorteile:

  • Sie müssen nicht mehr in der Log-Datei suchen.
  • Ein Klick auf den Stacktrace öffnet die entsprechende Source Datei.

Aug 16

Bewährte Vorgensweise bei Exception Handling in Java:

Weitere Meinungen:

  • Bruce Eckel (”Thinking in Java”)
    Standpunkt: Checked Exceptions are not needed at all!
  • Alan Griffiths
    Standpunkt: Use unchecked exceptions with caution!

» » » »

Aug 15

Dieser Blogbeitrag zeigt wie man mit gängigen Java Frameworks einen einfachen Webservice implementiert. Dabei wird nach dem Ansatz vorgegangen zuerst die Java Klassen statt der WSDL zu entwickeln. Um die Implementierung als Webservice zu deployen und die WSDL automatisch generieren zu können, werden die Java Klassen über Annotations mit den notwendigen Metadaten versehen.

Update: Siehe auch Artikel zur WSDL-First Development.

Das hier beschriebene Beispiel basiert auf Apache CXF 2.0, JSR-181, JAXB 2.1, Spring Framework, sowie Jetty als embedded HTTP Server um den Webservice bereitzustellen.

Der komplette Source Code inklusive einem Maven Build Script steht zum Download bereit.

Schritt 1: Anforderungen aufnehmen, dokumentieren und Schnittstelle entwerfen

Der Start für jeden neuen Webservice sind in der Regel neue Anforderungen aus dem Fachbereich. Diese Anforderungen müssen zunächst einmal aufgenommen und dokumentiert werden. Daraus kann man anschließend eine entsprechende Schnittstelle für den Service entwerfen. In diesem Beispiel wird ein einfacher Service zu Verwaltung von Kunden beschrieben. Das folgende UML-Diagramm zeigt die Schnittstelle des Services sowie die Datenobjekte mit denen der Service arbeitet:

CustomerService Classdiagram

Wie man dem Klassendiagramm entnehmen kann, wird unser Beispiel-Service eine einzige Methode anbieten, die eine Kundenummer als Inputparameter entgegennimmt und einen Kunden als Outputobjekt zurück liefert. Die Serviceschnittstelle wurde für dieses Beispiel natürlich stark vereinfacht.

Schritt 2: Datenstrukturen als Java Klassen implementieren

Die Java Klassen für die Datenstrukturen sind einfache POJOs und enthalten nur die entsprechenden Getter- und Setter-Methoden für die Attribute.

Customer.java
Person.java
Gender.java
Address.java

Schritt 3: Service Interface definieren

Als nächstes muss das Service Interface implementiert werden und mit entsprechenden JSR-181 Annotations versehen werden:

Array

Während die Annotation @WebService unbedingt erforderlich ist, ist die @WebMethod Annotation optional. Für die Nutzung von SOAP over JMS sollte jedoch hier die SOAP-Action angegeben werden.

CustomerService.java
BusinessLogicException.java

Schritt 4: Service Interface implementieren

Die eigentliche Implementierung der Businesslogik findet der Klasse CustomerServiceImpl statt welche das Interface ContactService implementiert:

Array

Wie man dem Source-Code entnehmen kann, gibt diese Implementierung immer den Kunden „Max Müller“ als Output zurück wenn die Kundennummer „12345“ als Inputparameter übergeben wurde und in allen anderen Fällen wird ein BusinessLogicException mit entsprechender Fehlermeldung geworfen.

CustomerServiceImpl.java

Schritt 5: Object-Factory sowie Request- und Response Klassen implementieren

Apache CXF 2.0 verwendet JAXB als Default-Datamapping. Aus diesem Grund ist es notwendig neben den Datenobjekten auch eine Factory für die Erzeugung der Datenobjekten sowie die Request- und Response Klassen zu implementieren.

ObjectFactory.java
GetCustomerRequest.java
GetCustomerResponse.java

Hierbei ist wichtig, dass die Request- und Response Klassen mit @XmlRootElement Annotation versehen sind.

Schritt 6: Service bereitstellen

In diesem Beispiel wird der Service mit Hilfe von Jetty über HTTP bereitgestellt. Die Konfiguration der Komponenten erfolgt über das Spring Framework. Die Spring Konfiguration ist in diesem Beispiel in der Datei server-applicationContext.xml enthalten.

server-applicationContext.xml

Über die main-Methode in der Klasse ServiceServer wird der Spring Context initialisiert und somit der Jetty Webcontainer gestartet, welcher die Service Implementierung unter http://localhost:9090/customerService verfügbar macht.

ServiceServer.java

Schritt 7: Client für den Service implementieren

Um den Service anzusprechen und testen zu können, empfiehlt es sich ein Client zu implementieren. Die Implementierung von Clients ist mit Apache CXF 2.0 relativ einfach deklarativ mit Hilfe des Spring Frameworks möglich. Die Spring Konfiguration für den Service Client ist in diesem Beispiel in der Datei client-applicationContext.xml enthalten.

client-applicationContext.xml

Die Klasse ServiceClient enthält eine main-Methode in der Spring Context initialisiert wird und auf das entsprechende Client-Bean zugegriffen wird.

ServiceClient.java

Alternativ eignet sich auch soapUI hervorragend zum Testen von Webservices.

Schritt 8: Projekt kompilieren und WSDL generieren

Um das Projekt einfach kompilieren zu können habe ich diesem Beispiel ein Maven Build Script beigefügt. Beim Kompileren des Projekts wird auch unter Zuhilfenahme des Java2WSDL Tools von Apache CXF die WSDL-Datei automatisch generiert. Diese WSDL-Datei wird im Verzeichnis /target/generated/wsdl/ abgelegt.» » » » » » » » »

Aug 14

Es scheinen ein relativ weit verbreitetes Missverständnis zu existieren, dass die Klasse java.text.SimpleDateFormat thead-sicher ist. Dies ist nicht korrekt, denn zumindest die Methode „format()“ verändert den Zustand der Instanz. In JavaDoc von java.text.SimpleDateFormat heißt es:

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

Vorschläge zur Lösung des Problems:

  • Aufrufe der Methode „format()“ synchronisieren. Dies könnte z.B. durch die Implementierung einer Wrapper-Klasse erfolgen.
  • Joda Time Framework verwenden. Die Klasse org.joda.time.format.DateTimeFormat ist thread-sicher and immutable.
  • Thread-Local verwenden wie z.B.:
  • Array

Achtung: Generell sollte man bei Verwendung von ThreadLocal sehr vorsichtig sein. Insbesondere wenn in der Anwendung Thread-Pools zum Einsatz kommen. Variablen, die in ThreadLocal abgelegt werden, werden vom Garbage Collector nicht bereinigt und sind auch für andere Threads sichtbar. Dies ist kann ein potentielles Sicherheitsproblem sein. In diesem Fall sehe ich jedoch kein Problem.» » » » »

Aug 13

Die Funktion parse(String) der Klasse java.text.DateFormat verarbeitet standardmäßig auch unsinnige Datumsangaben. Hier ist ein kleines Beispiel, welches das Verhalten der Funktion demonstriert:

Array

Wie man dem Beispiel entnehmen kann, wird ein zu hoher Datumswert einfach auf den nächsten Monat übertragen. Dieser Modus lässt sich jedoch über den Aufruf von „setLenient(false)“ ausschalten.» » »