Úvod do OData s Olingom

1. Úvod

Tento tutoriál nadväzuje na nášho Sprievodcu protokolom OData, kde sme preskúmali základy protokolu OData.

Teraz uvidíme, ako implementovať jednoduchú službu OData pomocou knižnice Apache Olingo.

Táto knižnica poskytuje rámec na vystavenie údajov pomocou protokolu OData, čo umožňuje ľahký prístup založený na štandardoch k informáciám, ktoré by sa inak uzamkli v interných databázach.

2. Čo je Olingo?

Olingo je jednou z „odporúčaných“ implementácií OData dostupných pre prostredie Java - druhým je rámec SDL OData. Spravuje ho nadácia Apache Foundation a skladá sa z troch hlavných modulov:

  • Java V2 - knižnice klientov a serverov podporujúce OData V2
  • Java V4 - serverové knižnice podporujúce OData V4
  • Javascript V4 - Javascript, knižnica iba pre klienta podporujúca OData V4

V tomto článku sa budeme venovať iba serverovým knižniciam V2 Java, ktoré podporujú priamu integráciu s JPA. Výsledná služba podporuje operácie CRUD a ďalšie funkcie protokolu OData vrátane objednávania, stránkovania a filtrovania.

Olingo V4 na druhej strane spracováva iba aspekty protokolu na nižšej úrovni, ako je vyjednávanie typu obsahu a analýza adries URL. To znamená, že budeme na nás, vývojároch, aby sme kódovali všetky dôkladné podrobnosti týkajúce sa vecí, ako je generovanie metadát, generovanie back-endových dotazov na základe parametrov adresy URL atď.

Pokiaľ ide o klientsku knižnicu JavaScript, zatiaľ ju vynechávame, pretože keďže OData je protokol založený na protokole HTTP, na prístup k nej môžeme použiť ktorúkoľvek knižnicu REST.

3. Služba Olingo Java V2

Vytvorme pomocou týchto dvoch jednoduchú službu OData Sada entíts, ktoré sme použili v našom krátkom úvode do samotného protokolu. Olingo V2 je vo svojej podstate iba súborom zdrojov JAX-RS a ako taký potrebujeme poskytnúť potrebnú infraštruktúru, aby sme ju mohli používať. Konkrétne potrebujeme implementáciu JAX-RS a kompatibilný kontajner servletu.

Pre tento príklad rozhodli sme sa použiť Spring Boot - pretože poskytuje rýchly spôsob vytvorenia vhodného prostredia na hosťovanie našich služieb. Použijeme tiež Olingo JPA adaptér, ktorý „hovorí“ priamo s používateľom dodávaným zariadením EntityManager za účelom zhromaždenia všetkých údajov potrebných na vytvorenie údajov OData EntityDataModel.

Aj keď to nie je prísna požiadavka, zahrnutie adaptéra JPA výrazne zjednodušuje vytváranie našich služieb.

Okrem štandardných závislostí Spring Boot musíme pridať pár Olingových pohárov:

 org.apache.olingo olingo-odata2-core 2.0.11 javax.ws.rs javax.ws.rs-api org.apache.olingo olingo-odata2-jpa-processor-core 2.0.11 org.apache.olingo olingo-odata2 -jpa-processor-ref 2.0.11 org.eclipse.persistence eclipselink 

Najnovšia verzia týchto knižníc je k dispozícii v centrálnom úložisku Maven:

  • olingo-odata2-jadro
  • olingo-odata2-jpa-procesor-jadro
  • olingo-odata2-jpa-processor-ref

Tieto vylúčenia v tomto zozname potrebujeme, pretože Olingo má závislosti na EclipseLink ako svojom poskytovateľovi JPA a tiež používa inú verziu JAX-RS ako Spring Boot.

3.1. Triedy domén

Prvým krokom k implementácii služby OData založenej na JPA s Olingom je vytvorenie našich doménových entít. V tomto jednoduchom príklade vytvoríme iba dve triedy - Výrobca automobilov a CarModel - s jedným vzťahom medzi mnohými:

@Entity @Table (name = "car_maker") verejná trieda CarMaker {@Id @GeneratedValue (strategy = GenerationType.IDENTITY) private Long id; @NotNull súkromné ​​meno reťazca; @OneToMany (mappedBy = "výrobca", orphanRemoval = true, cascade = CascadeType.ALL) súkromné ​​zoznamové modely; // ... vynecháva sa getter, setter a hashcode} @Entity @Table (name = "car_model") verejná trieda CarModel {@Id @GeneratedValue (strategy = GenerationType.AUTO) private Long id; @NotNull súkromné ​​meno reťazca; @NotNull súkromné ​​celé číslo rok; @NotNull súkromné ​​reťazce sku; @ManyToOne (voliteľné = false, fetch = FetchType.LAZY) @JoinColumn (name = "maker_fk") súkromný výrobca automobilov; // ... vynechaní getri, nastavovatelia a hashcode}

3.2. ODataJPAServiceFactory Implementácia

Kľúčovým komponentom, ktorý musíme poskytnúť Olingu, aby sme mohli poskytovať údaje z domény JPA, je konkrétna implementácia abstraktnej triedy tzv. ODataJPAServiceFactory. Táto trieda by sa mala rozširovať ODataServiceFactory a funguje ako adaptér medzi JPA a OData. Pomenujeme túto továreň CarsODataJPAServiceFactory, po hlavnej téme pre našu doménu:

@ Komponenta verejnej triedy CarsODataJPAServiceFactory rozširuje ODataJPAServiceFactory {// vynechané ďalšie metódy ... @Override public ODataJPAContext initializeODataJPAContext () vrhá ODataJPARuntimeException {ODataJPAContext ctx = getODataJPAContext (); ODataContext octx = ctx.getODataContext (); HttpServletRequest request = (HttpServletRequest) octx.getParameter (ODataContext.HTTP_SERVLET_REQUEST_OBJECT); EntityManager em = (EntityManager) požiadavka .getAttribute (EntityManagerFilter.EM_REQUEST_ATTRIBUTE); ctx.setEntityManager (em); ctx.setPersistenceUnitName ("predvolené"); ctx.setContainerManaged (true); návrat ctx; }} 

Olingo volá initializeJPAContext () metóda, ak táto trieda získať nové ODataJPAContext slúži na vybavenie každej požiadavky OData. Tu používame getODataJPAContext () metóda zo základnej triedy, aby sme dostali „obyčajnú“ inštanciu, ktorú potom upravíme.

Tento proces je trochu komplikovaný, takže nakreslíme sekvenciu UML, aby sme vizualizovali, ako sa to všetko deje:

Upozorňujeme, že používame zámerne setEntityManager () namiesto setEntityManagerFactory (). Jeden by sme mohli získať od jari, ale ak ho odovzdáme Olingu, bude v rozpore so spôsobom, akým Spring Boot spracováva jeho životný cyklus - najmä pri transakciách.

Z tohto dôvodu sa uchýlime k schváleniu už existujúceho EntityManager napríklad a informovať ho, že jeho životný cyklus je externe riadený. Injekčne EntityManager inštancia pochádza z atribútu dostupného na aktuálnu požiadavku. Neskôr si ukážeme, ako nastaviť tento atribút.

3.3. Registrácia zdrojov v Jersey

Ďalším krokom je registrácia našich ServiceFactory s runtime Olinga a zaregistrujte vstupný bod Olinga s runtime JAX-RS. Urobíme to vo vnútri a ResourceConfig odvodená trieda, kde tiež definujeme cestu OData pre našu službu / odata:

@Component @ApplicationPath ("/ odata") verejná trieda JerseyConfig rozširuje ResourceConfig {public JerseyConfig (CarsODataJPAServiceFactory serviceFactory, EntityManagerFactory emf) {ODataApplication app = new ODataApplication (); app .getClasses () .forEach (c -> {if (! ODataRootLocator.class.isAssignableFrom (c)) {register (c);}}); register (nový CarsRootLocator (serviceFactory)); register (nový EntityManagerFilter (emf)); } // ... vynechané ďalšie metódy}

Olingo je k dispozícii ODataApplication je bežný JAX-RS Aplikácia trieda, ktorá zaregistruje niekoľko poskytovateľov pomocou štandardného spätného volania getClasses ().

Môžeme použiť všetky okrem ODataRootLocator trieda taká, aká je. Tento konkrétny je zodpovedný za vytvorenie inštancie našej ODataJPAServiceFactory implementácia pomocou Javy newInstance () metóda. Ale keďže chceme, aby to Spring spravovala za nás, musíme ho nahradiť vlastným lokátorom.

Tento lokátor je veľmi jednoduchý prostriedok JAX-RS, ktorý rozširuje skladové zásoby spoločnosti Olingo ODataRootLocator a vracia nám to našu jarnú správu ServiceFactory v prípade potreby:

@Path ("/") verejná trieda CarsRootLocator rozširuje ODataRootLocator {private CarsODataJPAServiceFactory serviceFactory; public CarsRootLocator (CarsODataJPAServiceFactory serviceFactory) {this.serviceFactory = serviceFactory; } @Override public ODataServiceFactory getServiceFactory () {return this.serviceFactory; }} 

3.4. EntityManager Filtrovať

Posledný zostávajúci kus pre našu službu OData EntityManagerFilter. Tento filter vstrekuje EntityManager v aktuálnej žiadosti, takže je k dispozícii pre ServiceFactory. Je to jednoduchý JAX-RS @ Poskytovateľ trieda, ktorá implementuje oboje ContainerRequestFilter a ContainerResponseFilter rozhrania, aby mohla správne spracovávať transakcie:

@Provider verejná statická trieda EntityManagerFilter implementuje ContainerRequestFilter, ContainerResponseFilter {public static final String EM_REQUEST_ATTRIBUTE = EntityManagerFilter.class.getName () + "_ENTITY_MANAGER"; súkromná konečná EntityManagerFactory emf; @Context private HttpServletRequest httpRequest; public EntityManagerFilter (EntityManagerFactory emf) {this.emf = emf; } @Override filter public void (ContainerRequestContext ctx) hodí IOException {EntityManager em = this.emf.createEntityManager (); httpRequest.setAttribute (EM_REQUEST_ATTRIBUTE, em); if (! "GET" .equalsIgnoreCase (ctx.getMethod ())) {em.getTransaction (). begin (); }} @Override public void filter (ContainerRequestContext requestContext, ContainerResponseContext responseContext) hodí IOException {EntityManager em = (EntityManager) httpRequest.getAttribute (EM_REQUEST_ATTRIBUTE); if (! "GET" .equalsIgnoreCase (requestContext.getMethod ())) {EntityTransaction t = em.getTransaction (); if (t.isActive () &&! t.getRollbackOnly ()) {t.commit (); }} em.close (); }} 

Prvý filter () metóda, volaná na začiatku požiadavky na zdroj, používa poskytnuté EntityManagerFactory vytvoriť nový EntityManager inštancia, ktorá sa potom umiestni pod atribút, aby ju neskôr mohol server Windows obnoviť ServiceFactory. Preskakujeme aj žiadosti GET, pretože by nemali mať žiadne vedľajšie účinky, takže nebudeme potrebovať transakciu.

Druhy filter () metóda sa volá po tom, čo Olingo dokončí spracovanie požiadavky. Tu tiež kontrolujeme metódu požiadavky a v prípade potreby vykonáme transakciu.

3.5. Testovanie

Vyskúšajme našu implementáciu pomocou jednoduchého zvlnenie príkazy. Prvé, čo môžeme urobiť, je získať služby $ metadáta dokument:

zvlnenie // localhost: 8080 / odata / $ metadáta

Podľa očakávania dokument obsahuje dva typy - Výrobca automobilov a CarModel - a združenie. Poďme sa teraz trochu pohrať s našou službou a načítať zbierky a entity najvyššej úrovne:

curl // localhost: 8080 / odata / CarMakers curl // localhost: 8080 / odata / CarModels curl // localhost: 8080 / odata / CarMakers (1) curl // localhost: 8080 / odata / CarModels (1) curl // localhost : 8080 / odata / CarModels (1) / CarMakerDetails 

Teraz otestujme jednoduchý dotaz, ktorý vráti všetky Výrobcovia automobilov kde jeho názov začína „B“:

curl // localhost: 8080 / odata / CarMakers? $ filter = startswith (názov, 'B') 

Úplnejší zoznam príkladov adries URL je k dispozícii v našom článku Sprievodca protokolom OData.

5. Záver

V tomto článku sme videli, ako vytvoriť jednoduchú službu OData podporovanú doménou JPA pomocou Olingo V2.

V čase písania tohto článku existuje otvorený problém so sledovaním prác JIRA spoločnosti Olingo na module JPA pre V4, ale posledný komentár sa datuje k roku 2016. V repozitári GitHub spoločnosti SAP je tiež otvorený adaptér JPA tretej strany, ktorý, aj keď nevydaný, zdá sa, že je v tomto okamihu kompletnejší ako Olingo.

Ako obvykle je všetok kód tohto článku k dispozícii na GitHub.


$config[zx-auto] not found$config[zx-overlay] not found