[RESTful Webservices mit JAX-RS]



Ähnliche Dokumente
RESTful Web. Representational State Transfer

Wiederholung: Beginn

Aktuelle Technologien zur Entwicklung verteilter Anwendungen RESTful Web Services mit JAX-RS

WebService in Java SE und EE

Anleitung zur Webservice Entwicklung unter Eclipse

Session Beans & Servlet Integration. Ralf Gitzel ralf_gitzel@hotmail.de

Übung: Verwendung von Java-Threads

Verteilte Systeme: Übung 4

Step by Step Webserver unter Windows Server von Christian Bartl

Enterprise Applikation Integration und Service-orientierte Architekturen. 09 Simple Object Access Protocol (SOAP)

Version Deutsch In diesem HOWTO wird beschrieben wie Sie Ihren Gästen die Anmeldung über eine SMS ermöglichen.

Connecting Content. User Manual. Version: 1.2

OP-LOG

Java Kurs für Anfänger Einheit 5 Methoden

Einführung in die Java- Programmierung

Containerformat Spezifikation

SEP 114. Design by Contract

Containerformat Spezifikation

Anwendungsprotokolle: HTTP, POP, SMTP

Objektorientierte Programmierung für Anfänger am Beispiel PHP

Flash, Network und Facebook. Steven Mohr

Verschlüsseln Sie Ihre Dateien lückenlos Verwenden Sie TrueCrypt, um Ihre Daten zu schützen.

MailUtilities: Remote Deployment - Einführung

EJB Beispiel. JEE Vorlesung 10. Ralf Gitzel

Es sollte die MS-DOS Eingabeaufforderung starten. Geben Sie nun den Befehl javac ein.

Live Update (Auto Update)

Kurzeinführung Excel2App. Version 1.0.0

2 Die Terminaldienste Prüfungsanforderungen von Microsoft: Lernziele:

Musterlösung für Schulen in Baden-Württemberg. Windows Basiskurs Windows-Musterlösung. Version 3. Stand:

Java Kurs für Anfänger Einheit 4 Klassen und Objekte

Programmieren in Java

Software Engineering. Zur Architektur der Applikation Data Repository. Franz-Josef Elmer, Universität Basel, HS 2015

Motivation. Inhalt. URI-Schemata (1) URI-Schemata (2)

Registrierung am Elterninformationssysytem: ClaXss Infoline

Objektorientierte Programmierung. Kapitel 12: Interfaces

Unsere Webapplikation erweitern

4D Server v12 64-bit Version BETA VERSION

In 15 einfachen Schritten zum mobilen PC mit Paragon Drive Copy 10 und Microsoft Windows Virtual PC

Konfigurationslanleitung für J2EE und Eclipse im KBS-Pool

Bedienungsanleitung für den SecureCourier

COMPUTER MULTIMEDIA SERVICE

REST Grundlagen. Seminar Aktuelle Software-Engineering-Praktiken für das World Wide Web. Olga Liskin

Objektorientierte Programmierung

Seite 1 von 14. Cookie-Einstellungen verschiedener Browser

! " # $ " % & Nicki Wruck worldwidewruck

Informationen zur Verwendung von Visual Studio und cmake

News & RSS. Einleitung: Nachrichten er-(veröffentlichen) und bereitstellen Nachrichten erstellen und bereitstellen

Thema: Microsoft Project online Welche Version benötigen Sie?

Über die Internetseite Hier werden unter Download/aktuelle Versionen die verschiedenen Module als zip-dateien bereitgestellt.

Webservices. 1 Einführung 2 Verwendete Standards 3 Web Services mit Java 4 Zusammenfassung. Hauptseminar Internet Dienste

crm-now/ps Webforms Webdesigner Handbuch Erste Ausgabe

Elexis-BlueEvidence-Connector

etermin Einbindung in Outlook

Aus unserer Projekt- und Schulungserfahrung Oracle TechNet

Multimedia im Netz. Wintersemester 2011/12. Übung 10. Betreuer: Verantwortlicher Professor: Sebastian Löhmann. Prof. Dr.

Anleitung mtan (SMS-Authentisierung) mit SSLVPN.TG.CH

Dieses Tutorial gibt eine Übersicht der Form Klassen von Struts, welche Besonderheiten und Unterschiede diese aufweisen.

Klausurteilnehmer. Wichtige Hinweise. Note: Klausur Informatik Programmierung, Seite 1 von 8 HS OWL, FB 7, Malte Wattenberg.

How to install freesshd

Binäre Bäume. 1. Allgemeines. 2. Funktionsweise. 2.1 Eintragen

Web Services stellen eine Integrationsarchitektur dar, die die Kommunikation zwischen verschiedenen Anwendungen

Universal Dashboard auf ewon Alarmübersicht auf ewon eigener HTML Seite.

Java und XML 2. Java und XML

PHPNuke Quick & Dirty

CSS-Grundlagen. Etwas über Browser. Kapitel. Die Vorbereitung

Guide DynDNS und Portforwarding

Artikel Schnittstelle über CSV

Durch Standardisierung können Webservices von jedem Cluster verwendet werden, unabhängig von Betriebssystem und verwendeter Sprache.

Loggen Sie sich in Ihrem teamspace Team ein, wechseln Sie bitte zur Verwaltung und klicken Sie dort auf den Punkt Synchronisation.

Zustandsgebundene Webservices

Clientkonfiguration für Hosted Exchange 2010

Eigenen WSUS Server mit dem UNI WSUS Server Synchronisieren

Einführung in die objektorientierte Programmierung mit Java. Klausur am 19. Oktober 2005

Anleitung über den Umgang mit Schildern

FTP-Server einrichten mit automatischem Datenupload für

Installation und Inbetriebnahme von Microsoft Visual C Express

Übungen zu Softwaretechnik

Erstellung botoptimierter Partnerlinks

Installation des edu- sharing Plug- Ins für Moodle

Anleitung Captain Logfex 2013

BSV Software Support Mobile Portal (SMP) Stand

Leitfaden zur ersten Nutzung der R FOM Portable-Version für Windows (Version 1.0)

Internet Explorer Version 6

2. Einrichtung der ODBC-Schnittstelle aus orgamax (für 32-bit-Anwendungen)

.NET Code schützen. Projekt.NET. Version 1.0

Drucken von Webseiten Eine Anleitung, Version 1.0

Wie richten Sie Ihr Web Paket bei Netpage24 ein

Um DynDNS zu konfigurieren, muss ausschließlich folgendes Menü konfiguriert werden:

Um dies zu tun, öffnen Sie in den Systemeinstellungen das Kontrollfeld "Sharing". Auf dem Bildschirm sollte folgendes Fenster erscheinen:

TeamSpeak3 Einrichten

Anwendungshinweis Nr. 12. Wie konfiguriere ich redundante Serververbindungen

Urlaubsregel in David

Datei Erweiterungen Anzeigen!

Sie werden sehen, dass Sie für uns nur noch den direkten PDF-Export benötigen. Warum?

KURZANLEITUNG CLOUD OBJECT STORAGE

Installations Guide für YAJSW und DTLDAP

Nicht kopieren. Der neue Report von: Stefan Ploberger. 1. Ausgabe 2003

Übungen zur Softwaretechnik

Java: Vererbung. Teil 3: super()

Transkript:

2011 Felix Barnsteiner Aktuelle Technologien zur Entwicklung verteilter Java Anwendungen Betreut von Michael Theis Bearbeitet von [RESTful Webservices mit JAX-RS]

Inhaltsverzeichnis 1. Einleitung... 1 2. Was ist REST?... 2 3. HTTP... 4 3.1. HTTP Methoden... 6 3.2. HTTP Statuscodes... 7 4. Was ist JAX-RS?... 8 5. Erstellen eines RESTful Webservices... 8 5.1. Vorbereitung... 8 5.2. Erstellen einer Hello World Anwendung...10 5.2.1. Server...10 5.2.2. Client...12 6. JAX-RS im Detail...13 6.1. Binden von URIs an Java Klassen und Methoden...13 6.2. Binden von HTTP Operationen an Java Methoden...14 6.3. CRUD - HTTP Method Mapping...15 6.4. Auslesen von Request Parametern...16 6.5. Content Negotiation...18 6.6. Rückgabewerte...19 6.7. Entity Provider...20 6.7.1. XML...21 6.7.2. JSON...23 6.8. Exceptions...23 7. Welche Implementierungen von JAX-RS gibt es?...25 7.1. Jersey...25 7.2. JBoss RESTEasy...25 7.3. Apache CXF...25 8. REST gegen Schwergewichtige Webservices...26 9. Fazit...26 10. Abbildungsverzeichnis...30 11. Literaturverzeichnis...30 12. Erklärung...31

1. Einleitung In dieser Studienarbeit werde ich die theoretischen Hintergründe von REST, sowie JAX-RS, den Java Standard zur Erstellung von RESTful Webservices (auch REST APIs genannt), beschreiben. Des Weiteren soll der Leser durch Praxisbeispiele dazu befähigt werden eigene Webservices zu implementieren. Zunächst möchte ich erklären was Webservices sind und was die Motivation dieser ist. Webservices ermöglichen es Programmen, die auf verschiedenen Plattformen laufen und in unterschiedlichen Programmiersprachen geschrieben wurden, miteinander zu kommunizieren. Hierbei gibt es zwei Hauptaufgabengebiete. Kommunikation mit internen Systemen Webservices können dabei helfen unabhängige interne Systeme wie z.b. Legacysysteme zu integrieren und beispielsweise eine Schnittstelle zwischen alten Abrechnungsprozeduren, welche in COBOL geschrieben wurden und modernen JavaEE Applikationen darstellen. Kommunikation mit externen Systemen Partner oder Kunden können durch Webservices dazu befähigt werden, automatisiert mit internen Systemen zu kommunizieren. Beispielsweise bietet amiando.com (ein Onlinetool für Eventmanagement- und Registrierung) eine REST API an, mit der die Services von amiando von externen Partnern in Anspruch genommen werden können. Xing.com, deren Plattform in einer anderen Programmiersprache implementiert ist, nutzt diese API unter anderem, um integriert in ihrer Webseite die Möglichkeit anzubieten, ein amiando Event mit Ticketvorverkauf einzurichten. RESTful Webservices sind jene Webservices, welche konform zu den Architekturprinzipien von REST sind. Die Eigenschaften von RESTful Webservices sind, dass eine möglichst große Anzahl von Clients, egal in welcher Sprache sie programmiert wurden, dazu zu befähigt werden, den Service effizient zu konsumieren, sowie eine maximale Skalierbarkeit zu gewährleisten. Leichtgewichtige Webservices mit REST Seite 1

2. Was ist REST? REST (Representational State Transfer) beschreibt einen Architekturstil für verteilte Hypermedia-Systeme, welcher Prinzipien definiert, die bei Anwendung auf einen Webservice unter anderem zu Skalierbarkeit, Performance, Vereinheitlichung von Schnittstellen und Entkopplung von Komponenten führt. (Fielding, 2000) Die Prinzipien von REST sind: Identifizierung von Ressourcen Ressourcen sind vergleichbar mit Objekten, wie man sie aus JAVA kennt. Jede Ressource muss durch einen URI (Uniform Ressource Identifier) gekennzeichnet sein. (Oracle) Beispielsweise adressiert. http://www.university.edu/student/01234567 eine Studenten Ressource mit der Matrikelnummer 01234567. Ressourcen sind entkoppelt von deren Repräsentation und können unterschiedliche Formate haben, da verschiedene Plattformen andere Repräsentationen benötigen. Zum Beispiel benötigen Browser HTML und Java benötigt XML oder JSON. (Burke, 2010) Manipulation der Ressourcen durch deren Repräsentationen Wenn ein Client eine Repräsentation einer Ressource besitzt, hat dieser genügend Informationen darüber, um eine Ressource auf dem Server zu ändern oder zu löschen, falls diese die Berechtigung dazu hat. Selbsterklärende Nachrichten Es stehen Metadaten über die Ressource zur Verfügung, welche zum Beispiel dazu genutzt werden um Übertragungsfehler zu ermitteln, das Repräsentationsformat auszuhandeln und um Authentifizierung durchzurühren. (Oracle) Einheitliche Schnittstelle Eine überschaubare Menge an wohldefinierten Methoden um die Ressourcen zu manipulieren. (Burke, 2010) HTTP bietet dazu unter anderem die Methoden GET, PUT und DELETE an. GET liefert, ähnlich wie ein Getter in JAVA, den aktuellen Zustand einer Ressource zurück. Ein Aufruf der GET Methode der Studentenressource könne z.b. den Namen und das aktuelle Semester des Studenten zurückliefern. Leichtgewichtige Webservices mit REST Seite 2

Zustandslose Kommunitation Zustandslose Applikationen sind einfacher zu skalieren. (Burke, 2010) Hypermedia As The Engine Of Application State (HATEOAS) Hypermedia sind Dokumente, welche Verlinkungen zu anderen Dokumenten enthalten, wie z.b. HTML oder ein XML Dokument, welches Links enthält. Die Grundidee hinter HATEOAS ist, dass sich der Client nur eine fixe Adresse des Webservices merken muss. Alle gültigen Folgeseiten werden in dem vom Server zurückgelieferten Dokumenten verlinkt. Der Applikationsstatus wird damit durch das Auswählen eines Links angetrieben. Wenn wir beispielsweise eine Liste aller Studenten einer Hochschule einsehen wollen, könnten wir ein HTTP GET auf http://university.edu/students absenden. Da die Liste wahrscheinlich sehr lang wird, könnten wir eine Pagingfunktion einbauen, damit standardmäßig nur 20 Studenten gleichzeitig zurückgegeben werden. <students> <link rel="next" href="http:// hochschule.edu/students?startindex=20"/> <student id="123"> <name>felix</name> <term>ibb6a</term> </student>... </students> Hierdurch muss der Client nicht den URI der Ressource kennen, welche die Liste fortsetzt, sondern muss sich nur die Relation (in diesem Fall next ) merken. Dies führt zu einer Entkopplung von Client und Server, da der Server nun die URIs nach Belieben ändern kann. (Burke, 2010) Ein Beispiel für ein System, welches diesen Prinzipien unterliegt ist das World Wide Web. Bei RESTful Webservices geht es allerdings darum, maschinenlesbare Formen von Webseiten anzubieten, welche Daten oder Funktionen enthalten können. REST ist also kein eigenständiges Protokoll. Dennoch wird mit REST meist eine Kommunikation über HTTP assoziiert, da sich die Architekturprinzipien von REST damit gut umsetzen lassen. Aus diesem Grund ist es wichtig ein gutes Verständnis von HTTP zu haben um RESTful Webservices zu entwickeln. (Burke, 2010) Leichtgewichtige Webservices mit REST Seite 3

3. HTTP Um die Funktionsweise von RESTful Webservices besser verstehen zu können, werde ich im Folgenden zunächst auf das HTTP Protokoll eingehen. HTTP ist ein zustandsloses synchrones Request/Response basiertes Netzwerkprotokoll, welches für dokumentenbasierte verteilte Systeme genutzt wird. Es ist das Protokoll, welches hauptsächlich im WWW, z.b. von Browsern wie Mozilla Firefox oder Microsoft Internet Explorer, benutzt wird. (Burke, 2010) Jede HTTP Nachricht ist entweder ein Request oder eine Response. Requests stellen Anfragen an einen Server dar und Responses geben die Antwort des Servers an den Client zurück. Abbildung 1: Request und Response (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Eine HTTP Nachricht besteht aus drei Teilen: Start Line Gibt bei einem Request an, was zu tun (welche HTTP Methode, welcher URI, welche Protokollversion) ist und bei einer Response was passiert ist (welche Protokollversion, welcher Statuscode). (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Header Felder Keiner oder mehrere Header Felder kommen nach der Start Line. Jedes Feld besteht aus einem Schlüssel und einem Wert, welche durch ein Doppelpunkt getrennt sind (:). Die Header enden mit einer Leerzeile. (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Leichtgewichtige Webservices mit REST Seite 4

Ein wichtiger Request Header für RESTful Webeservices ist der Accept Header. Dieser Teilt dem Server mit, welches Datenformat (welchen MIME Mediatyp) der Client bevorzugt. (Ruby, 2007) Eine Liste aller Medientypen ist hier zu finden: http://www.iana.org/assignments/media-types/index.html. Browser präferieren beispielsweise den Medientyp text/html. Body Nach der Leerzeile kommt ein optionaler Message Body, welcher jede Art von Daten enthalten kann. Beispielsweise HTML, Plaintext, JSON, XML oder Binärdaten. Request Bodys überbringen Daten zum Server (z.b. Daten, die der Client in einem Formular eingegeben hat), Response Bodys übertragen Daten zurück zum Client (z.b. ein HTML-File). (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Mit dem Plugin HttpFox für den Browser Firefox lassen sich die HTTP Nachrichten, die der Browser sendet und empfängt, mitschneiden. Hier ist ein Beispiel für ein Request (Aufruf von http://hm.edu/studierende/index.de.html mit Firefox): Start Line GET /studierende/index.de.html HTTP/1.1 Header Host: hm.edu User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; de; rv:1.9.2.12)... Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q =0.8 Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Body {leer Hier die zugehörige Response: Start Line HTTP/1.1 200 OK Header Date: Wed, 20 Apr 2011 10:37:44 GMT Server: Apache Last-Modified: Wed, 20 Apr 2011 09:38:09 GMT Content-Length: 19790 Content-Type: text/html Body <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" Leichtgewichtige Webservices mit REST Seite 5

"http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> </html> 3.1. HTTP Methoden (auch Verb genannt) In dem Beispiel HTTP- Request haben wir bereits die GET Methode kennen gelernt, doch was sind HTTP Methoden eigentlich und welche sind für RESTful Webservices relevant? HTTP Methoden sind mit Methoden von Programmiersprachen vergleichbar. Sie beschreiben die Erwartung des Clients wie der Server die Anfrage zu verarbeiten hat. (Ruby, 2007) Um konform mit der HTTP Version 1.1 zu sein, müssen nur die Methoden GET und HEAD implementiert werden. (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Ich werde nun die für RESTful Webservices relevanten HTTP Verben vorstellen: GET ist das wohl am weitesten verbreitete HTTP Verb. Ähnlich wie bei einem Getter bei Java lässt sich mit dieser Methode der aktuelle Zustand einer Ressource auslesen. POST sendet Daten an den Server. Diese Methode wird oft dazu genutzt, die Daten, die in einem HTML-Formular (<form>...</form>) eingegeben wurden, an den Server zu übermitteln. PUT lädt eine Ressource unter Angabe des Ziel-URIs auf den Server oder zu tauscht diese aus, falls der URI bereits existiert. DELETE löscht eine Ressource. HEAD verhält sich genauso wie GET, mit dem Unterschied, dass bei der Antwort kein Message-Body, sondern nur die Header zurückgegeben werden um beispielsweise herauszufinden, ob eine Ressource existiert. Die Server Entwickler müssen sicherstellen, dass bei einem Aufruf von HEAD die gleichen Header wie bei GET zurückgegeben werden. (Gourley, Totty, Sayer, Reddy, & Aggarwal, 2002) Leichtgewichtige Webservices mit REST Seite 6

3.2. HTTP Statuscodes Statuscodes stehen in der Start Line des Headers und teilen dem Client mit, ob der Sever die Anfrage richtig verarbeiten konnte. Ein Statuscode ist unterteilt in eine von Maschinen auswertbare dreistellige Zahl und ein einer Beschreibung des Status. Es gibt eine Fülle an Statuscodes, doch an dieser Stelle werde ich nur die erläutern, die insbesondere im Bezug zu RESTful Webservices von Relevanz sind. 2xx Ein Statuscode, der mit einer 2 beginnt, bedeutet, dass die Anfrage erfolgreich ausgeführt wurde 200 OK Die Anfrage konnte erfolgreich ausgeführt werden; der Response Body ist nicht leer. Z.B. bei einem erfolgreichem GET, oder POST. 201 Created Eine neue Ressource wurde angelegt. Z.B. wenn per PUT oder POST eine neue Ressource angelegt wurde. 204 No Content Die Anfrage konnte erfolgreich ausgeführt werden; der Response Body ist leer. Z.B. bei einem erfolgreichem ändern einer Ressource durch PUT. 4xx Client Error Ein Statuscode, der mit einer 4 beginnt, bedeutet, dass ein Fehler aufgetreten ist, welcher eher im Verantwortungsbereich des Clients liegt. 400 Bad Request Der Server konnte die Anfrage wegen eines Syntaxfehlers nicht verstehen. 401 Unauthorized Der Client muss sich druch ein WWW-Authenticate Header authentifizieren. 404 Not Found Die angeforderte Ressource konnte nicht gefunden werden. 405 Method Not Allowed Die HTTP Methode, mit der die Ressource angesprochen wurde, ist für diese nicht erlaubt. Im Allow-Header werden die gültigen Methoden aufgelistet. 406 Not Acceptable Der Server kann keines der im Accept Header des Request spezifizierten Repräsentationsformate erzeugen. Im Body kann eine Liste von unterstützten Repräsentationsformaten stehen. 5xx Ein Statuscode, der mit einer 5 beginnt, gibt an, dass ein Serverseitiger Fehler aufgetreten ist. 500 Internal Server Error Durch einen unerwarteten Fehler konnte die Anfrage nicht ausgeführt werden. (Group, 1999) Leichtgewichtige Webservices mit REST Seite 7

4. Was ist JAX-RS? JAX-RS (Java API for RESTful Web Services) ist ein Framework, welches darauf abzielt einfache Java Objekte durch Annotationen als Webservice zu deklarieren. Die Spezifikation setzt HTTP als Übertragungsprotokoll voraus und bindet URIs und HTTP Methoden durch weitere Annotationen an die jeweiligen Java Klassen und -Methoden. (Hadley & Sandoz, 2009) JAX-RS bietet die Möglichkeit sehr einfach Informationen aus dem HTTP Request auszulesen. Es vereinfacht die Entkopplung der Java Datenobjekte und deren Repräsentation, welche an den Client geschickt wird (z.b. XML oder JSON), bietet Exception-Mapper an, welche anwendungsspezifische Exceptions in HTTP Statuscodes und Nachrichten umwandeln und bietet Unterstützung das Repräsentationsformat mit dem Client auszuhandeln (Content Negotiation). (Burke, 2010) Man sollte sich jedoch nicht der falschen Annahmen hingeben, dass alles eine REST API ist, was mit JAX-RS entwickelt wurde. Denn wie bereits erwähnt wurde, ist REST kein Protokoll, sondern ein Architekturstil. Dieser wird durch JAX-RS vereinfacht, jedoch ähneln mache Webservices, die sich eine REST-API nennen eher dem RPC (Remote Procedure Call) Stil, da oftmals die Kopplung von Client zu Server, durch Vernachlässigung des HATEOAS Grundsatzes zu stark ist. (Fielding, Rest APIs must be hypertext-driven, 2008) 5. Erstellen eines RESTful Webservices In diesem Kapitel werde ich Schritt für Schritt erklären wie man mit Jersey, Eclipse EE und Apache Tomcat einen RESTful Webservice von Grund auf implementiert. 5.1. Vorbereitung Herunterladen der Bibliotheken Zunächst müssen die Bibliotheken jersey-budle.jar und asm.jar von der Jersey Homepage (http://jersey.java.net/) sowie die jsr311-api.jar von der JSR 311 Homepage (http://jsr311.java.net/) heruntergeladen werden. Installation von Tomcat Um das Projekt starten zu können müssen wir als nächstes einen Servlet Container wie z.b. Apache Tomcat Installieren und in Eclipse integrieren. Auf http://tomcat.apache.org/ kann der Servlet Container heruntergeladen werden. Ferner ist dort beschrieben, wie dieser installiert werden kann. Leichtgewichtige Webservices mit REST Seite 8

Um Tomcat in Eclipse zu integrieren wechseln wir zunächst in die Java EE Perspektive und Navigieren zu dem Reiter Server. Falls dieser nicht zu sehen ist, kann er unter Window>Show View>Servers eingeblendet werden. Danach fügen wir mit Rechtsklick>Server>New Tomcat hinzu. Erstellen des Projekts rest-server Danach erstellen wir zwei Projekte in Eclipse - eines für den Server, welcher den Webservice bereitstellt und eines für den Client, welcher den Service konsumiert. Fangen wir zunächst mit dem Server an. Dazu erstellen wir in Eclipse ein Dynamic Web Project mit dem Namen rest-server, fügen im Erstellungsdialog das Projekt zu unserem gerade erstellten Server hinzu, kopieren die drei Bibliotheken (s.o.) in das /WEB-INF/lib Verzeichnis und fügen diese dem Klassenpfad hinzu. Für die Konfiguration des Webprojekts und die Registrierung von Jersey wird ein sog. Deployment Desktiptor benötigt, welcher sich in dem Verzeichnis WebContent/WEB- INF/web.xml befindet. Deployment Desktiptor - web.xml <?xml version="1.0" encoding="utf-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemalocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="webapp_id" version="3.0"> <servlet> <servlet-name>rest-servlet</servlet-name> <servlet-class> com.sun.jersey.spi.container.servlet.servletcontainer </servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>rest-servlet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app> Leichtgewichtige Webservices mit REST Seite 9

Wichtig ist hierbei das Registrieren des REST-Servlets - in unserem Fall das von Jersey - durch das <servlet> Tag sowie das Umleiten aller Anfragen auf den Server, welche mit /rest/ beginnen auf dieses Servlet durch das <servlet-mapping> Tag. Anfragen, die mit http://localhost:8080/rest-server/rest/ beginnen werden auf das Jersey REST-Servlet umgeleitet, wenn der Pfad des Servers /rest-server ist (Standardeinstellung von Tomcat). rest-client Nun erstellen wir ein Client Projekt um den die vom Server bereitgestellten Services konsumieren und testen zu können. Hierzu erstellen wir ein neues Java Projekt mit dem Namen rest-client, und fügen die Bibliotheken jersey-bundle.jar und jsr311-api.jar dem Klassenpfad hinzu. Damit sind die Vorbereitungen abgeschlossen und wir können damit beginnen unsere Anwendung zu implementieren. 5.2. Erstellen einer Hello World Anwendung 5.2.1. Server Eine Hello World Anwendung mit JAX-RS zu schreiben ist sehr einfach. Zunächst erstellen wir eine Ressource in Form einer einfachen Java Klasse - nennen wir sie HelloResource. In dieser Klasse benötigen wir noch eine Methode sayhello(), welche den String Hello World! zurückgibt. Doch wie funktioniert die Zuordnung von URIs zu den Ressourcen (Java-Klassen) und deren Methoden? Sehen wir uns zunächst den Quellcode an: HelloResource.java package edu.hm.restserver.resources; import javax.ws.rs.get; import javax.ws.rs.path; import javax.ws.rs.produces; import javax.ws.rs.core.mediatype; @Path("hello") public class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN) public String sayhello() { return "Hello World!"; Leichtgewichtige Webservices mit REST Seite 10

Die Zuordnung von URIs zu den Ressourcen erfolgt über Annotationen, welche unter anderem über Klassen geschrieben werden können (mehr dazu im Kapitel 6.4 Auslesen von Request Parametern). Der Parameter, welcher der Annotation übergeben wird (in diesem Fall hello ) beschreibt den relativen Pfad unseres Services. Wenn der Absolute Pfad unserer Applikation http://localhost:8080/rest-server/ ist und in die web.xml so konfiguriert ist, dass alle Anfragen, welche mit /rest beginnen zum Jersey Servlet weitergeleitet werden, dann ist diese Ressource unter http://localhost:8080/restserver/rest/hello verfügbar. (Burke, 2010) Die Entscheidung, welche Methode einer angefragten Ressource Aufgerufen wird hängt vom HTTP Verb des Requests ab. Für jede HTTP Methode gibt es eine dazu gehörige Annotation (z.b. @GET für die HTTP GET Methode). Wenn man nun eine Methode mit @GET Kennzeichnet, wird diese Aufgerufen, wenn die HTTP Methode des Requests GET ist. Durch die Annotation @Produces kann der MIME Medientyp der Daten im Body der HTTP- Response spezifiziert werden. HTTP Request GET rest/hello Server rest Jersey Servlet hello GET @Path("hello") HelloResource @GET sayhello() Abbildung 2: HTTP Methoden und URI Matching Um zu testen, ob alles funktioniert, können wir nun den Server starten und mit dem Browser http://localhost:8080/rest-server/rest/hello aufrufen. Dadurch sendet der Browser ein HTTP GET Request an unseren Server, welcher die Anfrage an das Jersey- Servlet umleitet (da der Request mit /rest/ beginnt - siehe web.xml), welches Aufgrund Leichtgewichtige Webservices mit REST Seite 11

des Pfades (/hello) die mit @Path("hello") annotierte Ressource bereitstellt und die mit @GET annotierte Methode ausführt. Als Ergebnis sollte nun Hello World! Im Browserfenster zu sehen sein. 5.2.2. Client Das Schöne an RESTful Webservices ist, dass man mit jeder Programmiersprache, die eine HTTP Unterstützung anbietet, einen RESTful Client schreiben kann. JAX-RS ist nur ein Server-seitiges Framework, das Unterstützung bei der Implementierung von RESTful Services anbietet. Es umfasst derzeit leider noch keine Client-API, was sich jedoch mit der Version 2.0 von JAX-RS ändern soll. (Burke, 2010) Jersey bietet allerdings eine sehr gute API zur Erstellung von Clients. Hier ein Codebeispiel, welches unser gerade erstellten Hello World- Webservice unter http://localhost:8080/rest-server/rest/hello aufruft: MyRestClient.java package hm.edu.restclient.client; import ; public class MyRestClient { final WebResource resource; public MyRestClient() { resource = Client.create(). resource("http://localhost:8080/rest-server/rest"); public void callget(string path, String mediatype) { ClientResponse response = null; response = resource.path(path). accept(mediatype).get(clientresponse.class); System.out.println("HTTP Statuscode: " + response.getstatus()); if (response.hasentity()) System.out.println(response.getEntity(String.class)); public static void main(string[] args) { new MyRestClient().callGet("hello", MediaType.TEXT_PLAIN); Nach dem Ausführen des Programms sollte nun Hello World! auf der Konsole erscheinen. Auf diesen Client-Code werde ich nicht weiter eingehen, da sich diese Arbeit auf das Schreiben von Serverseitigem Code und die JAX-RS API konzentriert. Interessierten Lesern sei jedoch der User Guide von Jersey empfohlen: http://jersey.java.net/nonav/documentation/latest/user-guide.html#client-api Leichtgewichtige Webservices mit REST Seite 12

6. JAX-RS im Detail 6.1. Binden von URIs an Java Klassen und Methoden Die @Path Annotation definiert, auf welchen URI Pfad bzw. auf welche URI Pfadvorlage eine Ressource reagieren soll. URI Pfadvorlagen sind URIs, welche eine Variable in der URI Syntax enthalten. Variablen werden mit geschweiften Klammern deklariert ( { und ). Ein Beispiel für eine @Path Annotation mit Variable: @Path("user/{username") @Path kann sowohl über einer Klasse, als auch über einer Methode stehen. Durch die Annotation @PathParam lassen sich diese Variablen auslesen und in einen Methoden Parameter injizieren: @Path("user") public class UserResource { @GET @Path("{username") public String getuser(@pathparam("username") String username) { return username; (Oracle) Die Methode getuser(...) wäre damit z.b. über ein HTTP GET Request auf http://localhost:8080/rest-server/rest/user/felix zu erreichen und würde Felix als Antwort zurückgeben. Es können in einem Pfad mehrere Variablen, sowie dieselbe Variable mehrmals auftreten. Des Weiteren sind auch Reguläre Ausdrücke erlaubt. Diese werden nach dem Variablennamen definiert und mit einem Doppelpunkt getrennt. Beispielsweise definiert {id : \\d+, dass die Variable id aus einer oder mehreren Ziffern bestehen muss). (Burke, 2010) Es ist es nicht von Belang, ob ein führender oder abschließender Slash ( / ) angefügt wird. Es folgen einige Beispiele Leichtgewichtige Webservices mit REST Seite 13

Wert der @Path Annotation Beispiel URI /{firstname/{lastname/ http://example.com/john/doe {question/{question/{question/ http://example.com/why/why/why/ maps/{location http://example.com/maps/main%20street /{name3/home http://example.com//home customer/{id : \\d+ http://example.com/customer/123 (Oracle) 6.2. Binden von HTTP Operationen an Java Methoden In dem Hello World Beispiel haben wir bereits gesehen, wie man mit der @GET Annotation Java Methoden an HTTP Verben bindet. JAX-RS definiert weitere Annotationen, welche die Gängisten HTTP Verben abdecken: @javax.ws.rs.get @javax.ws.rs.put @javax.ws.rs.post @javax.ws.rs.delete @javax.ws.rs.head Falls man seine Java Methoden an weitere HTTP Operationen binden will, hat man die Möglichkeit seine eigenen Annotationen zu definieren. (Burke, 2010) Wie das geht werde ich in dieser Arbeit nicht weiter ausführen. In den meisten Fällen sollten die JAX-RS Annotationen genügen. Die JAX-RS Runtime unterstützt die Methoden HEAD und OPTIONS automatisch, falls diese nicht explizit implementiert wurden. Für einen HEAD Request führt die JAX-RS Runtime automatisch die mit @GET annotierte Methode aus und verwirft den Rückgabewert. Bei einem OPTIONS Request werden im Allow Header der HTTP Response die unterstützten Methoden der Ressource aufgeführt. Zusätzlich wird ein WADL (Web Application Description Language) Dokument zurückgegeben, welches alle Methoden, inklusive ihrer Java Methodennamen und den MIME Mediatypen der Rückgabewerte, enthält. (Oracle) WADL des Hello World Beispiels: <?xml version="1.0" encoding="utf-8" standalone="yes"?> <application xmlns="http://research.sun.com/wadl/2006/10"> <doc xmlns:jersey="http://jersey.dev.java.net/" jersey:generatedby="jersey: 1.3 06/17/2010 05:04 PM"/> <resources base="http://localhost:8080/rest-server/rest/"> Leichtgewichtige Webservices mit REST Seite 14

<resource path="hello"> <method name="get" id="sayhello"> <response> <representation mediatype="text/plain"/> </response> </method> </resource> </resources> </application> 6.3. CRUD - HTTP Method Mapping Die Frage, welche hinter CRUD-HTTP Method Mapping steht ist, wie man die CRUD (Create, Retrieve, Update und Delete) Operationen den HTTP Methoden GET, PUT, POST und DELETE zuordnet. (Calcote, 2008) Die Zuordnung von Create-GET und Delete-DELETE ist noch trivial, jedoch kann sowohl PUT als auch POST dazu verwendet werden eine Ressource neu anzulegen oder zu verändern. PUT hat im Gegensatz zu POST eine wohldefinierte Semantik. Wenn man PUT dazu nutzt, eine neue Ressource anzulegen oder zu verändern, muss im Request der Pfad der neuen Ressource angegeben werden. Falls bereits eine Ressource unter diesem Pfad existiert, wird diese ausgetauscht. Falls nicht, wird sie neu angelegt. Dies ist dann sinnvoll, wenn der Aufrufer bereits einen eindeutigen Schlüssel der hinzuzufügenden Ressource kennt. Bei einer Studentenressource könnte dies z.b. die Matrikelnummer oder die Personalausweisnummer sein. POST sollte in den Fällen für das Anlegen von neuen Ressourcen verwendet werden, wenn der Aufrufer den eindeutigen Schlüssel der zu erzeugenden Ressource nicht kennt - z.b. beim Anlegen einer neuen Bestellung. Falls POST für das Verändern einer Ressource zuständig ist, kann auch ein Teil der Ressource, z.b. nur der Nachname eines Studenten, geändert werden. CRUD Operation Create Retrieve Update Delete HTTP Verb PUT, POST GET PUT, POST DELETE (Oracle) Leichtgewichtige Webservices mit REST Seite 15

6.4. Auslesen von Request Parametern In dem Hello World Beispiel haben wir bereits gesehen, wie man per @PathParam einen Parameter aus dem URI Pfad auslesen kann. JAX-RS definiert noch weitere Annotationen, welche dazu dienen Parameter, welche vom Client an den Server geschickt werden, in Java Methodenparameter zu injizieren (In allen Beispielen ist davon auszugehen, dass sich die Methode in einer Java Klasse befindet, welche mit @Path( user ) annotiert ist): @PathParam Mithilfe dieser Annotation kann man Werte aus URI Variablen auslesen. Beispiel: @POST @Path( {id ) public void post(@pathparam( id ) int id) { System.out.println(id); Aufruf: http://example.com/user/1 Output: 1 @MatrixParam Mithilfe dieser Annotation kann man Werte aus den Matrix Parametern eines URIs auslesen. Matrix Parameter werden durch Semikolon separiert. Beispiel: http://example.com/user;name=felix. Sie kommen allerdings eher selten vor, weshalb ich darauf nicht näher eingehe. @QueryParam Mithilfe dieser Annotation kann man Werte aus den Query Parametern eines URIs auslesen. Query Parameter können an jede URI angehängt werden und werden durch ein Fragezeichen (? ) eingeleitet. Sie haben das Format key=value. Mehrere Queryparameter können durch ein ( & ) voneinander getrennt werden: http://example.com/user?name=felix&matrikelnumber=123 Beispiel: @POST public void post(@queryparam( id ) int id) { System.out.println(id); Aufruf: http://example.com/user?id=1 Output: 1 @FormParam Mithilfe dieser Annotation kann man Werte aus HTML Formen auslesen. Leichtgewichtige Webservices mit REST Seite 16

Beispiel: @POST @Path( {id ) public void post(@formparam( id ) int id) { System.out.println(id); Aufruf: Client schickt eine HTTP Form mit einem Feld id an: http://example.com/user Output: 1 @HeaderParam Mithilfe dieser Annotation kann man Werte aus den HTTP Request Headern auslesen. Beispiel: @POST @Path( {id ) public void post(@headerparam( id ) int id) { System.out.println(id); Aufruf: Client schickt ein HTTP Request mit einem Header id: 1 an: http://example.com/user Output: 1 @CookieParam Mithilfe dieser Annotation kann man Werte aus HTTP Cookies auslesen. Vorsicht: Laut der Definition von Roy Fielding ist ein Webservice, welcher Gebrauch von Cookies macht, kein RESTful Webservice (nachzulesen in Kapitel 6.3.4.2). Deshalb werde ich auf die Benutzung dieser Annotation nicht weiter eingehen. @Context Mithilfe dieser Annotation können mehrere Hilfsobjekte, wie z.b. das HttpHeaders Objekt, welche von JAX-RS zur Verfügung gestellt wird, in einen Methodenparameter injiziert werden. Ich werde an dieser Stelle nicht auf alle Hilfsobjekte eingehen. Bei weiterem Interesse sei das Kapitel 5 und 6 der JAX-RS Spezifikation empfohlen. Beispiel: @POST public void post(@context UriInfo ui) { MultivaluedMap<String, String> queryparams = ui.getqueryparameters(); MultivaluedMap<String, String> pathparams = ui.getpathparameters(); Leichtgewichtige Webservices mit REST Seite 17

(Burke, 2010) Automatische Konvertierung zu Java Typen Wie wir bereits an den Beispielen gesehen haben, ist JAX-RS in der Lage, die eigentlich als Zeichenkette vorliegenden Parameter automatisch in Java Objekte bzw. primitive Typen umzuwandeln. Dies Funktioniert mit jedem Java Typ, der einer dieser Kriterien entspricht: 1. Es ist ein primitiver Datentyp 2. Es ist eine Javaklasse, die einen Konstruktor mit einem einzigen String Parameter hat 3. Es ist eine Javaklasse, die eine statische Methode valueof(string s) besitzt, welche eine Instanz der Klasse zurückgibt. 4. Es ist eine java.util.list<t>, java.util.set<t>, oder java.util.sortedset<t>, bei dem T ein Typ ist, welcher das Kriterium 2 oder 3 erfüllt, oder ein String ist. Beispiele sind List<Double>, Set<String>, or SortedSet<Integer>. (Hadley & Sandoz, 2009) 6.5. Content Negotiation Webservices müssen teilweise sehr flexibel und von vielen Clients und Plattformen aus erreichbar sein. RESTful Webservices haben den Vorteil, dass die meisten Programmiersprachen eine Anbindung zu HTTP haben. Dies ist jedoch noch nicht genug. Verschiedene Clients benötigen ein spezifisches Repräsentationsformat, mit dem sie effizient arbeiten können. Java Clients kommen meist mit XML am besten zurecht, Ajax Clients arbeiten effizienter mit JSON und Ruby Clients bevorzugen YAML. Auch die Internationalisierung von Inhalten kann von Relevanz sein. HTTP bietet auch hier Unterstützung durch Accept-Header, mit denen sich das MIME Format, die Encodierung und die Sprache aushandeln lassen. Dieses Protokoll nennt sich Content Negotiation. Wie wir bereits an dem Beispiel HTTP-Request in Kapitel 3 sehen konnten, es dem Client möglich, mehrere Formate, Encodierungen und Sprachen anzugeben und diese zu gewichten. Zum Beispiel: GET http://example.com/stuff Accept: application/xml, application/json Mit diesem Aufruf weist der Client den Server an, eine entweder in XML oder JSON formatierte Antwort zu erhalten. Falls der Server dieses Format nicht liefern kann, sendet er eine Antwort mit dem Statuscode 406 Not Acceptable an den Client zurück. Leichtgewichtige Webservices mit REST Seite 18

Mit JAX-RS hat man die Möglichkeit, unterschiedliche Java Methoden, basierend auf dem Inhalt des Accept-Headers für die Selbe HTTP Operation zu verwenden. Hier ein Beispiel: @Path("/students") public class StudentResource { @GET @Path("{id") @Produces("application/xml") public Customer getstudentxml(@pathparam("id") int id) { @GET @Path("{id") @Produces("text/plain") public String getstudenttext(@pathparam("id") int id) { @GET @Path("{id") @Produces("application/json") public Customer getstudentjson(@pathparam("id") int id) { Leider gibt es bis dato noch keine @ProducesLanguages oder @ProducesEncoding Annotationen. (Burke, 2010) 6.6. Rückgabewerte Methoden, welche mit einer Annotation, die eine HTTP Operation an eine Java Methode bindet (z.b. @GET), können die Rückgabewerte void, Response oder einen anderen Java Typ (mehr dazu im Kapitel 6.7 Entity Provider)haben. Das Response Objekt ist dann hilfreich, wenn man die HTTP Response, welche an den Client geschickt wird, noch genauer kontrollieren will. Z.B. durch angepasste HTTP Statuscodes, Cookies oder Header. Ausschnitt aus javax.ws.rs.core.response: public abstract class Response { public abstract Object getentity(); public abstract int getstatus(); public abstract MultivaluedMap<String, Object> getmetadata(); Response ist eine Abstrakte Klasse, welche drei Abstrakte Methoden beinhaltet. getentity() enthält das Java Objekt, das in den Body der HTTP Response geschrieben werden soll. getstatus() liefert den HTTP Satuscode zurück. getmetadata() gibt eine Liste mit Schlüssel- Werte Paaren zurück, welche die HTTP Response Header repräsentieren. Die Response Objekte können nicht von Hand angelegt werden. Stattdessen werden sie von Instanzen der Factoryklasse javax.ws.rs.core.response.responsebuilder erzeugt, welche Leichtgewichtige Webservices mit REST Seite 19

wiederum durch die Benutzung einer der statischen Hilfsmethoden von Response (z.b. public static ResponseBuilder ok()), zurückgegeben werden. Durch diese Hilfsmethoden werden die ResponseBuilder Objekte vorinitialisiert. Beispielsweise ist der HTTP Statuscode des zurückgegebenen ResponseBuilder Objekts bei Benutzung der Methode public static ResponseBuilder ok() 200 OK. Es können nun Attribute wie Header, Cookies, Sprache oder Inhalt des Message Bodys gesetzt werden. Wenn man mit dem Konfigurieren des ResponseBuilders fertig ist, kann die build() Methode aufgerufen werden, welche ein Response Objekt zurückgibt. Beispiel: @Path("hello") public class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN) public Response sayhello() { String hello = "Hello World!"; ResponseBuilder builder = Response.ok(hello); builder.language("en").header("some-header", "some value"); return builder.build(); (Burke, 2010) 6.7. Entity Provider Im Kapitel 6.4 Auslesen von Request Parametern habe ich gezeigt, wie man aus dem Header bzw. der URI eines HTTP Requests Daten auslesen kann. In diesem Kapitel geht es darum, welche Möglichkeiten JAX-RS bietet, den Body eines Requests auszulesen bzw. in den Body einer Response zu schreiben. JAX-RS bietet durch sogenannte MessageBodyReader und MessageBodyWriter die Möglichkeit, bestimmte Java Datentypen automatisch aus dem Body auslesen bzw. hineinschreiben. (Burke, 2010) Folgende Tabelle listet alle von JAX-RS bereitgestellten MessageBodyReader und MessageBodyWriter auf. Java Typ Unterstützter MIME Media Typ byte[] Alle Medientypen (*/*) java.lang.string Alle Text Medientypen (text/*) java.io.inputstream Alle Medientypen (*/*) java.io.reader Alle Medientypen (*/*) java.io.file Alle Medientypen (*/*) javax.activation.datasource Alle Medientypen (*/*) javax.xml.transform.source XML Medientypen (text/xml, application/xml, und Leichtgewichtige Webservices mit REST Seite 20

javax.xml.bind.jaxbelement und Anwendungs JAXB Klassen MultivaluedMap<String, String> StreamingOutput application/*+xml) XML Medientypen (text/xml, application/xml, und application/*+xml) Form Inhalt (application/x-www-form-urlencoded) Alle Medientypen (*/*), nur MessageBodyWriter (Hadley & Sandoz, 2009) Beispiel: byte[] kann automatisch in jeden Medientyp konvertiert werden und jeder Medientyp kann in ein byte[] konvertiert werden. @Path("hello") public class HelloResource { @GET @Produces("*/*") public byte[] sayhello() { return "Hello World!".getBytes(); @POST @Consumes("*/*") public void sayhello(byte[] name) { System.out.println("Hello " + new String(name)); Falls das noch nicht ausreichen sollte, gibt es die Option eigene Provider zu implementieren. Dies ist jedoch nicht im Umfang dieser Arbeit. Wir haben bereits gesehen, wie man z.b. mit der @PathParam Annotation Request Parameter in Java Methoden Parameter injizieren kann. Für das Injizieren des Inhalts des Request Bodys gibt es keine Annotation. Stattdessen wird dieser in den Requestparameter injiziert, welcher nicht annotiert ist. Mit der Annotation @Consumes kann der Medientyp des Request Bodys festgelegt werden. Beispiel: @Path("hello") public class HelloResource { @GET @Produces(MediaType.TEXT_PLAIN) @Consumes(MediaType.TEXT_PLAIN) public String sayhello(string name) { return "Hello " + name; 6.7.1. XML Durch die Integration der älteren Java Spezifikation JAXB (Java Architecture for XML Binding) ist JAX-RS in der Lage, ein beliebiges Java-Objekt, welches mit der JAXB Annotation @XmlRootElement gekennzeichnet ist, automatisch als XML Datei und eine XML Leichtgewichtige Webservices mit REST Seite 21

Datei in ein Java Objekt zu konvertieren. Dieser Vorgang wird auch als Marshalling und Unmarshalling bezeichnet. (Burke, 2010) Beispiel: @XmlRootElement public class Student { private String name; private int matrikelnumber; // getter + setter @Path("student") public class StudentResource { static HashMap<Integer, Student> students = new HashMap<Integer, Student>(); @POST @Consumes("application/xml") public void createstudent(student student) { savestudent(student); @GET @Path("{matrikelnumber") @Produces({ MediaType.APPLICATION_XML ) public Student getstudent(@pathparam("matrikelnumber") Integer matrikelnumber) { return students.get(matrikelnumber); private void savestudent(student student) { students.put(student.getmatrikelnumber(), student); In diesem Beispiel wird bei einem GET Request auf die student Ressource der Student mit der entsprechenden Matrikelnummer aus einer HashMap geladen, welche in diesem Beispiel als Datenbankmock dienen soll, und automatsch im XML Format in den Body der HTTP Response geschrieben. Der Konsument dieses Webservices würde nun beispielsweise folgende Antwort erhalten: <?xml version="1.0" encoding="utf-8" standalone="yes"?> <student> <matrikelnumber>12345</matrikelnumber> <name>felix</name> </student> Bei einem PUT Request muss der Client ein gültiges Customer XML Dokument in den Body des HTTP Requests schreiben, welcher dann von der JAX-RS Runtime ausgelesen und in den Methodenparameter Student student injiziert wird. Schließlich wird das Objekt in der students HashMap angespeichert. Leichtgewichtige Webservices mit REST Seite 22

6.7.2. JSON JSON (JavaScript Object Notation) ist wie XML ein Repräsentationsformat, jedoch ist der Aufbau leichtgewichtiger und Menschenleslicher. JSON Beispiel des Studenten: {"matrikelnumber":"12345","name":"name" Die Konvertierung von und zu einer JSON Repräsentation ist genauso einfach. Das einzige, was hierbei zu tun ist, ist die entsprechenden Methoden mit @Produces("application/json") zu Annotieren. Hier ist es ebenfalls wichtig, dass die Objekte, die zurückgegeben werden sollen mit @XmlRootElement annotiert sind. Die JSON Konvertierung ist allerdings nicht im JAX-RS Standard enthalten. Die Methode, welche ich hier beschreibe bezieht sich auf die Referenzimplementierung Jersey. @Path("student") public class StudentResource { @POST @Consumes({ "application/xml", "application/json" ) public void createstudent(student student) { savestudent(student); @GET @Path("{matrikelnumber") @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML ) public Student getstudent(@pathparam("matrikelnumber") Integer matrikelnumber) { return students.get(matrikelnumber); In diesem Beispiel wird bei einem GET Request je nach Wert des Accept Headers, das Studenten Objekt in das entsprechende Format konvertiert. Bei einem PUT Request kann entweder eine JSON oder eine XML Repräsentation des Studentenobjekts im Body stehen. Diese wird dann von JAX-RS automatisch Konvertiert und in den Methodenparameter injiziert. 6.8. Exceptions Aufgetretene Fehler können entweder per Response Objekt, oder durch eine geworfene Exception an den Client kommuniziert werden. Geworfene Exceptions werden von der JAX- RS Laufzeit behandelt, wenn ein Exceptionmapper registriert wurde. Dieser ordnet Exceptions zu HTTP Responses mit entsprechendem Responsecode zu. Falls kein Mapper registriert wurde, übernimmt das Servlet die Kontrolle. Leichtgewichtige Webservices mit REST Seite 23

Es gibt ebenfalls die Möglichkeit eine javax.ws.rs.webapplicationexception zu werfen, für die kein Exceptonmapper geschrieben werden muss. Dem Konstruktor dieser Exception kann ein Responseobjekt, ein Statuscode oder eine andere Exception übergeben werden. Falls die Exception mit einem Response Objekt oder einem Statuscode initialisiert wurde, werden diese verwendet um die HTTP Response zu erzeugen. Falls nicht, wird der Statuscode 500 Internal Server Exception an den Client geschickt. (Burke, 2010) Beispiel zu WebApplicationException: @Path("student") public class StudentResource { @GET @Path("{matrikelnumber") @Produces({ MediaType.APPLICATION_XML ) public Student getstudent(@pathparam("matrikelnumber") Integer matrikelnumber) { Student student = students.get(matrikelnumber); if(student == null) { throw new WebApplicationException(Response.Status.NOT_FOUND); return student; In diesem Beispiel wird versucht einen Studenten mit einer bestimmten Matrikelnummer zu laden. Falls der Student nicht gefunden werden konnte, wird der Statuscode 404 Not Found an den Client übergeben. Einen Exceptionmapper zu implementieren ist ebenfalls sehr einfach. Dazu muss das Interface javax.ws.rs.ext.exceptionmapper implementiert und die Klasse mit der Annotation @Provider gekennzeichnet werden. Diese weist JAS-RS an, den Mapper zu registrieren. Das Interface ExceptionMapper gibt die Methode toresponse(...) vor, welche eine Exception erwartet und ein Response Objekt zurückgibt: (Hadley & Sandoz, 2009) public interface ExceptionMapper<E extends Throwable> { Response toresponse(e exception); Beispielsweise wird die IllegalArgumentException an vielen Stellen geworfen. Um nicht jedes Mal diese Exception manuell zu behandeln, können wir uns einen Exceptionmapper schreiben, der uns die Arbeit abnimmt. @Provider public class IllegalArgumentMapper implements ExceptionMapper<IllegalArgumentException> { public void Response toresponse(illegalargumentexception exception) { return Response.status(Response.Status.BAD_REQUEST).build(); Leichtgewichtige Webservices mit REST Seite 24

JAX-RS wird nun bei einer geworfenen IllegalArgumentException, oder einer Exception, die davon abgeleitet wurde, den Statuscode 400 Bad Request an den Client senden. 7. Welche Implementierungen von JAX-RS gibt es? In diesem Kapitel werde ich kurz die wichtigsten Implementierungen der JAX-RS Spezifikation und die Besonderheiten dieser vorstellen. 7.1. Jersey Jersey ist die Referenzimplementierung von JAX-RS und ist in dem Application Server GlassFish enthalten. Ich habe es in meinen Beispielen verwendet, da es, wie wir im Kapitel 6.7.2 JSON sehen werden, eine sehr bequeme Möglichkeit bietet, eine JSON basierte REST API zu implementieren. Des Weiteren bietet Jersey Unterstützung bem Erstellen eines RESTful Clients. Momentan gibt es hierfür keinen offiziellen Standard. (Burke, 2010) 7.2. JBoss RESTEasy JBoss RESTEasy ist die JAX-RS Implementierung von Red Hat. Sie enthält einen Embedded Container, der es ermöglicht die Webservices einfach und schnell zu testen. Des Weiteren ist es mit RESTEasy möglich asynchrone HTTP Responses zu senden. Es wird ebenfalls eine Client API angebunden, welche, wie auch die Server API Performanceverbesserung durch Caching verspricht. (Burke, 2010) 7.3. Apache CXF Apache CXF ist ein populäres Open Source Framework, welches einige hilfreiche Zusätze bietet, wovon ich die interessantesten vorstellen will. Aggregieren von Request Parametern in Beans: Da die Anzahl von Methodenparametern schnell sehr groß werden kann, ist es mit Apache CXF möglich, verschiedene Requestparameter eines Typs (z.b. Queryparameter) in einer Bean zusammenzufassen. Bsp: @POST public void createstudent(@queryparam("") Student student) { savestudent(student); Leichtgewichtige Webservices mit REST Seite 25

In diesem Beispiel werden die Queryparameter matrikelnumber und name automatisch in das Studentenobjekt injiziert. Dies Funktioniert sogar bei verschachtelten Objekten (z.b. für ein im Studenten abgespeichertes Adressobjekt. Des Weiteren gibt es die Möglichkeit die Webservices nicht mit Annotationen, sondern per XML Konfiguration zu deklarieren. Eine Client API ist ebenfalls enthalten. (Burke, 2010) 8. REST gegen Schwergewichtige Webservices Mit schwergewichtig ist gemeint, dass diese Webservices wie z.b. SOAP, anders als RESTful Webservices, HTTP nicht als Anwendungsprotokoll verwenden, sondern das für jeden Service ein neues Protokoll definiert wird und HTTP meist nur als Transportprotokoll verwendet wird. SOAP verfolgt einen anderen Architekturstil als REST. Im Unterschied zu REST werden keine Ressourcen adressiert, sondern es wird häufig nur ein URI mittels HTTP POST aufgerufen. Die Semantik des Aufrufs wird in einem XML Dokument, welches sich im Message Body befindet, festgelegt. Hier liegen einige Probleme der Schwergewichtigen Webservices: Einen zu verstehen hilft nicht andere zu verstehen, da es keine einheitlichen Methoden gibt. Des Weiteren können einige Clients Probleme damit haben den Service zu konsumieren, da nur ein Datenformat (XML) unterstützt wird, wessen Aufbau genau spezifiziert werden muss. Zudem müssen viele Funktionen, die das HTTP Protokoll bietet, wie z.b. Autorisierung, Content Negotiation oder Caching neu erfunden werden. Der Vorteil der schwergewichtigen Webservices gegenüber RESTful Webservices ist, dass diese asynchrone Kommunikation und sogar verteilte Transaktionen unterstützen. Zusätzlich ist die durch die genaue Festlegung der Rückgabewerte das Interface genauer spezifiziert und Konsumenten können dies für die automatische Generierung von Clientcode nützen. 9. Fazit Meiner Meinung nach sind RESTful Webservices am besten für die Kommunikation mit externen Systemen geeignet, da die Skalierung durch die schlankeren Nachrichten und den HTTP Mechanismen wie Caching im Vergleich zu den schwergewichtigen Webservices besser funktioniert. Zusätzlich können Clients durch Content Negotiation unterschiedliche Repräsentationen anfordern, mit denen sie am besten arbeiten können. Leichtgewichtige Webservices mit REST Seite 26

Falls aber großer Wert auf Schnittstellenstabilität und komplexere Features wie verteile Transaktionen gelegt wird, ist SOAP momentan noch die bessere Alternative. Ich denke jedoch, dass sich in Zukunft die Tendenz eher in Richtung RESTful Webservices verlagern wird. Allerdings muss man sich als Webserviceentwickler meist den Anforderungen des Kunden oder einer bestehenden Systemlandschaft anpassen. Da heutzutage die meisten Webservices auf SOAP setzen, hat man oft gar nicht die Wahl sich für REST zu entscheiden. JAX-RS stellt eine sinnvolle, leichtgewichtige und einfache API zur Entwicklung von RESTful Webservices zur Verfügung, die allerdings keine Garantie für REST Konformität bietet. JAX- RS setzt bei der Konfiguration von Webservices rein auf Annotationen. So kann auf transparente und effiziente Weise eine beliebige Java Klasse als Webservice gekennzeichnet werden, sowie die Zuordnung von URIs zu Java Klassen und Methoden bzw. die Zuordnung von HTTP Verben zu Java Methoden erfolgen. Des Weiteren werden Annotationen für das Auslesen von Requestparametern und Content Negotiation bereitgestellt. Durch die Integration von JAXB muss sich der Entwickler nicht um die Konvertierung von und zu XML (im Fall von Jersey auch JSON) kümmern, sondern kann wie gewohnt mit Java Beans arbeiten. Zusätzlich wird die Möglichkeit angeboten, die HTTP Response nach Belieben zu gestalten, sowie applikationsspezifische Exceptions automatisiert in HTTP Responses umzuwandeln. Meiner Meinung nach wird momentan für das REST Prinzip Hypermedia As The Engine Of Application State noch zu wenig Unterstützung geboten. Es gibt zwar eine programmatische Lösung eine Methode einer bestimmten Ressource zu referenzieren. Jedoch gibt es keine deklarative Möglichkeit die Folgeaktionen inklusiver ihrem URI einer Methode automatisiert zurückzugeben. Des Weiteren funktioniert das Verlinken von aggregierten Objekten (z.b. ein Student, welcher eine Adresse hat) nicht automatisch und ist in Kombination mit JAX-B momentan nicht umzusetzen. Im Moment werden alle Verzweigungen zu anderen Domänenobjekten traversiert und in eine XML Datei zusammengefügt. Bsp.: <student> <matrikelnumber>12345</matrikelnumber> <name>felix</name> <address> <street>lothstr. 64</street> </address> </student> Leichtgewichtige Webservices mit REST Seite 27

Besser wäre, den URI der dazugehörigen Adresse anzugeben. Gerade bei komplexen Objekten kann durch diese Methode viel Bandbreite eingespart werden, was zu einer besseren Skalierbarkeit führt. Bsp.: <student> <matrikelnumber>12345</matrikelnumber> <name>felix</name> <address>http://example.com/address/54321</address> </student> Mein Vorschlag zu diesem Thema ist einen neuen Parameter in die @GET Annotation einzuführen, in der man das Class Objekt des zurückgegebenen Typs übergeben kann. Damit könnte in diesem Beispiel die Methode, welche eine Adresse zurückgibt mit dieser erweiterten Annotation gekennzeichnet werden. Bsp: @GET(Address.class) @Path("{id") @Produces({ MediaType.APPLICATION_XML ) public Address getaddress(@pathparam("id") Integer id) { Address address; // Adresse anhand der id aus der DB laden return address; Beim Serialisieren der Java Objekte in XML muss dann geprüft werden, ob das Class Objekt eines referenzierten Objekts (z.b. Address) in einer @GET Annotation einer Ressourcenklasse spezifiziert wurde. Ein anderer Ansatz wäre die von JAX-B bereitgestellten Annotationen um JAX-RS spezifische zu erweitern um die Webservicemethode (inklusive des Namens des Primärschlüssels des referenzierten Objekts, welcher als Parameter in die Webservicemethode übergeben wird) zu referenzieren, welche das Referenzierte Objekt zurückgibt. Bsp: @XMLRootElement class Student { private Integer matrikelnumber private String name @LinkedRessource(AddressRessource.class, "getaddress", "addressid") private Address address Schön wäre es ebenfalls, wenn an einer zentralen Stelle (z.b. im oder neben dem WADL) die XSD (XML Schema Definition) aller Entitäten, welche der Webservice definiert und mit @XmlRootElement annotiert sind, automatisch generiert werden würde. Dies hätte den Vorteil, dass der Client genau wüsste, welches Format er bei Methoden, welche z.b. einen Studenten als Parameter erwarten oder zurückliefern, zu übertragen bzw. zu erwarten hätte. Er könnte diese Information ebenfalls dazu nutzen, Code (z.b. mit dem Maven JAX-B Plugin) generieren zu lassen um vom XML Format zu abstrahieren. Leichtgewichtige Webservices mit REST Seite 28