85
Prof. Dr. Stephan Kleuker 476 5. RESTful Web Services JavaScript Object Notation • JSONP Idee: Web-Services Idee: RESTful erste Services GET, POST • Clients • Response • Path-Parameter • Aufrufparameter Architektur von REST-Applikationen Fallstudie (GET, POST, PUT, DELETE) • Ausblick Komponentenbasierte Software- Entwicklung

5. RESTful Web Services - home.edvsz.hs-osnabrueck.dehome.edvsz.fh-osnabrueck.de/skleuker/WS14_KbSE/WS1415... · 2014-12-07 · •JSR 339: JAX-RS 2.0: The Java API for RESTful Web

  • Upload
    buihanh

  • View
    216

  • Download
    0

Embed Size (px)

Citation preview

Prof. Dr. Stephan Kleuker

476

5. RESTful Web Services

• JavaScript Object Notation

• JSONP

• Idee: Web-Services

• Idee: RESTful

• erste Services

• GET, POST

• Clients

• Response

• Path-Parameter

• Aufrufparameter

• Architektur von REST-Applikationen

• Fallstudie (GET, POST, PUT, DELETE)

• Ausblick

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

477

Ausblick auf weitere Themen

Komponentenbasierte Software-Entwicklung

Browser

Datenbank

JPA

EJBBean

Validation

CDIScope

JSFRESTful

WebService

Web Sockets 2

1

3

Prof. Dr. Stephan Kleuker

478

Einstieg JSON

• JavaScript Object Notation (http://json.org/)

• textuelles Austauschformat, abgeleitet aus JavaScript{ "name": "Tony Stark",

"alter": 42,

"firma": { "name": "Stark Industries",

"ort": "New York, N.Y"

},

"freunde":["Steve Rogers", "Bruce Banner"]

}

• Sammlung von

– (Name: Wert)-Paaren

– Arrays von Werten

• Werte können wieder aus beiden Elementen bestehen

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

479

Vereinheitlichung von JSON in Java

in JEE 7 ergänzt:

• JSR 353: JavaTM API for JSON Processing (23.5.2013), https://jcp.org/en/jsr/detail?id=353

• Referenzimplementierung jsonp https://jsonp.java.net/

• in Glassfish 4.0 enthalten

zwei zentrale APIs

• Object Model API; sehr analog zum DOM API für XML parsing

• Streaming API; sehr analog zum StAX API

• unabhängig von Programmiersprachen nutzbar

• kompakter als XML (ähnlich gut/schlecht menschenlesbar)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

480

Beispiel: JSON-Object lesen (1/2)

public static void main(String[] args) {

String daten =

"{ \"name\": \"Tony Stark\","

+ " \"alter\": 42,"

+ " \"firma\": { \"name\": \"Stark Industries\","

+ " \"ort\": \"New York, N.Y\""

+ "},"

+ "\"freunde\":[\"Steve Rogers\", \"Bruce Banner\", 42]"

+ "}";

JsonReader reader = Json.createReader(new StringReader(daten));

JsonObject tony = reader.readObject();

reader.close();

//Set<String> namen = tony.keySet(); // geht auch

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

481

Beispiel: JSON-Objekt lesen (2/2)

System.out.println("Name : " + tony.getString("name"));

System.out.println("Alter : " + tony.getInt("alter"));

JsonObject firma = tony.getJsonObject("firma");

System.out.println("Firmenname : " + firma.getString("name"));

System.out.println("Umsatz : " + firma.getInt("umsatz", 20));

JsonArray freunde = tony.getJsonArray("freunde");

for (JsonValue freund : freunde) {

System.out.println(freund + " * " + freund.getValueType());

}

}

Name : Tony Stark

Alter : 42

Firmenname : Stark Industries

Umsatz : 20

Steve Rogers * STRING

Bruce Banner * STRING

42 * NUMBER

Default, wenn nicht da

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

482

Beispiel: JSON-Objekt von Hand erstellen

public static void main(String[] args) {

JsonObject personObject = Json.createObjectBuilder()

.add("name", "Bruce Banner")

.add("alter", 44)

.add("firma",

Json.createObjectBuilder()

.add("name", "Shield")

.add("ort", "unbekannt")

.build())

.add("freunde",

Json.createArrayBuilder()

.add("James Howlett")

.add("Ben Grimm")

.build())

.build();

System.out.println("Object: " + personObject);

}

Object:

{"name":"Bruce

Banner","alter":44,"f

irma":{"name":"Shield

","ort":"unbekannt"},

"freunde":["James

Howlett","Ben

Grimm"]}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

483

Ausschnitt Klassendiagramm

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

484

Beispiel: Stream-Bearbeitung von JSON

// daten: siehe JSON lesen

JsonParser parser = Json

.createParser(new StringReader(daten));

while (parser.hasNext()) {

Event event = parser.next();

System.out.print(event + ": ");

switch (event) {

case KEY_NAME:

System.out.print(parser.getString());

break;

case VALUE_NUMBER:

System.out.print(parser.getInt());

break;

}

System.out.println("");

}

START_OBJECT:

KEY_NAME: name

VALUE_STRING:

KEY_NAME: alter

VALUE_NUMBER: 42

KEY_NAME: firma

START_OBJECT:

KEY_NAME: name

VALUE_STRING:

KEY_NAME: ort

VALUE_STRING:

END_OBJECT:

KEY_NAME: freunde

START_ARRAY:

VALUE_STRING:

VALUE_STRING:

VALUE_NUMBER: 42

END_ARRAY:

END_OBJECT:Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

485

Binding

• Binding schafft automatische Umwandlungsmöglichkeit von A nach B und von B nach A

• ohne Binding muss die Umwandlung (marshalling) manuell erfolgen, bei Netztransport ggfls. Rückumwandlung notwendig (unmarshalling)

• Java-Objekt von und nach XML löst JAXB

• JSR 222: JavaTM Architecture for XML Binding (JAXB) 2.0, https://jcp.org/en/jsr/detail?id=222

• wichtig Umwandlungsprozess konfigurierbar

• Java-Objekt von und nach JSON noch nicht standardisiert (für JEE 8 angekündigt)

• Referenzimplementierung für Glassfish (Stand Ende 2013) ist MOXy (übersetzt JAXB-Annotationen nach JSON)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

486

Beispiel: Vorbereitung einer Entitäts-Klasse für JSON

@XmlRootElement

public class Punkt implements Serializable {

private int x;

private int y;

public Punkt() {} // wichtig

public Punkt(int x, int y) {this.x = x; this.y = y;}

public int getX() {return x;}

public int getY() {return y;}

public void setX(int x) {this.x = x;}

public void setY(int y) {this.y = y;}

@Override

public String toString() {return "[" + x + "," + y + "]";}

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

487

Annotationen zur Steuerung der Übersetzung

@XmlElement(name=“rufname") // Key-Umbenennung

public String name;

@XmlTransient // nicht übertragen

public int alter;

• man beachte, dass man erhaltenes Objekt auch noch mit vorherigen Methoden modifizieren kann

• Übersetzung noch nicht standardisiert (aktuell MOXy, Teil von EclipseLink)

• da manuelle JsonObject-Erzeugung nicht sehr aufwändig und sehr flexibel, wird es gute Alternative bleiben

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

488

Hintergrund Web Services

• zentraler Wunsch: einfache Nutzung von Software über das Netz

• unabhängig wo sich ein Rechner befindet

• unabhängig von der Programmiersprache

SOAP-basierte WebServices

• jeder Service hat eindeutige Kennung (URI, Uniform Resource Identifier)

• Schnittstellenbeschreibung WSDL

• typisch: XML-basierte Kommunikationsprotokolle

• typisch: Verbindung mit SOA

• hier nicht wichtig, aber SOA ≠ SOAP ≠ Web Service

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

489

Hintergrund: Service Oriented Architecture

Service-

Verzeichnis

Service-

Anbieter

Service-

Nutzer

3. Anfragen

4. Antworten

SOAP

WSDL

HTTP

UDDI

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

490

Zwischenfazit SOA

• Vision: auf Grundlage von Geschäftsprozessmodellierungen kann individuelle Software für ein Unternehmen entstehen

• Realität: machbar, wenn alles auf einem Hersteller basiert

• Realität: UDDI hat in fast allen Projekten nicht stattgefunden (SOA ist auch Super Overhyped Acronym)

• aber: WebServices basierend auf SOAP haben als Kommunikationskonzept zentrale Bedeutung bekommen

• gilt als relativ langsam

• aber: Unternehmen nutzen es um MS-basierte Oberfläche mit JEE-realisiertem Server zu verbinden

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

491

RESTful (Representational State Transfer)

• Idee von der Interaktion zwischen Rechnern bleibt

• REST ist ein Architekturstil für verteilte Hypermedia-Systeme

• Protokoll: nutze Möglichkeiten von HTTP

– GET: lese Information (SELECT)

– POST: neue Information (INSERT)

– PUT: ändere Information (UPDATE)

– DELETE: lösche Information (DELETE)

• Klammern deuten Ähnlichkeit zu Datenbankoperationen an

• Grundlage: Dissertation Roy Fielding „Architectural Styles and the Design of Network-based Software Architectures “

• http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

492

Woher kommt „ Representational State Transfer“

Client fordert Information mit Hilfe einer URL an.

Eine Repräsentation der Information wird als Ergebnis zurückgegeben (z. B. in Form eines JSON-Objekts), Client hat Informationszustand.

Client nutzt Hyperlink in Ergebnis um weitere Informationen anzufordern.

Neues Ergebnis versetzt Client in einen neuen Informationszustand.

ResourceClient

http://www.scrumsprinter.de/sprint/42

{ “id”: 42,

“name”: “Prototyp”,

“elemente”: [ …

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

493

HATEOAS – saubere REST-Architektur

„Hypermedia as the Engine of Application State“

• Client kennt nur die Basis-URI des Dienstes

• Server leitet durch Informationszustände der Anwendung durch Bekanntgabe von Wahlmöglichkeiten (Hyperlinks)

• Der vollständige Informationszustand kann beim Client oder beim Server liegen, oder auch über beide verteilt sein

• HTTP-Kommunikationsprotokoll selbst bleibt zustandslos

• Grundregel: GET, PUT, DELETE sind idempotent; führen zum gleichen Ergebnis, egal wie oft sie im gleichen Informationszustand aufgerufen werden

• häufig genutzter Trick: POST auch zur partiellen Aktualisierung

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

494

Wer nutzt es (Beispiele)?

• Hinweis: Öfter wird gegen die geforderte Reinform von RESTful WebServices verstoßen, und normale Anfragemöglichkeit mit GET als RESTful bezeichnet

• Google Maps

• Google AJAX Search API

• Yahoo Search API

• Amazon WebServices

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

495

Standardisierung in Java

viele Implementierungen

• Restlet http://www.restlet.org/

• Apache CXF http://cxf.apache.org/

• Project Zero http://www.projectzero.org

• GlassFish Jersey https://jersey.dev.java.net/ (Referenz)

• JBoss RESTeasy http://www.jboss.org/resteasy/

Standardisierung für Java:

• JSR 311: JAX-RS: The JavaTM API for RESTful Web Services, https://jcp.org/en/jsr/detail?id=311 (10.10.2008)

• JSR 339: JAX-RS 2.0: The Java API for RESTful Web Services, https://jcp.org/en/jsr/detail?id=339 (24.5.2013)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

496

JAX-RS aktivieren

• in JEE-aware Servern reicht theoretisch folgendes ausimport javax.ws.rs.ApplicationPath;

import javax.ws.rs.core.Application;

@ApplicationPath("resources")

public class ApplicationConfig extends Application {

}

• ist generell im .war-File

• sonst Konfiguration als Servlet nötig

• Beschreibung in web.xml

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

497

JAX-RS aktivieren (Alternative)

@ApplicationPath("resources")

public class ApplicationConfig extends Application {

@Override

public Set<Class<?>> getClasses() {

Set<Class<?>> resources = new java.util.HashSet<>();

try { // customize Jersey 2.0 JSON provider:

Class jsonProvider = Class

.forName("org.glassfish.jersey.moxy.json.MoxyJsonFeature");

resources.add(jsonProvider);

} catch (ClassNotFoundException ex) {}

addRestResourceClasses(resources);

return resources;

}

private void addRestResourceClasses(Set<Class<?>> resources) {

resources.add(hello.HelloWorld.class);

}

}

Anbieter von Services

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

498

erste RESTful-WebServices

@Path("/helloworld")

public class HelloWorld {

public HelloWorld() { }

@GET

@Produces("text/html")

public String getHtml() {

return "<html><body><h1>Hello, World!!</h1></body></html>";

}

@GET

@Produces(MediaType.TEXT_PLAIN)

public String getText() {

return "Tach Welt";

}

}Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

499

detaillierte Analyse

@Path("/helloworld")

• Gibt Aufrufpfad an, hier resources/helloworld

• könnte auch nur an einzelnen Methoden stehen

• kann auch zusätzlich an Methoden stehen, so dass sich der Pfad verlängert

@GET

@Produces("text/html")

• Annotationen aus javax.ws.rs

• HTTP-Befehl und Ergebnistyp (mögliche Ergebnistypen, mehrere MIME-Typen [Multipurpose Internet Mail Extension])

• nachfolgender Methodenname spielt keine Rolle!Komponentenbasierte Software-

Entwicklung

Prof. Dr. Stephan Kleuker

500

direkter Aufruf

• bei GET ist direkter Aufruf im Browser möglich

• aber, das ist ein sehr sehr untypisches Szenario

• typisch:

– Aufruf direkt aus einer Web-Seite, meist mit JavaScript

– Aufruf aus anderer Software heraus mit Mitteln der jeweiligen Programmiersprache (z. B. java.net.URL)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

501

Detaillierte Analyse mit cURL

• generell jedes Programm zur Erzeugung von HTTP-Aufrufen und Analyse der Ergebnisse geeignet

• Kommando-Zeile mit cURLhttp://curl.haxx.se/download.html

• Für etwaige Parameter muss auch URL in Anführungsstrichen stehen

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

502

Nutzung automatischen Marshallings - GET

• verschiedene Rückgabetypen bedienbar (praktisch sinnvoll?)@GET

@Produces({MediaType.TEXT_XML, MediaType.APPLICATION_JSON})

public Punkt getJSon2() {

return new Punkt(42,43); // war @XMLRootElement annotiert

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

503

Nutzung automatischen Unmarshallings - POST

@POST

@Produces(MediaType.TEXT_PLAIN)

@Consumes(MediaType.APPLICATION_JSON)

public String postit(Punkt p){

System.out.println(p);

return "ok";

}

• weitere Parameter im JSON-Objekt führen zu Fehlern

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

504

zentrale Klassen Client und Response

• RESTful Web Services werden typischerweise aus anderer Software aufgerufen

• dies ist natürlich auch in Java möglich; vor JAX-RS 2.0 aber proprietäre Lösungen der Anbieter

• jetzt Klasse javax.ws.rs.client.Client

• Bei der Nutzung von RESTful Web Services können verschiedene Klassen als Typen für Parameter und Rückgabe genutzt werden

• Hilfreich ist Klasse javax.ws.rs.core.Response

• Server erzeugt Response-Objekt

• Client kann problemlos Response-Objekt lesen

• Response ist ein Stream, muss auch geschlossen werden

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

505

Hilfsmethode zur genaueren Analyse von Response

private void details(Response res) {

System.out.println("-----------------\n"

+ "AllowedMethods : " + res.getAllowedMethods() + "\n"

+ "Entity Class: " + res.getEntity().getClass() + "\n"

+ "Language : " + res.getLanguage() + "\n"

+ "Location : " + res.getLocation() + "\n"

+ "Mediatype : " + res.getMediaType() + "\n"

+ "Links : " + res.getLinks() + "\n"

+ "Status : " + res.getStatus() + "\n"

+ "Date : " + res.getDate() + "\n"

+ "Class : " + res.getClass() + "\n"

+ "Inhalt : " + res.readEntity(String.class));

res.close();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

506

Kleine Beispiele (1/7)

• Anmerkung: Zeigt Service-Nutzung, zeigt nichts von RESTpublic class ClientAnalyse {

private Client client;

private WebTarget userTarget;

public ClientAnalyse() {

Client client = ClientBuilder.newClient();

userTarget = client

.target("http://localhost:8080/resources/helloworld");

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

507

Kleine Beispiele (2/7)

public void analyse1() {

Response res = userTarget.request("text/html").get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : text/html

Links : []

Status : 200

Date : Wed May 14 18:55:35 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

508

Kleine Beispiele (3/7)

public void analyse1() {

Response res = userTarget.request(MediaType.TEXT_PLAIN).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : text/plain

Links : []

Status : 200

Date : Wed May 14 18:55:35 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : <html lang="en"><body><h1>Hello, World!!</h1></body></html>

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

509

Kleine Beispiele (4/7)

public void analyse3() {

Response res = userTarget

.request(MediaType.APPLICATION_JSON).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : application/json

Links : []

Status : 200

Date : Wed May 14 18:55:35 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : {"x":42,"y":43}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

510

Kleine Beispiele (5/7)

public void analyse4() {

Response res = userTarget.request(MediaType.TEXT_XML).get();

details(res);

}

AllowedMethods : []

Entity Class: class org.glassfish.jersey.client.HttpUrlConnector$1

Language : null

Location : null

Mediatype : text/xml

Links : []

Status : 200

Date : Wed May 14 19:08:13 CEST 2014

Class : class org.glassfish.jersey.client.ScopedJaxrsResponse

Inhalt : <?xml version="1.0" encoding="UTF-8"

standalone="yes"?><punkt><x>42</x><y>43</y></punkt>

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

511

Kleine Beispiele (6/7)

public void analyse5() {

Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);

Entity e = Entity.entity(new Punk(3, 4)

, MediaType.APPLICATION_JSON);

System.out.println(e + " : " + e.getEntity());

String res = buil.post(e, String.class);

System.out.println(res);

}

javax.ws.rs.client.Entity@52aa911c : [3,4]

ok

• Anmerkung: Klasse Punk wie Punkt, sogar ohne XMLRootElement-Annotation , aber Serializable

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

512

Kleine Beispiele (7/7)

public void analyse5() {

Builder buil = this.userTarget.request(MediaType.TEXT_PLAIN);

Entity e = Entity.json(new Punk(2,3));

System.out.println(e + " : " + e.getEntity());

String res = buil.post(e, String.class);

System.out.println(res);

}

javax.ws.rs.client.Entity@49fa424c : [2,3]

ok

• Klasse Entity bietet einige Marshalling-Methoden

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

513

flexible Dienststrukturen

• generell soll man aus Antworten auf weitere Abfragemöglichkeiten schließen können

• /helloworld/kunden/

Frage nach Kunden: Sammlung der Namen aller Kunden

• /helloworld/kunden/Hoeness/

Frage nach Kunden mit Namen: alle Eigenschaften des Kunden

• /helloworld/kunden/Hoeness/konten

Frage nach Konten eines benannten Kunden: Sammlung aller Konten des Kunden

• /helloworld/kunden/Hoeness/konten/42

Frage nach Kontonummer eines benannten Kunden: alle Eigenschaften des Kontos dieses Kunden

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

514

Beispiel: Umsetzung von Pfaden (1/4)

@Path("helloworld")

public class HelloWorld {

// Kundenname, Sammlung von Konten (Nummer, Betrag)

private Map<String, Map<Integer, Long> > kunden;

public HelloWorld() {

// zufaellige Beispieldaten

Map<Integer,Long> tmp = new HashMap<>();

tmp.put(42,32000000L);

kunden = new HashMap<>();

kunden.put("Hoeness", tmp);

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

515

Beispiel: Umsetzung von Pfaden (2/4)

@GET

@Produces(MediaType.APPLICATION_JSON)

@Path("/kunden/{user}/konten/{id}")

public JsonObject getKontostand(

@PathParam("user") String user

, @PathParam("id") int id) {

JsonObjectBuilder erg = Json.createObjectBuilder();

Map<Integer,Long> kunde = kunden.get(user);

if(kunde == null){

return erg.add("fehler", "kein Kunde").build();

}

Long summe = kunde.get(id);

if(summe == null){

return erg.add("fehler", "kein Konto").build();

}

return erg.add("summe", summe).build();

}Komponentenbasierte Software-

Entwicklung

Prof. Dr. Stephan Kleuker

516

Beispiel: Umsetzung von Pfaden (3/4)

public static void main(String[] a){

String[] verdaechtig = {"Rummenigge", "Hoeness"};

int[] nummern = {42,43};

Client client = ClientBuilder.newClient();

for(String v:verdaechtig){

for (int n:nummern){

WebTarget target = client.target(

"http://localhost:8080/resources/helloworld/kunden/"

+ v + "/konten/" + n);

JsonObject erg = target

.request(MediaType.APPLICATION_JSON)

.get(JsonObject.class);

System.out.println(erg);

}

}

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

517

Beispiel: Umsetzung von Pfaden (4/4)

{"fehler":"kein Kunde"}

{"fehler":"kein Kunde"}

{"summe":32000000}

{"fehler":"kein Konto"}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

518

Umsetzung von Pfaden

@Path("/kunden/{user}/konten/{id}")

• Einbau von Pfadvariablen, auf die in Parameterliste mit @PathParam("user") zugegriffen werden kann

• einfache Java-Typen, typischerweise int, long, String nutzbar; Konvertierung automatisch

• Pfadvariablen in der Klassenannotation können dann in jedem Methodenkopf genutzt werden

• Pfadvariablen können in @Path doppelt vorkommen und müssen dann gleichen Wert bei Nutzung haben

• im Hinterkopf: wenn HTTPS, dann auch User-Token so übertrag- und später prüfbar (Sicherheit)

• im Hinterkopf: individueller Wert für jeden Nutzer, der E-Mail mit so einem Link erhält

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

519

Externer Service zur Analyse von IPs (1/4)

private static void zeigeJsonObjekt(JsonObject js){

for(String key:js.keySet()){

System.out.println(key+ ": " + js.get(key));

}

}

public static void main(String[] s){

String SERVICE = "http://freegeoip.net/json";

Client client = ClientBuilder.newClient();

WebTarget wt = client.target(SERVICE);

Invocation.Builder invoc = wt.request();

JsonObject ergebnis = invoc.get(JsonObject.class);

zeigeJsonObjekt(ergebnis);

zeigeJsonObjekt(client.target(SERVICE+"/www.bild.de")

.request().get(JsonObject.class));

}Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

520

Externer Service zur Analyse von IPs (2/4)

ip: 93.196.192.46

country_code: DE

country_name: Germany

region_code: 07

region_name: Nordrhein-Westfalen

city: Hopsten

zipcode:

latitude: 52.3833

longitude: 7.6167

metro_code:

area_code:

ip: 209.8.115.88

country_code: US

country_name: United States

region_code: TX

region_name: Texas

city: Dallas

zipcode:

latitude: 32.7831

longitude: -96.8067

metro_code: 623

area_code: 214

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

521

Externer Service zur Analyse von IPs (3/4)

public static void main(String[] st){

Client client = ClientBuilder.newClient();

WebTarget wt = client.target("http://freegeoip.net/json");

Invocation.Builder invoc = wt.request();

Response ergebnis = invoc.get();

System.out.println(ergebnis);

ergebnis.bufferEntity(); // sonst Fehler bei 42

System.out.println(ergebnis.getEntity());

for(String s:ergebnis.getHeaders().keySet()){

System.out.println(s +": " + ergebnis.getHeaders().get(s));

}

System.out.println(ergebnis.readEntity(JsonObject.class));

System.out.println(ergebnis.getEntity().getClass()); //42

ergebnis.close();

}Komponentenbasierte Software-

Entwicklung

Prof. Dr. Stephan Kleuker

522

Externer Service zur Analyse von IPs (4/4)

ScopedJaxrsResponse{ClientResponse{method=GET,

uri=http://freegeoip.net/json, status=200, reason=OK}}

java.io.ByteArrayInputStream@6d420a24

Date: [Wed, 14 May 2014 17:48:10 GMT]

Access-Control-Allow-Origin: [*]

Content-Length: [222]

Content-Type: [application/json]

{"ip":"93.196.192.46","country_code":"DE","country_name":"Germany","

region_code":"07","region_name":"Nordrhein-

Westfalen","city":"Hopsten","zipcode":"","latitude":52.3833,"longitu

de":7.6167,"metro_code":"","area_code":""}

class java.io.ByteArrayInputStream

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

523

Übergabe von Aufrufparametern (1/2)

@GET

@Produces(MediaType.APPLICATION_JSON)

@Path("/rechnen")

public JsonObject machMathe(

@QueryParam("op1") int op1,

@QueryParam("op2") int op2,

@DefaultValue("plus")

@QueryParam("operator") String operator) {

JsonObjectBuilder erg = Json.createObjectBuilder();

if(operator.equals("minus")){

return erg.add("operator", operator)

.add("ergebnis", (op1-op2)).build();

}

return erg.add("operator", "plus")

.add("ergebnis", (op1+op2)).build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

524

Übergabe von Aufrufparametern (2/2)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

525

Dienstnutzung mit Aufrufparametern (1/2)

public static void main(String[] s) {

String SERVICE

= "http://maps.googleapis.com/maps/api/geocode/json";

Client client = ClientBuilder.newClient();

WebTarget wt = client.target(SERVICE +

"?address=Quakenbrueck&sensor=false");

Invocation.Builder invoc = wt.request();

JsonObject ergebnis = invoc.get(JsonObject.class);

System.out.println(ergebnis);

JsonObject details = ((JsonArray)ergebnis.get("results"))

.getJsonObject(0);

JsonObject position= (JsonObject)

((JsonObject)details.get("geometry")).get("location");

System.out.println(position);

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

526

Dienstnutzung mit Aufrufparametern (2/2)

{"results":[{"address_components":[{"long_name":"Quakenbrück","

short_name":"Quakenbrück","types":["locality","political"]},{"l

ong_name":"Osnabrück","short_name":"OS","types":["administrativ

e_area_level_3","political"]},{"long_name":"Lower

Saxony","short_name":"NDS","types":["administrative_area_level_

1","political"]},{"long_name":"Germany","short_name":"DE","type

s":["country","political"]}],"formatted_address":"Quakenbrück,

Germany","geometry":{"bounds":{"northeast":{"lat":52.6967289,"l

ng":8.0344312},"southwest":{"lat":52.65917049999999,"lng":7.903

767999999999}},"location":{"lat":52.675599,"lng":7.950777699999

999},"location_type":"APPROXIMATE","viewport":{"northeast":{"la

t":52.6967289,"lng":8.0344312},"southwest":{"lat":52.6591704999

9999,"lng":7.903767999999999}}},"types":["locality","political"

]}],"status":"OK"}

{"lat":52.675599,"lng":7.950777699999999}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

527

Aufgabe

Sprinter soll um eine RESTful-Schnittstelle ergänzt werden,

• mit der von außen auf Sprints zugegriffen werden kann,

• die nur eine Teilmenge der Daten der Sprints sieht,

• die neue Sprints anlegen kann,

• die Sprints editieren kann,

• die Sprints löschen kann

• Entscheidung: Ergänze Programm um RESTful Webservices

• Schnittstelle wird in neuem Projekt genutzt (das zum einfacheren Verständnis eine JSF-Oberfläche bekommt)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

528

Nutzungsszenario

• Links nicht ausimplementiert

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

529

Architektur: hierarchischer Aufbau

Resource POST(CREATE)

GET(READ)

PUT(UPDATE)

DELETE(DELETE)

/sprints erzeugt neuen Sprint

Übersicht über alle Sprints

Aktualisiere alle Sprints (oder weglassen)

alle Sprints löschen

/sprints/42 Fehler! Zeige Sprint mit id 42

wenn Sprint mit id 42 existiert, dann aktualisieren, sonst Fehler

Lösche den Sprint mit id42

Hinweise: noch sauberer wäre /sprint/42 (Einzahl)graue Felder nicht realisiert

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

530

Einordnung SprintRestController (Server)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

531

Client (minimal)

Komponentenbasierte Software-Entwicklung SprinterRESTClient

Prof. Dr. Stephan Kleuker

532

Vorbereitung im Server

@Stateless // oder @Singleton

@Path("")

public class SprintRestController implements Serializable{

@Inject

private PersistenzService pers;

@Context

private UriInfo uriInfo; // später genauer

private SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

public SprintRestController() {

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

533

Hilfsmethode zum Sprint einpacken

private JsonObject jsonSprint(Sprint s, boolean einzeln) {

String idzeigen = (einzeln) ? "" : "" + s.getId();

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("id", s.getId())

.add("motto", s.getMotto())

.add("starttermin", formatter.format(s.getStarttermin()))

.add("endtermin", formatter.format(s.getEndtermin()))

.add("geplanterAufwand", s.getGeplanterAufwand())

.add("farbe", s.color())

.add("link", uriInfo.getAbsolutePathBuilder()

.path(idzeigen + "/backlogElemente")

.build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

534

GET /sprints (1/2)

@GET

@Produces({MediaType.APPLICATION_JSON})

@Path("/sprints")

public JsonObject getSprints(

@DefaultValue("-1") @QueryParam("von") int von,

@DefaultValue("-1") @QueryParam("bis") int bis) {

List<Sprint> alle = pers.findAllSprint();

if (von < 0 || von >= alle.size()) {

von = 0;

}

if (bis < 0 || bis >= alle.size()) {

bis = alle.size() - 1;

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

535

GET /sprints (2/2)

JsonArrayBuilder elemente = Json.createArrayBuilder();

for (int i = von; i <= bis; i++) {

elemente.add(jsonSprint(alle.get(i), false));

}

return Json.createObjectBuilder()

.add("sprints", elemente)

.build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

536

Client – Vorbereitung (1/2)

• Client braucht keine echte Datenhaltung

• Ansatz: Daten lokal in SessionScope halten (für kleinere Datenmengen ok

@Named

@SessionScoped

public class SprintController implements Serializable {

private Client client;

private List<Map<String, Object>> sprints;

private final static String[] keys = {"id", "motto"

, "starttermin", "endtermin", "geplanterAufwand"

, "link", "farbe"};

private final static String SPRINTS

= "http://localhost:8080/Sprinter/resources/sprints";

private final static String HOME = "index";

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

537

Client – Vorbereitung (2/2)

• eine Variable pro Eigenschaft mit get und setenum Status {BASIC, EDIT;}

private long id;

private String motto;

private Date starttermin;

private Date endtermin;

private int geplanterAufwand;

private Status modus;

private String meldung = ""; // Statusmeldung ohne Voodoo

SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

public SprintController() {

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

538

Client – Initialisierung (1/2)

@PostConstruct

public void init() {

this.modus = Status.BASIC;

this.client = ClientBuilder.newClient();

WebTarget wt = client.target(SPRINTS);

Invocation.Builder buil = wt

.request(MediaType.APPLICATION_JSON);

JsonObject ergebnis = buil.get(JsonObject.class);

JsonArray array = ergebnis.getJsonArray("sprints");

this.sprints = new ArrayList<Map<String, Object>>();

for (JsonValue val : array) {

JsonObject js = (JsonObject) val;

// speichert einen String als Attribut/Wert-Paar

Map<String, Object> werte = new HashMap<String, Object>();

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

539

Client – Initialisierung (2/2)

for (String k : keys) {

werte.put(k, js.get(k));

}

this.sprints.add(werte);

}

this.motto = "";

this.starttermin = null;

this.endtermin = null;

this.geplanterAufwand = 0;

} in älteren Versionen (Übung !), überflüssige " entfernen for (String k : keys) {

Object tmp = js.get(k);

String txt = tmp.toString();

if(txt.startsWith("\"") && txt.endsWith("\"") && txt.length() > 1){

tmp = txt.substring(1, txt.length()-1);

}

werte.put(k, tmp);

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

540

Erfolgloses Löschen möglich

• vom anderen Nutzer gelöscht oder modifiziert

• Idempotent wäre, diesen Fehler zu ignorieren (ist gelöscht)

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

541

Server Action loeschen

@DELETE

@Path("/sprints/{id}")

public JsonObject loeschen(@PathParam("id") long id) {

pers.removeSprint(id);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("status", "geloescht");

return js.build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

542

Client löschen

public String loeschen(Object sid) {

System.out.println("loeschen: " + sid);

WebTarget wb = client.target(SPRINTS + "/" + sid);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.delete(JsonObject.class);

this.meldung = "loeschen erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "loeschen gescheitert: " + e;

}

init();

this.modus = Status.BASIC;

return HOME;

}Komponentenbasierte Software-

Entwicklung

Prof. Dr. Stephan Kleuker

543

Neuer Sprint – Server (1/2)

@POST

@Produces(MediaType.APPLICATION_JSON)

@Consumes(MediaType.APPLICATION_JSON)

@Path("/sprints")

public JsonObject hinzufuegen(JsonObject jo) {

Sprint sprint = new Sprint();

sprint.setMotto(jo.getString("motto"));

sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));

SimpleDateFormat formatter

= new SimpleDateFormat("dd.MM.yyyy");

try {

sprint.setStarttermin(formatter

.parse(jo.getString("starttermin")));

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

544

Neuer Sprint – Server (2/2)

sprint.setEndtermin(formatter

.parse(jo.getString("endtermin")));

} catch (ParseException ex) {

return null;

}

pers.persist(sprint);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("link"

, uriInfo.getAbsolutePathBuilder()

.path(sprint.getId() + "/backlogElemente")

.build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

545

Neuer Sprint – Client Aktion uebernehmen (1/4)

public String uebernehmen() {

// Validerung des Clients muss dieser regeln

if (this.starttermin == null || this.endtermin == null){

this.meldung = "Start- und Endtermin angeben!";

return HOME;

}

if (this.starttermin.compareTo(this.endtermin) > 0){

this.meldung = "Endtermin nicht vor Starttermin";

return HOME;

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

546

Neuer Sprint – Client Aktion uebernehmen (2/4)

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("motto", this.motto)

.add("starttermin", formatter.format(this.starttermin))

.add("endtermin", formatter.format(this.endtermin))

.add("geplanterAufwand", this.geplanterAufwand);

if (this.modus.equals(Status.BASIC)) {

neuerSprint(js);

}

if (this.modus.equals(Status.EDIT)) {

editiereSprint(js);

}

init();

this.modus = Status.BASIC;

return HOME;

}Komponentenbasierte Software-

Entwicklung

Prof. Dr. Stephan Kleuker

547

Neuer Sprint – Client Aktion uebernehmen (3/4)

private void neuerSprint(JsonObjectBuilder js){

WebTarget wb = client.target(SPRINTS);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

Entity entity = Entity.entity(js.build()

, MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.post(entity, JsonObject.class);

this.meldung = "einfuegen erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "einfuegen gescheitert: " + e;

}

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

548

Sprint editieren – Server (1/2)

@PUT

@Produces(MediaType.APPLICATION_JSON)

@Consumes(MediaType.APPLICATION_JSON)

@Path("/sprints/{id}")

public JsonObject aktualisieren( @PathParam("id") long id

, JsonObject jo) {

Sprint sprint = pers.findSprint(id);

sprint.setMotto(jo.getString("motto"));

sprint.setGeplanterAufwand(jo.getInt("geplanterAufwand"));

try {

sprint.setStarttermin(formatter

.parse(jo.getString("starttermin")));

sprint.setEndtermin(formatter

.parse(jo.getString("endtermin")));

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

549

Sprint editieren – Server (2/2)

} catch (ParseException ex) {

return null;

}

pers.merge(sprint);

JsonObjectBuilder js = Json.createObjectBuilder();

js.add("link"

, uriInfo.getAbsolutePathBuilder()

.path("/backlogElemente").build().getPath());

return js.build();

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

550

Editiere Sprint – Client Aktion uebernehmen (4/4)

private void editiereSprint(JsonObjectBuilder js) {

WebTarget wb = client.target(SPRINTS + "/" + this.id);

Invocation.Builder build = wb

.request(MediaType.APPLICATION_JSON);

js.add("id", id);

Entity entity = Entity.entity(js.build()

, MediaType.APPLICATION_JSON);

try {

JsonObject ergebnis = build.put(entity, JsonObject.class);

this.meldung = "aktualisieren erfolgreich: " + ergebnis;

} catch (Exception e) {

this.meldung = "aktualisieren gescheitert: " + e;

}

}

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

551

UriInfo (1/2)

@Path("ana")

@Stateless

public class Analyse {

@Context

private UriInfo uriInfo;

private final static Logger LOGGER = Logger

.getLogger(Analyse.class.getSimpleName());

@GET

@Produces(MediaType.TEXT_PLAIN)

public String getText() {

LOGGER.info("in getText");

LOGGER.info(this.uriInfo.getAbsolutePath().toString());

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

552

UriInfo (2/2)

LOGGER.info(this.uriInfo.getPath());

LOGGER.info(this.uriInfo.getRequestUri().toString());

for (String s:this.uriInfo.getQueryParameters().keySet()){

LOGGER.info(s+ ": "

+ this.uriInfo.getQueryParameters().get(s));

}

return "hai";

}

INFO: in getText

INFO: http://localhost:8080/resources/ana

INFO: /ana

INFO: http://localhost:8080/resources/ana?x=Hai&text=42

INFO: text: [42]

INFO: x: [Hai]

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

553

WADL (1/3)

• Web Application Description Language

• XML-basierte Beschreibung angebotener Dienste

• generell soll HTTP-Befehl OPTIONS genutzt werden, um Übersicht zu erhalten

• Alle möglichen Dienste mit Parametern werden aufgeführt

• Dienstbeschreibungen können aus Annotation generiert werden

• Alternativ kann @OPTIONS-annotierte Methode realisiert werden (z. B. um Ausgabe zu verhindern)

• Bedeutung eher gering, für Werkzeuge basierend auf WADL-Services interessant; erkennen so Aktualisierungen

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

554

WADL (2/3) - Beispielmethode

@GET

@Produces("text/html")

public String getHtml() {

return "<html><body>Hello, World!!</body></html>";

}

<resources base="http://localhost:8080/resources/">

<resource path="helloworld">

<method id="getHtml" name="GET">

<response>

<representation mediaType="text/html"/>

</response>

</method>

...

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

555

WADL (3/3) – Beispiel aus Sprinter

<resources base="http://localhost:8080/Sprinter/resources/">

<resource path="sprints">

<method id="getSprints" name="GET">

<request>

<param xmlns:xs="http://www.w3.org/2001/XMLSchema"

name="von"

style="query" type="xs:int" default="-1"/>

<param xmlns:xs="http://www.w3.org/2001/XMLSchema"

name="bis"

style="query" type="xs:int" default="-1"/>

</request>

<response>

<representation mediaType="application/json"/>

</response>

</method>

<method id="hinzufuegen" name="POST">

<request>

<representation mediaType="application/json"/>

</request>

<response>

<representation mediaType="application/json"/>

</response>

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

556

@FormParam

<form action="http://vfl.de/mitglieder" method="post">

<p>

Vorname: <input type="text" name="vorname"><br>

Nachname: <input type="text" name="nachname"><br>

<input type="submit" value="Send">

</p>

</form>

@Path("/mitglieder")

@Consumes(Mediatype.APPLICATION_FORM_URLENCODED)

public class CustomerResource {

@POST

public void createCustomer(

@FormParam(“vorname") String vorname

, @FormParam(“nachname") String nachname) {

...

}

ermöglicht die Übernahme von Parametern einer POST-Anfrage eines HTML-Formulars

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

557

Response.Status (gibt evtl. passende Exceptions)public enum Status {

OK(200, "OK"), CREATED(201, "Created"),

ACCEPTED(202, "Accepted"),

NO_CONTENT(204, "No Content"),

MOVED_PERMANENTLY(301, "Moved Permanently"),

SEE_OTHER(303, "See Other"),

NOT_MODIFIED(304, "Not Modified"),

TEMPORARY_REDIRECT(307, "Temporary Redirect"),

BAD_REQUEST(400, "Bad Request"),

UNAUTHORIZED(401, "Unauthorized"),

FORBIDDEN(403, "Forbidden"),

NOT_FOUND(404, "Not Found"),

NOT_ACCEPTABLE(406, "Not Acceptable"),

CONFLICT(409, "Conflict"), GONE(410, "Gone"),

PRECONDITION_FAILED(412, "Precondition Failed"),

UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type"),

INTERNAL_SERVER_ERROR(500, "Internal Server Error"),

SERVICE_UNAVAILABLE(503, "Service Unavailable");

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

558

Weiterführend (1/2)

• asynchron@POST

@Asynchronous public void bearbeite(

@Suspended AsyncResponse ar, Daten daten)

• reguläre Ausdrücke in Path, @Path("{id : .+}")

komplexe Auswertungsregeln, was, wenn mehrere Möglichkeiten an Pfaden existieren

• HEAD: nimmt typischerweise erste GET und gibt statt Ergebnis nur Header und Response-Code zurück

• MIME-Types können sehr detailliert sein, generelltype/subtype;name=value;name=value...

@Consumes("application/xml;charset=utf-8")

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

559

Weiterführend (2/2)

• JAX-RS-Annotationen können auch nur in Interfaces ausgelagert werden

• Matrix-Parameter (Attribute) behandelbarhttp://beispiel.spieler.de/vfl;typ=Sturm/2015

• Nutzung von Header-Parametern @HeaderParampublic String get(@HeaderParam("Referrer") String

aufrufer) {

public String get(@Context HttpHeaders headers) {

• Cookie-Nutzung public String get(@CookieParam(“minr") int minr)

• genauere Analyse vom ResponseBuilder.status(.)

• Einbindung von Bean Validation

• …

Komponentenbasierte Software-Entwicklung

Prof. Dr. Stephan Kleuker

560

Literatur

• (Standard-Links sind im Text)

• [Bur14] B. Burke, RESTful Java with JAX-RS 2.0, O‘Reilly, Sebastopol (CA), USA, 2014

• http://www.oracle.com/technetwork/articles/java/jaxrs20-1929352.html

Komponentenbasierte Software-Entwicklung