Web Service Tutorial - Fault-Handling in Web Services mit JAX-WS

Realisiert mit Eclipse und JAX-WS

Autor: Kai Stapel
Version: 24.05.2010

Hinweis: Dieses Tutorial ist im Rahmen der Übung zur Vorlesung Entwicklung service-orientierter Architekturen und Anwendungen (SOA 2008 und SOA 2010) entstanden.

In diesem Tutorial wird beschrieben, wie der Gästebuch Webservice aus dem Gästebuch-Webservice-Tutorial um Fault-Handling (auch bekannt als Exception-Handling) erweitert wird. Es wird wieder der Top-Down-Ansatz (WSDL-to-Java) verfolgt, bei dem zunächst der Fault in der Service-Schnittstelle (WSDL) definiert und anschließend basierend auf dieser Schnittstelle die Service-Implementierung erzeugt wird.

Voraussetzungen

Dieses Tutorial setzt voraus, dass Sie die Java JDK, Eclipse mit der Web-Tools-Platform (WTP) (wir empfehlen die Eclipse IDE for Java EE Developers, da sie WTP bereits enthält) installiert und Eclipse korrekt mit Tomcat verbunden haben. Zudem sind Kenntnisse aus dem JAX-WS-Webservice-Tutorial hilfreich.

Tutorial

  1. Neues Projekt: Erstellen Sie ein neues Java-Projekt mit dem Namen JaxWSGBFaultService. Erstellen Sie in diesem Projekt mit Rechtsklick New -> Folder einen neuen Ordner mit dem Namen xml.
  2. XML-Import: Improtieren Sie in den Ordner xml die Gästebuch-Schema-Datei und die Gästebuch-WSDL.

    Screenshot: Neues Projekt und importierte Gästebuch-XML-Dateien

  3. Fault erstellen: Fügen Sie der Operation getEntries einen neuen Fault hinzu, indem Sie mit Rechtsklick auf die Operation das Kontextmenü öffnen und Add Fault wählen.

    Screenshot: Neuen Fault hinzufügen

    Wechseln Sie in die Properties view des Faults, indem Sie mit Rechtsklick auf den Fault-Teil der Operation getEntries (nicht den Part der Nachricht und nicht das Schema-Element) Show properties wählen.

    Screenshot: In Properties-View wechseln

    Dort mit General -> Message -> New... eine neue Nachricht mit dem Namen NoEntriesYetFault erstellen.

    Screenshot: Neue Fault-Nachricht erstellen 1

    Screenshot: Neue Fault-Nachricht erstellen 2

    Anschließend noch (1., 2.) den Part-Teil der Nachricht in parameters umbenennen und (3., 4.) ein neues Schema-Element mit dem gleichen Namen NoEntriesYetFault erstellen.

    Screenshot: Neues Fault-Element erstellen

  4. Element-Typ anpassen: Stellen Sie den Schema-Typ des Schema-Elements NoEntriesYetFault auf xsd:string, indem Sie zunächst in den Inline-Schema-Editor wechseln, anschließend per Rechtsklick auf das Schema-Element Set Type -> Browse... auswählen und schließlich den Datentyp string aus dem Namespace http://www.w3.org/2001/XMLSchema einstellen.

    Screenshot: In den Inline-Schema-Editor wechseln

    Screenshot: Set-Type wählen

    Screenshot: Nach Schema-Typ string suchen

  5. Binding neu generieren: Vor der Generierung der Java-Klassen muss nun noch das Binding neu erstellt werden. Klicken Sie dazu per Rechtsklick auf das Binding-Symbol und wählen Generate Binding Content.... Wählen Sie im darauf folgenden Menü Overwrite existing binding information und klicken Sie auf Finish. Speichern Sie abschließend die WSDL.

    Screenshot: WSDL: Binding generieren 1

    Screenshot: WSDL: Binding generieren 2

  6. Die fertige WSDL mit Fault: Der folgende Ausschnitt aus der WSDL zeigt die wesentlichen Teile des NoEntriesYetFault.
    ...
    	<xsd:element name="NoEntriesYetFault" type="xsd:string" />
    ...
    	<wsdl:message name="NoEntriesYetFault">
    		<wsdl:part name="parameters" element="tns:NoEntriesYetFault" />
    	</wsdl:message>
    ...
    	<wsdl:operation name="getEntries">
    		<wsdl:input message="tns:getEntriesRequest" />
    		<wsdl:output message="tns:getEntriesResponse" />
    		<wsdl:fault message="tns:NoEntriesYetFault" name="fault" />
    	</wsdl:operation>
    ...
    

    Screenshot: WSDL: Übersicht

  7. Java-Klassen mit wsimport generieren: Öffnen Sie ein Terminal und wechseln Sie in das Service-Projekt-Verzeichnis. Generieren Sie die Klassen mit folgendem Befehl:
    wsimport -Xnocompile -s src xml/GuestBook.wsdl
    
    Der Schalter -Xnocompile sorgt dafür, dass nur Java-Quellcode (.java) und keine kompilierten Klassen (.class) erzeugt werden. Der Schalter -s gibt den Zielordner an. Aus den Target-Namespaces werden Java-Packages erzeugt, was in unserem Beispiel dafür sorgt, dass Schema- und Service-Klassen in unterschiedlichen Packages landen.

    Screenshot: wsimport Aufruf

    Screenshot: Übsericht der generierten Klassen

  8. Webservice implementieren: Implementieren Sie nun den Gästebuch-Webservice. Erstellen Sie dazu im Package de.unihannover.se.soa10.guestbook.service die Klasse GuestBookImpl. Die Klasse implementiert das Interface de.unihannover.se.soa10.guestbook.service.GuestBook. Annotieren Sie die Klassendeklaration mit
    @WebService(name = "GuestBook",
    	serviceName = "GuestBook",
    	portName = "GuestBookSOAP",
    	targetNamespace = "http://soa10.se.unihannover.de/GuestBook/Service",
    	endpointInterface = "de.unihannover.se.soa10.guestbook.service.GuestBook")
    
    Der Parameter name mapped auf wsdl:portType, serviceName auf wsdl:service, portName auf wsdl:port, targetNamespace auf den Target-Namespace dee WSDL und endpointInterface auf den Endpoint-Interface-Namen. Das Interface wurde zuvor mit wsimport generiert. Um den Fault auszulösen, muss nur die generierte Exception NoEntriesYetFault geworfen werden.
    // throws fault if guest book is empty
    throw new NoEntriesYetFault("NoEntriesYetFault",
    	"There are no entries in this guest book, yet. " +
    	"You can either post a message or come back later.");
    
    Nach Implementierung der Methoden insertEntry und getEntries sollte die Klasse so aussehen (inkl. Debug-Ausgaben): GuestBookImpl.java
    package de.unihannover.se.soa10.guestbook.service;
    
    import javax.jws.WebService;
    
    import de.unihannover.se.soa10.guestbook.schema.GuestBookEntry;
    
    @WebService(name = "GuestBook",
    		serviceName = "GuestBook",
    		portName = "GuestBookSOAP",
    		targetNamespace = "http://soa10.se.unihannover.de/GuestBook/Service",
    		endpointInterface = "de.unihannover.se.soa10.guestbook.service.GuestBook")
    public class GuestBookImpl implements GuestBook {
    
    	private de.unihannover.se.soa10.guestbook.schema.GuestBook guestBook;
    	
    	public GuestBookImpl() {
    		super();
    		this.guestBook = new de.unihannover.se.soa10.guestbook.schema.GuestBook();
    	}	
    	
    	@Override
    	public de.unihannover.se.soa10.guestbook.schema.GuestBook getEntries(
    			String parameters) throws NoEntriesYetFault {
    		System.out.println("DEBUG Info: fault webservice: "
    				+ "getEntries (parameter = \""
    				+ parameters + "\") called...");
    	
    		if(this.guestBook == null || this.guestBook.getEntry().size() == 0) {
    			System.out.println("DEBUG Info: fault webservice: "
    					+ "Guest book is empty. Throwing fault...");
    
    			// throws fault if guest book is empty
    			throw new NoEntriesYetFault("NoEntriesYetFault",
    					"There are no entries in this guest book, yet. " +
    					"You can either post a message or come back later.");
    		}
    
    		System.out.println("DEBUG Info: fault webservice: "
    				+ "Guest book is not empty...");
    		
    		return this.guestBook;
    	}
    
    	@Override
    	public void insertEntry(GuestBookEntry entry) {
    		System.out.println("DEBUG Info: fault webservice: "
    				+ "insertEntry (ID = "
    				+ entry.getID()
    				+ ", name = \""
    				+ entry.getName()
    				+ "\", eMail = \""
    				+ entry.getEMail()
    				+ "\", message size = "
    				+ entry.getMessage().length() + ") called...");
    		
    		this.guestBook.getEntry().add(entry);
    	}
    
    }
    
  9. Service-Starter implementieren: Um den Fault ausprobieren zu können, brauchen wir einen Server, auf dem der Service läuft. Für lokale Tests bringt das JAX-WS Framework eine einfache Möglichkeit zum Ausführen eines JAX-WS-Webservice mit. Mit folgender Anweisung startet man einen Java-Standalone-Server, auf dem der Webservice läuft:
    Endpoint endpoint = Endpoint.publish("http://localhost:8080/GuestBook", new GuestBookImpl());
    
    Erstellen Sie dazu im Package de.unihannover.se.soa10.guestbook eine neue Klasse GuestBookServiceStarter mit Main-Methode. ACHTUNG: Aus Sicherheitsgründen ist es wichtig, dass bei einem Fault nicht der gesamte Stack-Trace der Java-Exception an den Client geschickt wird. Dies gilt zumindest für den Produktiveinsatz von Webservices. In JAX-WS ist dies allerdings das Default-Verhalten. Durch setzten des System-Properties com.sun.xml.internal.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace auf true kann das geändert werden.
    // disable forwarding of stack trace
    System.setProperty(
    		"com.sun.xml.internal.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace",
    		"true");
    
    Die Main-Methode sieht inklusive Debug-Ausgaben wie folgt aus:
    Auszug aus GuestBookServiceStarter.java
    	public static void main(String[] args) throws IOException {
    		
    		// disable forwarding of stack trace
    		System.setProperty(
    				"com.sun.xml.internal.ws.fault.SOAPFaultBuilder.disableCaptureStackTrace",
    				"true");
    
    		GuestBook service = new GuestBookImpl();
    
    		System.out.println("DEBUG Info: fault webservice: Starting webservice...");
    		Endpoint endpoint = Endpoint.publish("http://localhost:8080/GuestBook", service);
    		
    		System.out.println("DEBUG Info: fault webservice: Server is running...");
    		
    		// keep server running until quit is pressed
    		JOptionPane.showOptionDialog(null,
    				"Der Service wurde gestartet.",
    				"Gästebuch-Webservice mit Fault-Handling",
    				JOptionPane.CANCEL_OPTION,
    				JOptionPane.PLAIN_MESSAGE,
    				null,
    				new String[]{"Service beenden"},
    				"Service beenden");
    		
    		System.out.println("DEBUG Info: fault webservice: Stopping webservice...");
    		endpoint.stop();
    	}
    
    Wenn der Service erfolgreich gestartet wurde, erscheint ein Nachrichten-Dialog. Zum Beenden des Service klicken Sie auf "Service beenden".

    Screenshot: Nachrichten-Dialog des laufenden Webservice

  10. Webservice mit Fault testen: Testen Sie den Service zum Beispiel mit dem Eclipse Web-Service-Explorer.
    Die SOAP-Nachricht des Faults sieht wie folgt aus:
    <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
      <S:Body>
        <S:Fault xmlns:ns3="http://www.w3.org/2003/05/soap-envelope">
          <faultcode>S:Server</faultcode>
          <faultstring>NoEntriesYetFault</faultstring>
          <detail>
            <ns2:NoEntriesYetFault
                xmlns="http://soa10.se.unihannover.de/GuestBook/Schema"
                xmlns:ns2="http://soa10.se.unihannover.de/GuestBook/Service">
              There are no entries in this guest book, yet.
              You can either post a message or come back later.
            </ns2:NoEntriesYetFault>
          </detail>
        </S:Fault>
      </S:Body>
    </S:Envelope>
    

Eclipse-Projekte

Der fertige JAX-WS Gästebuch Web Service mit Fault-Handling kann direkt in Eclipse als Projekt importiert werden. Klicken Sie dazu auf Import -> General -> Existing Projects into Workspace -> Select Archive File....

Weitere Tutorials des Fachgebiets


Letzte Änderung: 06.06.2011 von Kai Stapel