Programmering

REST for Java-udviklere, del 2: Restlet for de trætte

Open source Restlet API reducerer den arbejdsbyrde, der er involveret i at opbygge og forbruge RESTful API'er i Java. I denne anden artikel i REST til Java-udviklere -serien introducerer Brian Sletten dig til Restlet og gennemgår et eksempel på en applikation, hvor han bruger sine grænseflader til de servletcontainere, du bruger i dag, samtidig med at vi forbereder os på fremtidens systemer. Brian introducerer også kort JSR 311: JAX-RS, Suns indsats for at integrere RESTful API'er med Java EE-stakken.

Java-udviklere har længe været interesseret i REST-arkitektoniske stil, men få har endnu rejst afstanden mellem den velkendte verden af ​​objekter og den RESTfulde verden af ​​ressourcer. Selvom vi måske kan lide det faktum, at RESTful-tjenester kan produceres eller forbruges af andre sprog, hader vi at skulle konvertere data til og fra byte-streams. Vi hader at skulle tænke på HTTP, når vi bruger værktøjer som Apache HTTP Client. Vi ser længseligt på objekter skabt af wsdl2java kommando, som lader os sende argumenter ind i en SOAP-tjeneste lige så let som enhver anden metodeopkald, feje detaljerne ved at påkalde en fjerntjeneste under tæppet. Og vi finder ud af, at servletmodellen bare er lidt for afbrudt fra de ressourcer, der produceres. Det er tilstrækkeligt at sige det, mens vi har været i stand at bygge RESTful services fra bunden, har det ikke været en behagelig oplevelse.

REST til Java-udviklere

Læs serien:

  • Del 1: Det handler om oplysningerne
  • Del 2: Restlet for trætte
  • Del 3: NetKernel

Politiske spørgsmål har undertiden forværret de tekniske forhindringer. Mange ledere føler, at SOAP-baserede webtjenester er den foreskrevne måde at opbygge serviceorienterede arkitekturer (SOA'er) i Java EE på. Dette ændrer sig med fremkomsten af ​​vigtige aktiviteter som JSR 311, JAX-RS: Java API til RESTful Web Services, som du lærer om i denne artikel. Hvis ikke andet, legitimerer denne indsats RESTful udvikling i JEE-rummet.

I mellemtiden er der kommet hjælp. På elegant måde gør open source Restlet-rammen det let at undgå de vanskelige problemer, der kan opstå ved at bruge traditionel JEE-teknologi til at opbygge og forbruge RESTful-tjenester.

Restlets rødder

I et forsøg på at løse nogle af de tekniske problemer, der er involveret i at gøre REST med Java, forsøgte Jérome Louvel, en fransk softwarekonsulent, at skabe en ramme, der ville give en mere naturlig pasform. Han så først på NetKernel-miljøet som udgangspunkt. Så meget som han kunne lide det, passede det ikke perfekt til den API-fokuserede ramme, han søgte at stille til rådighed. Oplevelsen var med til at påvirke hans tænkning om de slags ting, som et REST-orienteret miljø kan tilbyde. (Den næste artikel i denne serie vil udforske NetKernel mere detaljeret.)

Da Louvel arbejdede med sine rammer, udviklede han tre mål:

  • Enkle handlinger skal være enkle til grundlæggende brug. Standardindstillingerne skal fungere med minimal indsats, men også give mulighed for mere komplekse konfigurationer.
  • Kode skrevet til denne API skal være bærbar på tværs af containere. Selvom servletbaserede systemer kan flyttes mellem containere som Tomcat, Jetty og IBM WebSphere, havde Louvel et større billede i tankerne. Servlet-specifikationen er bundet til HTTP og en blokerende I / O-model. Han ønskede, at hans API skulle kunne adskilles fra begge disse og kunne indsættes i de containere, der er i brug i dag. Han ønskede også, at de skulle være anvendelige med ringe anstrengelse i alternative og nye containere som Grizzly, AsyncWeb og Simple Framework.
  • Det skal ikke kun berige serversiden ved at producere RESTful-grænseflader i Java, men også klientsiden. Det HttpURLforbindelse klasse og Apache HTTP-klient er for lavt til at integrere rent og direkte i de fleste applikationer.

Med disse mål i tankerne satte han sig for at producere Restlet API. Efter et par år i flux blev API'en stabil, og et samfund voksede omkring det. I dag har API-kernen en levende brugerbase, og der er en betydelig aktivitet i gang for at understøtte integration med andre værktøjssæt og initiativer såsom JAX-RS. (Louvel er nu med i JAX-RS-ekspertgruppen.)

Grundlæggende om restlet

En basisserver med Restlet API kunne muligvis ikke være nemmere, som vist i liste 1.

Notering 1. En basisserver med Restlet

pakke net.bosatsu.restlet.basic; import org.restlet.Restlet; import org.restlet.Server; import org.restlet.data.MediaType; import org.restlet.data.Protocol; import org.restlet.data.Request; import org.restlet.data.Response; offentlig klasse SimpleServer {public static void main (String [] args) throw Exception {Restlet restlet = new Restlet () {@Override public void handle (Request request, Response response) {response.setEntity ("Hello, Java RESTafarians!", MediaType.TEXT_PLAIN); }}; // Undgå konflikter med andre Java-containere, der lytter på 8080! ny server (Protocol.HTTP, 8182, restlet) .start (); }}

Denne applikation gør ikke meget (undtagen spread good cheer), men den viser to af Restlets grundlæggende principper. For det første er enkle ting enkle. Mere komplekse aktiviteter er bestemt mulige, men du bekymrer dig kun om dem, når du har brug for det. REST mangler ikke evnen til at håndhæve sikkerhed, begrænsninger, indholdsforhandling eller andre vigtige opgaver. Disse forbliver stort set ortogonale aktiviteter, meget forskellige fra processen med at tilfredsstille en RESTful API. Du lægger kompleksiteten på efter behov.

For det andet er koden i liste 1 designet til at være bærbar blandt containertyper. Bemærk, at den ikke angiver en container. Restlets er de faktiske ressourcer, der i sidste ende svarer på anmodningerne. Der skelnes ikke mellem containeren, der håndterer anmodningen, og informationsressourcensvareren, som det kan være i servletmodellen. Hvis du skriver koden i en IDE og tilføjer afhængigheder af org.restlet.jar og com.noelios.restlet.jar arkiver, du kan køre applikationen og skulle se en logmeddelelse som denne:

7. december 2008 23:37:32 com.noelios.restlet.http.StreamServerHelper start INFO: Start af den interne HTTP-server

Ret en browser til // localhost: 8182, og du skal se den venlige hilsen.

Bag kulisserne er den org.restlet.jar indeholder alle de vigtigste grænseflader til denne API. Det com.noelios.restlet.jar indeholder en grundlæggende implementering af disse grænseflader og giver en standard HTTP-håndteringsfunktion. Du ønsker ikke at gå i produktion med denne HTTP-motor, men det er usædvanligt praktisk til udviklings- og testformål. Du behøver ikke starte en større container for at teste din RESTful-kode. Enheds- og integrationstest kan være meget lettere som et resultat.

Prøven i liste 1 bruger en masse standardadfærd til at oprette en standard Ansøgning eksempel (jeg vil diskutere Ansøgning i det næste eksempel) og lyt til HTTP-protokolanmodninger på port 8182. Den StreamServerHelper klassen begynder at lytte på denne port og sender anmodninger til Restlet eksempel når de kommer ind.

Louvels mål om at understøtte klientsiden RESTful Java opfyldes også med lethed, som du kan se i Listing 2.

Notering 2. En Restlet-klient

pakke net.bosatsu.restlet.basic; importere java.io.IOException; import org.restlet.Client; import org.restlet.data.Protocol; offentlig klasse SimpleClient {offentlig statisk tomrum hoved (String [] args) kaster IOException {String uri = (args.length> 0)? args [0]: "// localhost: 8182"; Klientklient = ny klient (Protocol.HTTP); client.get (uri) .getEntity (). skriv (System.out); }}

Med SimpleServer stadig kører, skal lanceringen af ​​denne nye klientkode med de samme JAR-afhængigheder udskrive den venlige hilsen til konsollen. Udskrivning af output i denne stil fungerer naturligvis ikke for binærorienterede MIME-typer, men igen er det et praktisk udgangspunkt.

Ikke-CRUD eksempel

De fleste pædagogiske REST-eksempler viser CRUDish-tjenester (Opret, Hent, Opdater, Slet) omkring enkle objekter. Selvom denne stil helt sikkert fungerer godt med REST, er det på ingen måde den eneste tilgang, der giver mening - og de fleste af os er alligevel trætte af CRUD-eksempler. Det følgende eksempel viser det grundlæggende i en Restlet-applikation ved at indpakke stavekontrollen Jazzy open source.

REST handler om at styre information og ikke påberåbe sig vilkårlig adfærd, så du skal være forsigtig, når du overvejer en adfærdsorienteret API som Jazzy. Tricket er at behandle RESTful API som et informationsrum for ord, der findes og ikke findes inden for de ordbøger, der er i brug. Problemet kunne løses på en række måder, men denne artikel definerer to informationsrum. /ordbog bruges til at styre ord i ordbogen. /stavekontrol bruges til at finde forslag til ord, der ligner forkert stavede ord. Begge fokuserer på information ved at overveje fravær eller tilstedeværelse af ord i informationsrummene.

I en RESTful arkitektur kunne denne HTTP-kommando returnere en definition af et ord i ordbogen:

GET // localhost: 8182 / ordbog /ord

Det vil sandsynligvis returnere HTTP-svarskoden "Ikke fundet" for ord, der ikke er i ordbogen. I dette informationsrum er det fint at angive, at ord ikke findes. Jazzy giver ikke definitioner på ord, så jeg efterlader at returnere noget indhold som en øvelse for læseren.

Denne næste HTTP-kommando skal tilføje et ord til ordbogen:

PUT // localhost: 8182 / ordbog /ord

Dette eksempel bruger SÆTTE fordi du kan finde ud af, hvad URI i /ordbog informationsrummet skal være på forhånd og udstede flere SÆTTEs bør ikke gøre en forskel. (SÆTTE er en idempotent anmodning, ligesom . At udstede den samme kommando flere gange bør ikke gøre en forskel.) Hvis du vil tilføje definitioner, kan du sende dem ind som kroppe til SÆTTE handler. Hvis du vil acceptere flere definitioner over tid, vil du måske STOLPE disse definitioner i, fordi SÆTTE er en overskrivningsoperation.

Overse ikke synkronisering

For at holde eksemplerne fokuserede lægger denne artikel ikke særlig vægt på synkroniseringsproblemer. Behandl ikke din produktionskode så nonchalant! Konsulter en ressource som f.eks Java-samtidighed i praksis for mere information.

Det Restlet tilfælde, som jeg opretter, skal være bundet til de relevante informationsrum som vist i liste 3.

Listing 3. En simpel RESTful stavekontrol

pakke net.bosatsu.restlet.spell; import com.swabunga.spell.event.SpellChecker; import com.swabunga.spell.engine.GenericSpellDictionary; import com.swabunga.spell.engine.SpellDictionary; import java.io.File; import java.io.FileNotFoundException; importere java.io.IOException; import org.restlet.data.Protocol; import org.restlet. *; public class SpellCheckingServer udvider Application {public static String dictionary = "Restlet / dict / english.0"; offentlig statisk SpellDictionary stavningDict; offentlig statisk stavekontrol stavekontrol; offentlig statisk Restlet staveCheckerRestlet; offentlig statisk Restlet-ordbogRestlet; statisk {prøv {spellingDict = ny GenericSpellDictionary (ny fil (ordbog)); stavekontrol = ny stavekontrol (stavningsdikt); spellCheckerRestlet = ny SpellCheckerRestlet (stavekontrol); dictionaryRestlet = ny DictionaryRestlet (stavekontrol); } fange (Undtagelse e) {e.printStackTrace (); }} offentlig statisk ugyldig hoved (String [] args) kaster Undtagelse {Component component = new Component (); component.getServers (). tilføj (Protocol.HTTP, 8182); SpellCheckingServer spellingService = ny StaveCheckingServer (); component.getDefaultHost (). vedhæft ("", stavningsservice); component.start (); } offentlig Restlet createRoot () {Router router = ny Router (getContext ()); router.attach ("/ stavekontrol / {word}", stavekontrolRestlet); router.attach ("/ ordbog / {ord}", ordbogRestlet); retur router; }}

Efter at den har opbygget ordbogens forekomst og stavekontrollen, er Restlet-opsætningen i Listing 3 lidt mere kompliceret end i det tidligere grundlæggende eksempel (men ikke meget!). Det StavekontrolServer er en forekomst af en Restlet Ansøgning. En Ansøgning er en organisationsklasse, der koordinerer implementering af funktionelt forbundet Restlet tilfælde. Det omkringliggende Komponent spørger en Ansøgning for dens rod Restlet ved at ringe til createRoot () metode. Roden Restlet returneret angiver, hvem der skal svare på de eksterne anmodninger. I dette eksempel kaldes en klasse Router bruges til at sende til de underordnede informationsrum. Ud over at udføre denne kontekstbinding opretter det et URL-mønster, der gør det muligt for "ord" -delen af ​​URL'en at være tilgængelig som attribut på anmodningen. Dette vil blive udnyttet i Restlets oprettet i liste 4 og 5.

Det DictionaryRestlet, vist i liste 4, er ansvarlig for håndtering af anmodninger om manipulation af /ordbog informationsplads.