Frameworks zur Entwicklung von RESTful Web Services

RESTEasy

Bei diesem Produkt handelt es sich um eine zertifizierte JAX-RS-Implementierung aus dem Hause JBoss. Es hat verschiedene Erweiterungen gegenüber dem Java-Web-Service-Standard aufzuweisen und lässt sich mit zahlreichen Technologien und Systemen integrieren. RESTEasy beeindruckt durch die Unterstützung zahlreicher Medientypen. So klappt das automatische Marshalling beziehungsweise Unmarshalling auf Basis von JAXB-Annotationen nicht nur für XML, sondern auch für JSON (wahlweise mit Jackson oder Jettison), Fastinfoset und Atom. Weiterhin wird YAML (YAML Ain’t Markup Language) unterstützt. Das Framework stellt außerdem APIs zur komfortablen Verarbeitung von Multipart- und GZIP-komprimierten Daten bereit.

Via Interceptors kann sich der Entwickler client- und serverseitig an verschiedenen Punkten der Nachrichtenverarbeitung einhängen. Das Package org.jboss.resteasy.spi.interception enthält für diese Zwecke verschiedene Interfaces. Jeder Interceptor muss eine dieser Schnittstellen implementieren und zusätzlich je nach Typ mit @ServerInterceptor beziehungsweise @ClientInterceptor annotiert werden (Listing 8). Ihre Aktivierung erfolgt entweder über die Konfigurationsdatei WEB-INF/web.xml oder auf programmatischem Weg.

Für die GET-Methoden kann der Programmierer mittels der Annotation @Cache und deren Attribute eine bestimmte Caching-Strategie festlegen. Wünscht er ein solches Verhalten nicht, annotiert er sie einfach mit @NoCache. Das Caching ist auch für REST-Clients aktivierbar.

In Sachen Asynchronität hat RESTEasy ebenfalls einiges zu bieten. So stellt es dem Nutzer ein einfaches Programmiermodell zur Verfügung, das die asynchrone Verarbeitung von HTTP Requests erlaubt. Des Weiteren macht das Framework Dienstaufrufe gemäß dem Asynchronous Job Pattern [5] möglich. Durch das Anhängen bestimmter Query-Parameter an den eigentlichen URL lassen sich die synchronen Aufrufe dadurch ganz einfach in asynchrone umwandeln.

Listing 8
...
@ServerInterceptor
public class MyLoggingInterceptor implements PreProcessInterceptor {
  @Override
  public ServerResponse preProcess(HttpRequest request, ResourceMethod method) 
          throws Failure, WebApplicationException {
    System.out.println("HTTP Method: " + request.getHttpMethod());
    System.out.println("Request URL: " + request.getUri().getRequestUri());
    return null;
  }
}

Das Deployment der Webdienste kann über den eingebetteten Server vorgenommen werden (Listing 9). Diese Vorgehensweise empfiehlt sich allerdings nur für Testzwecke. In produktiven Umgebungen sollte der Entwickler die Auslieferung besser in Form einer Webapplikation vornehmen. Das Servlet org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher übernimmt dabei die Rolle des Front Controllers. Die Konfiguration nimmt er anhand verschiedener Parameter unter WEB-INF/web.xml vor. Am einfachsten ist es, darin den automatischen Scan- und Deploy-Modus zu aktivieren. Erfreulicherweise hat RESTEasy im Gegensatz zu Jersey kein Problem damit, wenn die JAX-RS-Annotationen in das Interface anstatt in die Ressourcenklasse gepackt wurden. Sofern zum Ausrollen der JBoss Application Server 6 genutzt wird, vereinfacht sich die Prozedur weiterhin. In diesem Fall muss nämlich weder das Front Controller Servlet im Deployment Descriptor eingetragen werden, noch sind die RESTEasy-Bibliotheken unter WEB-INF/lib mitzuliefern.

Listing 9
List providers = new ArrayList();
providers.add(BookNotFoundExceptionMapper.class);
providers.add(MyLoggingInterceptor.class);

TJWSEmbeddedJaxrsServer server = new TJWSEmbeddedJaxrsServer();
server.setRootResourcePath("/resources");
server.setPort(8080);
server.getDeployment().getActualResourceClasses().add(BookResourceImpl.class);
server.getDeployment().setActualProviderClasses(providers);
server.start();
...
server.stop();

Das Erstellen von REST-Clients erfolgt in ähnlicher Form wie bei der erstgenannten CXF-Variante. Mithilfe der Klasse org.jboss.resteasy.client.ProxyFactory wird zu einem mit JAX-RS-Annotationen versehenen Interface ein dynamischer Proxy erzeugt (Listing 10), über den der Nutzer die Methodenaufrufe vornimmt. Glücklicherweise sind für RESTEasy selbst Kontextvariablen in Methodensignaturen kein Problem. Es ignoriert diese auf der Clientseite ganz einfach.

Listing 10
Book book = ...;

RegisterBuiltin.register(ResteasyProviderFactory.getInstance());

BookResource resource = ProxyFactory.create(BookResource.class, 
                                "http://localhost:8080/resources/");
Response response = resource.create(null, book);

System.out.println("Status Code: " + response.getStatus());
System.out.println("Location: " + response.getMetadata().get("Location"));
Fazit

Der Artikel stellte mit Apache CXF, Jersey und RESTEasy drei bedeutende Vertreter zur Entwicklung von RESTful Web Services und zugehöriger Clients vor. Auf Restlet gingen wir nicht ein, weshalb es zumindest hier noch namentlich erwähnt werden soll. Wir konnten feststellen, dass all diese Frameworks direkten JSON-Support bieten, wodurch sich der Code unseres Bücherdienstes weiterhin vereinfachte. Da JAX-RS keine Client-API spezifiziert, das soll sich mit JAX-RS 2.0 aber ändern [6], weist derzeit jedes Framework eine proprietäre Lösung auf. Im Grunde lassen sich hierbei zwei Varianten unterscheiden: Bei der ersten wird zu einer mit JAX-RS-Annotationen ausgezeichneten Schnittstelle ein dynamischer Proxy für die Dienstabfrage generiert, bei der zweiten werden die abzusetzenden HTTP Requests mittels Method Chaining [7] zusammengebaut. Beide Methoden erlauben ein komfortables Arbeiten. Somit kann ohne Übertreibung festgehalten werden, dass diese virtuellen Baugerüste dem Nutzer den Rest geben, und zwar an fehlenden Funktionen.

Ein paar Worte zum Abschluss

Eine weite Reise liegt hinter uns, und doch sahen wir nur einen kleinen Ausschnitt des riesigen Web-Service-Universums. Aber ein Anfang ist nun gemacht und einer Vertiefung im Selbststudium steht nichts im Weg, wenngleich das in Verbindung mit einigen Frameworks ein etwas mühsames Unterfangen werden könnte. Am Horizont konnten wir zumindest schemenhaft einige der WS-*-Features erblicken, näher eingegangen sind wir auf diese allerdings nicht. Erahnen lässt sich jedoch, in Form welcher Komponenten uns diese zumeist begegnen werden. Na klar, als Interceptors, Handler und Filter. Sollten noch Fragen bestehen, können Sie mich gerne kontaktieren. So bleibt mir, Ihnen nur mehr eines zu wünschen: Mögen Ihnen Ihre Webdienste stets wie erwartet zu Diensten sein!

Bernhard Löwenstein (b.loewenstein[at]gmx.at) arbeitet als Projektleiter und Softwareentwickler für die Potsdamer Intervista AG. Er ist außerdem als IT-Trainer tätig und schreibt laufend Artikel für verschiedene deutsche Fachmagazine.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.