1. OData Connector

OData

LeanXcale provides a standard OData connector OData that is disabled by default. It can be configured in the On Cloud deployments

LeanXcale implements the version v4.5 of the OData standard implementing the Apache Olingo interfaces.

OData is an standard interface to access and query data. In the following example it is shown how to use it with the Apache Olingo Client dependency for the OData interface. It requires the table CAR created without any data to run. It inserts some rows, access them and modify some of them.

CREATE TABLE CAR (
     CarID INTEGER,
     CarYear INTEGER,
     CarTrade VARCHAR,
     CarNumber VARCHAR,
     PRIMARY KEY (CarID)
)

The source code of an example project can be downloaded from this public repository. It is a maven project with the source code to use it as an example.

This is the pom.xml file importing the olingo client dependency

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.leanxcale</groupId>
  <artifactId>olingo-client-example</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <packaging>jar</packaging>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.olingo</groupId>
      <artifactId>odata-client-core</artifactId>
      <version>4.5.0</version>
    </dependency>
  </dependencies>
</project>

This is the Java source code to insert, get and modify some rows in the CAR table.

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.URI;
import org.apache.olingo.client.api.ODataClient;
import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest;
import org.apache.olingo.client.api.communication.request.cud.UpdateType;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetIteratorRequest;
import org.apache.olingo.client.api.communication.response.ODataDeleteResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
import org.apache.olingo.client.api.communication.response.ODataEntityUpdateResponse;
import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
import org.apache.olingo.client.api.domain.ClientEntity;
import org.apache.olingo.client.api.domain.ClientEntitySet;
import org.apache.olingo.client.api.domain.ClientEntitySetIterator;
import org.apache.olingo.client.api.serialization.ODataDeserializerException;
import org.apache.olingo.client.core.ODataClientFactory;
import org.apache.olingo.commons.api.format.ContentType;

public class Main {

  private static final String SERVICE_URL = "http://localhost:8900/kivi";

  private static final String[] carsToInsert = new String[]{
      "{\"CARID\":1,\"CARYEAR\":1984,\"CARTRADE\":\"Mazda\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":2,\"CARYEAR\":2002,\"CARTRADE\":\"Mazda\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":3,\"CARYEAR\":2022,\"CARTRADE\":\"Mazda\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":4,\"CARYEAR\":1983,\"CARTRADE\":\"Mazda\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":5,\"CARYEAR\":1999,\"CARTRADE\":\"Toyota\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":6,\"CARYEAR\":2008,\"CARTRADE\":\"Toyota\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":7,\"CARYEAR\":2018,\"CARTRADE\":\"Toyota\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":8,\"CARYEAR\":2016,\"CARTRADE\":\"Ferrari\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":9,\"CARYEAR\":2021,\"CARTRADE\":\"Ferrari\",\"CARNUMBER\":\"IX3443\"}",
      "{\"CARID\":10,\"CARYEAR\":2022,\"CARTRADE\":\"Datsun\",\"CARNUMBER\":\"IX3443\"}"};

  private static final String carToUpdate = "{\"CARID\":10,\"CARTRADE\":\"Ferrari\"}";

  /**
     there is a table defined as
     CREATE TABLE CAR (
        CarID INTEGER,
        CarYear INTEGER,
        CarTrade VARCHAR,
        CarNumber VARCHAR,
        PRIMARY KEY (CarID))
   */

  public static void main(String[] args) {

    try {
      ODataClient odataClient = ODataClientFactory.getClient();
      odataClient.getConfiguration().setDefaultPubFormat(ContentType.APPLICATION_JSON);
      final String entitySetName = "Cars";

      //insert some cars
      for (int i = 0; i < 10; i++) {
        ClientEntity loadEntity = loadEntity(odataClient, carsToInsert[i]);
        URI absoluteUriImport = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).build();
        ODataEntityCreateRequest<ClientEntity> requestCreate = odataClient.getCUDRequestFactory().getEntityCreateRequest(absoluteUriImport,
            loadEntity);
        requestCreate.setAccept("application/json");
        ODataEntityCreateResponse<ClientEntity> responseCreate = requestCreate.execute();
        responseCreate.getBody();
        System.out.println("entry loaded " + carsToInsert[i]);
      }

      //read everything from a table
      URI absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).build();
      System.out.println("URI = " + absoluteUri);
      ODataEntitySetIteratorRequest<ClientEntitySet, ClientEntity> request =
          odataClient.getRetrieveRequestFactory().getEntitySetIteratorRequest(absoluteUri);
      request.setAccept("application/json");
      ODataRetrieveResponse<ClientEntitySetIterator<ClientEntitySet, ClientEntity>> response = request.execute();
      ClientEntitySetIterator<ClientEntitySet, ClientEntity> responseIterator = response.getBody();
      while (responseIterator.hasNext()) {
        printResult(responseIterator.next());
      }

      //read entity by key
      Integer keyValue = 1;
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      System.out.println("URI = " + absoluteUri);
      ODataEntityRequest<ClientEntity> entityRequest = odataClient.getRetrieveRequestFactory().getEntityRequest(absoluteUri);
      request.setAccept("application/json");
      ODataRetrieveResponse<ClientEntity> entityResponse = entityRequest.execute();
      ClientEntity clientEntity = entityResponse.getBody();

      printResult(clientEntity);

      //read entities by filter
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).filter("CARTRADE eq 'Ferrari'").build();
      System.out.println("URI = " + absoluteUri);
      request = odataClient.getRetrieveRequestFactory().getEntitySetIteratorRequest(absoluteUri);
      request.setAccept("application/json");
      response = request.execute();
      responseIterator = response.getBody();
      while (responseIterator.hasNext()) {
        printResult(responseIterator.next());
      }

      //read again car10
      keyValue = 10;
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      System.out.println("URI = " + absoluteUri);
      entityRequest = odataClient.getRetrieveRequestFactory().getEntityRequest(absoluteUri);
      request.setAccept("application/json");
      entityResponse = entityRequest.execute();
      clientEntity = entityResponse.getBody();
      printResult(clientEntity);

      //update car10 with patch (it will only update the values in the input clientEntity
      ClientEntity updateEntity = loadEntity(odataClient, carToUpdate);
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      ODataEntityUpdateRequest<ClientEntity> requestUpdate = odataClient.getCUDRequestFactory().getEntityUpdateRequest(absoluteUri,
          UpdateType.PATCH, updateEntity);
      requestUpdate.setAccept("application/json;odata.metadata=minimal");
      ODataEntityUpdateResponse<ClientEntity> responseUpdate = requestUpdate.execute();
      System.out.println("Response code: " + responseUpdate.getStatusCode());

      //read now again car10
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      System.out.println("URI = " + absoluteUri);
      entityRequest = odataClient.getRetrieveRequestFactory().getEntityRequest(absoluteUri);
      request.setAccept("application/json");
      entityResponse = entityRequest.execute();
      clientEntity = entityResponse.getBody();
      printResult(clientEntity);

      //update car10 with PUT (it will upsert the values in the input clientEntity. missing values in the clientEntity will be 'null'
      updateEntity = loadEntity(odataClient, carToUpdate);
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      requestUpdate = odataClient.getCUDRequestFactory().getEntityUpdateRequest(absoluteUri, UpdateType.REPLACE, updateEntity);
      requestUpdate.setAccept("application/json;odata.metadata=minimal");
      responseUpdate = requestUpdate.execute();
      System.out.println("Response code: " + responseUpdate.getStatusCode());

      //read now again car10
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      System.out.println("URI = " + absoluteUri);
      entityRequest = odataClient.getRetrieveRequestFactory().getEntityRequest(absoluteUri);
      request.setAccept("application/json");
      entityResponse = entityRequest.execute();
      clientEntity = entityResponse.getBody();
      printResult(clientEntity);

      //delete now car10
      absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
      ODataDeleteRequest requestDelete = odataClient.getCUDRequestFactory().getDeleteRequest(absoluteUri);
      requestDelete.setAccept("application/json;odata.metadata=minimal");
      ODataDeleteResponse responseDelete = requestDelete.execute();
      System.out.println("Response code: " + responseDelete.getStatusCode());

      //try to read again car10
      try {
        absoluteUri = odataClient.newURIBuilder(SERVICE_URL).appendEntitySetSegment(entitySetName).appendKeySegment(keyValue).build();
        System.out.println("URI = " + absoluteUri);
        entityRequest = odataClient.getRetrieveRequestFactory().getEntityRequest(absoluteUri);
        request.setAccept("application/json");
        entityRequest.execute();
      } catch (Exception ex) {
        System.out.println("car 10 does not exist");
      }
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private static ClientEntity loadEntity(ODataClient odataClient, String json) throws ODataDeserializerException {
    InputStream input = new ByteArrayInputStream(json.getBytes());
    return odataClient.getBinder().getODataEntity(odataClient.getDeserializer(ContentType.APPLICATION_JSON).toEntity(input));
  }

  private static void printResult(ClientEntity clientEntity) {
    clientEntity.getProperties().forEach((t) -> {
      System.out.print(t.getName() + ":");
      System.out.print(t.getValue() + " - ");
    });
    System.out.println();
  }
}

LeanXcale does not yet support arrays for the OData driver.