OData und Apache Olingo in der Praxis

Architektur/Methoden  –  0 Kommentare

Um den OData-Standard in der Praxis einsetzen zu können, sind Bibliotheken wie Apache Olingo nützlich. Sie helfen, Fehler zu vermeiden und bringen mehr Zeit für das Wesentliche – die Applikation.

Im ersten Artikel zu OData wurden dessen Theorie anhand eines einfachen CRUD-Szenarios dargestellt und die Vorteile bei der Verwendung von System Query Options beschrieben, die einen wesentlichen Teil von OData ausmachen. In der Praxis bietet es sich an, die generischen Teile der OData-Spezifikation für das Realisieren eines OData-Services oder die Kommunikation damit nicht selbst zu implementieren, sondern eine Bibliothek zu verwenden. So bleibt Zeit, sich auf die Daten und Logik der eigentlichen Anwendung zu konzentrieren.

Im Java-Umfeld bietet sich das Projekt Apache Olingo an, das sowohl Unterstützung beim Erstellen eines OData-Service als auch beim Datenaustausch damit bietet. Insbesondere gibt es Erweiterungspunkte, um Requests aufzubereiten (URI parsen, Daten konvertieren) und Responses bereitzustellen. Das Projekt stellt Funktionen bereit, um Entitäten nach OData-Spezifikation zu serialisieren und zu deserialisieren. Mit Erweiterungspunkten und Funktionen lassen sich sowohl OData-Services als auch -Clients umsetzen.

Mit einfachen Mitteln zum Erfolg

Um das volle Potenzial von OData in Verbindung mit Apache Olingo auszuschöpfen, wird die abstrakte Klasse ODataSingleProcessor verwendet. Eine Applikation kann sie als Superklasse verwenden und muss dann die Methoden überschreiben, die der angebotene Service anbieten will. Eine Anwendung, die nur einen lesenden Zugriff auf Daten im OData-Format bereitstellen will, muss etwa die readEntity(...) und readEntitySet(...) überschreiben und entsprechend implementieren. Erst für speziellere Lese- (beispielsweise auf Media-Ressourcen) oder Schreibzugriffe sind weitere Methoden zu ersetzen und zu implementieren.

Anhand des readEntity(...) sei kurz demonstriert, wie Apache Olingo die Implementierung des Funktionsumfangs von OData unterstützt. Die Methode ODataResponse readEntity(final GetEntityUriInfo uriInfo, final String contentType) wird mit den aufbereiteten URI-Informationen (GetEntityUriInfo-Objekt) und dem mitgeschickten "Accept Header"-Wert aufgerufen. Als Rückgabewert ist ein ODataResponse-Objekt vorgesehen, das unter anderem den HTTP Response Body und HTTP Header enthält.

Das GetEntityUriInfo-Objekt umfasst sowohl das EntitySet als auch die Key-Werte der referenzierten Entity. Mit den Informationen könnte man bereits Daten aus beispielsweise einer Datenbank auslesen.

// Referenziertes EntitySet
EdmEntitySet entitySet = uriInfo.getStartEntitySet();
// Key Wert der referenzierten Entity
KeyPredicate key =
uriInfo.getKeyPredicates().get(0);
// hier mit dem Wissen, dass es nur einen Key Wert gibt
String id = key.getLiteral();
Map<String, Object> data = dataStore.getCar(id);

Mit den Daten in Form einer Map lässt sich dann die EntityProvider-Klasse verwenden, um eine ODataResponse zu erzeugen.

URI serviceRoot = getContext().getPathInfo().getServiceRoot();
ODataEntityProviderPropertiesBuilder propertiesBuilder =
EntityProviderWriteProperties.serviceRoot(serviceRoot);

ODataResponse response = EntityProvider.writeEntry(contentType,
entitySet, data, propertiesBuilder.build());
return response;

Die hier verwendete Methode getContext() stellt der ODataSingleProcessor bereit. Darüber lässt sich das ODataContext-Objekt holen, das noch weitere Informationen enthält.

Wie man sieht, bedarf es für einen einfachen Lesezugriff wenig Aufwand. Zudem hat man durch die Objekte GetEntityUriInfo und ODataContext Zugriff auf alle wichtigen Informationen des Request. Für die Response kann man seine Daten einfach serialisieren lassen und hat danach durch das entsprechende ODataResponse-Objekt die Möglichkeit, das Ergebnis vor dem Senden noch anzupassen.

Für weitere Anwendungsfälle sei auf die Tutorials in der Olingo-Dokumentation verwiesen. Insbesondere bietet sich als Einstieg das "Basic Read Tutorial" an, das die ersten Schritte detailliert aufzeigt und auf die nächsten, passenden Tutorials verweist.

Um nicht nur einfach, sondern auch wirklich schnell einen OData-Service zu realisieren, bietet Apache Olingo derzeit zwei Erweiterungen an, die den zuvor gezeigten ODataSingleProcessor ergänzen. Beide stellen dabei einen vollständigen OData-Service bereit, der das definierte Modell als OData-Entitäten bietet und CRUD-Szenarien in Verbindung mit System Query Options unterstützt.

Die Erweiterung im jpa-processor-Modul ermöglicht es, das Modell aus mit der JPA (Java Persistence API) annotierten Klassen erstellen zu lassen und die Daten direkt aus einer darüber eingebundenen Datenquelle bereitzustellen. Im Modul annotations-processor ermöglicht eine Erweiterung, das Modell aus POJOs (Plain Old Java Objects) zu erstellen, die mit Annotationen (aus dem Paket org.apache.olingo.odata2.api.annotation.edm) versehen wurden. Die Daten sind dabei aktuell nur im Speicher vorhanden. In einer zukünftigen Feature-Erweiterung werden hier zusätzliche Möglichkeiten geschaffen, um die Daten auch anderweitig zu verwalten (siehe Feature Request "OLINGO-129").