diff --git a/simpleexample2/fxui/src/main/java/simpleex/ui/README.md b/simpleexample2/fxui/src/main/java/simpleex/ui/README.md index 5bea24d88df8862fe2502f303b239e07c57e7c4c..786c577ee8935da2cc8883f130410a0ddd91aef5 100644 --- a/simpleexample2/fxui/src/main/java/simpleex/ui/README.md +++ b/simpleexample2/fxui/src/main/java/simpleex/ui/README.md @@ -6,11 +6,17 @@ Brukergrensesnittet er enkelt og består av en liste og et kart. Lista viser inn Kartet implementeres av ([FxMapControl](https://github.com/ClemensFischer/FX-Map-Control), og siden biblioteket ikke er tilgjengelig i et sentral repository, så har vi bygget og lagt ved jar-filen. -I tillegg kan en lagre og lese inn **LatLongs**-objektet fra **Open...**- og **Save...**-aksjoner i en **File**-meny. +## Arkitektur + +Arkitekturen er som de fleste JavaFX-apper som bruker FXML, vi har en oppstartsklasse (**FxApp**) som arver fra **Application** og som stort sett bare laster inn og viser frem (innholdet i) en FXML-fil. FXML-fila angir en kontroller-klasse (med **fx:controller**-attributtet i rot-elementet) hvor UI-logikken ligger. + +Det finnes to varianter av applikasjonen, én som bruker lokale data lagret på fil og én som bruker sentrale data håndtert gjennom et REST-API på en server. Derfor har vi også to FXML-filer (**FxApp.fxml** og **FxAppUsingRest.fxml**) og to tilhørende kontroller-klasser (**FxAppController** og **FxAppUsingRestController**). For å gjøre det enklere å ha en del felles kode i en abstrakt kontroller-klasse (**AbstractFxAppController**), så er datatilgangen skilt ut i egne klasser (**LocalLatLongsDataAccess** og **RestLatLongsDataAccess**) som implementerer et felles **LatLongsDataAccess**-grensesnitt. + +Det er bare én app-klasse (**FxApp**), og denne velger hvilken variant som brukes, basert på om det oppgis en server-URL som kommandolinjeargument. Hvis en f.eks. kjører 'java FxApp http://localhost:8080/' så kjøres varianten som bruker REST-API-et. Det betyr også at serveren må startes. I tillegg til URL-en så kan en også oppgi initielle LatLongs-data kodet som json. Dette gjør det enklere å sjekke at data leses riktig fra REST-API-et ved oppstart. **build.gradle** er rigget slik at begge disse kommandolinjeargumentene oppgis ved kjøring av **Run**-oppgaven. ```plantuml -class FxAppController -class LatLongs +class AbstractFxAppController +class LatLongsDataAccess class BorderPane class "ListView<LatLong>" as ListView class "fxmapcontrol.MapBase" as MapBase @@ -18,7 +24,10 @@ class "fxmapcontrol.MapBase" as MapBase BorderPane *--> ListView: "left" BorderPane *--> MapBase: "center" -FxAppController --> LatLongs: "latLongs" -FxAppController --> MapBase: "mapView" -FxAppController --> ListView: "locationListView" +AbstractFxAppController --> LatLongsDataAccess: "dataAccess" +AbstractFxAppController --> MapBase: "mapView" +AbstractFxAppController --> ListView: "locationListView" + +FxAppController ..|> AbstractFxAppController +FxAppUsingRestController ..|> AbstractFxAppController ``` diff --git a/simpleexample2/fxui/src/test/java/simpleex/ui/README.md b/simpleexample2/fxui/src/test/java/simpleex/ui/README.md index 5244c0323b90835965a84752d6d99fecee2e037c..51d60a59b97d49348d2a77b9c172f7ab36f7d1ed 100644 --- a/simpleexample2/fxui/src/test/java/simpleex/ui/README.md +++ b/simpleexample2/fxui/src/test/java/simpleex/ui/README.md @@ -1 +1,5 @@ # Testkode for brukergrensesnittet + +Denne pakken inneholder testkode for JavaFX-app-en. Koden er ikke så grundig... + +Det mest spesielle er at det finnes to varianter (subklasser av **AbstractFxAppTest**), én for hver variant av app-en, altså med eller uten bruk av REST-API-et. Varianter som bruker REST-API-et (**FxAppUsingRestTest**) starter opp serveren ifm. rigging av datatilgangsobjektet (instans av **LatLongsDataAccess**) og stopper den i nedriggingsfasen. diff --git a/simpleexample2/restapi/README.md b/simpleexample2/restapi/README.md index 71af46e178cacd62831dc56cce7aee82acebb807..814d1ce68147d0da76a726d98aded291897c8642 100644 --- a/simpleexample2/restapi/README.md +++ b/simpleexample2/restapi/README.md @@ -1,7 +1,29 @@ # Modul for REST-api -Dette prosjektet inneholder REST-api for [simpleexample2](../README.md). +Dette modulen inneholder REST-api for [simpleexample2](../README.md). ## REST-api-et -## Bygging med gradle +Et REST-API er på en måte et objekt (eller sett med objekter) som leses og/eller kalles ved å bruke HTTP-forespørsler (HTTP-URL-er). Mottak av forespørslen håndteres av en HTTP-server, og så "omformes" forespørslen til et kall på en tilhørende metode i et "REST-tjeneste"-objekt. + +Denne modulen inneholder bare logikken til "REST-tjeneste"-objektet (**LatLongsService**), mens oppsettet av serveren ligger i [restserver-modulen](../restserver/README.md). En slik oppdeling gjør løsningen ryddigere (selv om det øker antall moduler). + +REST-API-et vårt er programmert iht. [JAX-RS-standarden](https://en.wikipedia.org/wiki/Java_API_for_RESTful_Web_Services), som lar en angi koblingen mellom HTTP og metodene på REST-tjeneste-objektet vha. Java-annotasjoner. F.eks. angir @Path-annotasjonen på **LatLongsService**-klassen at vår tjeneste er knyttet til **latLongs**-prefikset. Altså vil vår tjeneste aktiveres ved å angi **latLongs** først i stien til URL-en (men bak stien til serveren). Anta f.eks. at stien til serveren er "http://min-server:8080/". Da vil stien til vår tjeneste være "http://min-server:8080/latLongs". + +Som nevnt er JAX-RS *annotasjonsdrevet*. Det betyr at Java-annotasjoner ved hver metode angir detaljer ved forespørslen som trigger metoden. F.eks. vil en metode annotert med **@GET** bare kalles når HTTP-metoden er "GET". En kan bruke **@Path** for å angi et påkrevd sti-segment og **@PathParam** for å bruke dette sti-segmentet som argument til metoden. + +Hvis metoden bruker ekstra data sendt i tillegg til URL-en, så angis formatet med **@Consumes**-annotasjonen. Tilsvarende angis kodingen av resultatet med **@Produces**-annotasjonen. Vi bruker json-kodete data, så derfor bruker vi **MediaType.APPLICATION_JSON** (konstant for "application/json") som argument for begge disse. + +Vårt REST-API gir tilgang til *ett* **LatLongs**-objekt og tilbyr fem metoder: + +* lese innholdet (alle **LatLong**-objektene) - GET til **tjeneste-URL** +* lese innholdet til et spesifikt **LatLong**-element (angitt med posisjonen **num**) - GET (**@GET**) til **tjeneste-URL/num** (**@Path** og **@PathParam**) +* legge til LatLongs-objekter i spesifikk posisjon - POST (**@POST**) av json-kodet LatLong-array til **tjeneste-URL/num** (**@Path** og **@PathParam**) +* endre LatLong-objekt i spesifikk posisjon - PUT (**@PUT**) av json-kodet LatLong-objekt til **tjeneste-URL/num** (**@Path** og **@PathParam**) +* fjerne LatLong-objekt i spesifikk posisjon - DELETE (**@DELETE**) til **tjeneste-URL/num** (**@Path** og **@PathParam**) + +Merk at navnet på implementasjonsmetoden i **LatLongsService**-klassen ikke spiller noen rolle, det er annotasjonene som er viktige. + +## JSON-koding av data + +Når vi bruker **@Consumes** og **@Produces** med **MediaType.APPLICATION_JSON** som argument, så må vi også konfigurere tjenesten slik at kodingen av json-data bruker vår logikk, altså den som er programmert i [**core**-modulen](../core/README.md). Dette gjøres i **LatLongObjectMapperProvider**-klassen. Det er ikke så mye å si om den klassen, annet enn at den bruker **LatLongsModule**-klassen fra core-modulen.