Sunday, 21 July 2019

Apache olingo: HelloWorld application


Follow below step-by-step procedure to create simple OData hello world application.

Step 1: Create new maven project in Eclipse.

Open Eclipse. Right click on project Explorer -> New -> Other


It opens ‘select a wizard’ window. Search for ‘maven’ and select ‘maven project’. Click on next button.


Click on Next button.

Click on Next button.

Select the artifact ‘maven-archetype-webapp’ and click on Next button.

Give group id and artifact id as ‘olingoDemo’ and set the version to 1.

Click on Finish button.


Project structure is created like below.

As you see, java folder is not created under src/main folder. You can create it explicitly. After creating java folder under src/main, project structure looks like below.

As you see, java folder is not created under src/main folder. You can create it explicitly. After creating java folder under src/main, project structure looks like below.

Step 2: Open pom.xml and update maven dependencies.

pom.xml
<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/maven-v4_0_0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>olingoDemo</groupId>
 <artifactId>olingoDemo</artifactId>
 <packaging>war</packaging>
 <version>1</version>
 <name>olingoDemo Maven Webapp</name>
 <url>http://maven.apache.org</url>
 <properties>
  <javax.version>2.5</javax.version>
  <odata.version>4.0.0</odata.version>
  <slf4j.version>1.7.7</slf4j.version>
 </properties>

 <dependencies>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>servlet-api</artifactId>
   <version>${javax.version}</version>
   <scope>provided</scope>
  </dependency>

  <dependency>
   <groupId>org.apache.olingo</groupId>
   <artifactId>odata-server-api</artifactId>
   <version>${odata.version}</version>
  </dependency>
  <dependency>
   <groupId>org.apache.olingo</groupId>
   <artifactId>odata-server-core</artifactId>
   <version>${odata.version}</version>
   <scope>runtime</scope>
  </dependency>

  <dependency>
   <groupId>org.apache.olingo</groupId>
   <artifactId>odata-commons-api</artifactId>
   <version>${odata.version}</version>
  </dependency>
  <dependency>
   <groupId>org.apache.olingo</groupId>
   <artifactId>odata-commons-core</artifactId>
   <version>${odata.version}</version>
  </dependency>

  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-simple</artifactId>
   <version>${slf4j.version}</version>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupId>org.slf4j</groupId>
   <artifactId>slf4j-api</artifactId>
   <version>1.7.11</version>
   <scope>compile</scope>
  </dependency>
 </dependencies>

 <build>
  <finalName>olingoDemo</finalName>
 </build>
</project>

Implementing OData Services
To implement OData service, we need to do below things.
a.   Declare metadata of a service
b.   Handle Service requests

Declare the metadata of a service
As per OData specification, OData service has to declare its structure in metadata document. Clients of OData service use this metadata and get to know what are the entities available at this service and which requests can be executed.

How to get the metadata of a document?
<serviceroot>/$metadata

What is service document?
Apart from metadata, OData service can expose a service document.  Client can see the Entity collections that are offered by OData service.

How to get the service document?
<serviceroot>/

Olingl library provide APIs to implement bothe meta data of a document and service document. Our task is to use these APIs and implement these two documents.
We need to extend the class ‘CsdlEdmProvider’ to provide meta and service documents.

Step 1: Create a package ‘com.app.service’ and define the class 'DemoEdmProvider' like below.


DemoEdmProvider.java
package com.app.service;

import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;

/**
 * Class to provide OData services. Edm stands for Entity Data Model.
 * 
 * @author Krishna
 *
 */
public class DemoEdmProvider extends CsdlAbstractEdmProvider{

}


Define DemoEntityCollectionProcessor.java like below.

DemoEntityCollectionProcessor.java
package com.app.service;

import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.uri.UriInfo;

public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {

 public void init(OData odata, ServiceMetadata serviceMetadata) {
  
 }

 public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
   ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
  
 }

}


Step 2: Create a package ‘com.app.servlet’ and define the class DemoServlet.java.

DemoServlet.java
package com.app.servlet;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataHttpHandler;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.edmx.EdmxReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.app.service.DemoEdmProvider;
import com.app.service.DemoEntityCollectionProcessor;

public class DemoServlet extends HttpServlet {

 private static final long serialVersionUID = 1L;
 private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);

 @Override
 protected void service(final HttpServletRequest req, final HttpServletResponse resp)
   throws ServletException, IOException {

  try {
   OData odata = OData.newInstance();
   
   ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
   
   ODataHttpHandler handler = odata.createHandler(edm);
   handler.register(new DemoEntityCollectionProcessor());
   handler.process(req, resp);

  } catch (RuntimeException e) {
   LOG.error("Server Error occurred in ExampleServlet", e);
   throw new ServletException(e);
  }
 }
}


Update web.xml like below.

web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
 <display-name>Archetype Created Web Application</display-name>


 <servlet>
  <servlet-name>DemoServlet</servlet-name>
  <servlet-class>com.app.servlet.DemoServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>DemoServlet</servlet-name>
  <url-pattern>/DemoService.svc/*</url-pattern>
 </servlet-mapping>

</web-app>


As you see web.xml, I am routing all the call that starts with /DemoService.svc/* to DemoServlet. As you see the snippet of DemoServlet, It creates an instance of ODataHttpHandler and gives the request to ODataHttpHandler instance for further processing.

Step 3: Create index.jsp with below content.
index.jsp
<html>
<body>
 <h2>Hello World!</h2>
</body>
</html>


Total project structure looks like below.

Run the application on server.

Hit below url to get metadata.


Since we are not yet implemented the APIs, it returns no information about the entities. You can get the version of OData from the above information.
Hit below url to get service document information.



As you see above image, you end up in internal server error. It is because, we are not yet implemented the service document.

Providing metadata for all OData elements
In our example, we need to provide implementation for below methods in DemoEdmProvider class.

getEntityType() : Here we declare the EntityType “Product” and a few of its properties.

getEntitySet():  Here we state that the list of products can be called via the EntitySet “Products”.

getEntityContainer(): Here we provide a Container element that is necessary to host the EntitySet.

getSchemas(): The Schema is the root element to carry the elements.

getEntityContainerInfo(): Information about the EntityContainer to be displayed in the Service Document
public class DemoEdmProvider extends CsdlAbstractEdmProvider {

 @Override
 public CsdlEntityContainer getEntityContainer() throws ODataException {
  // TODO Auto-generated method stub
  return super.getEntityContainer();
 }

 @Override
 public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
  // TODO Auto-generated method stub
  return super.getEntityContainerInfo(entityContainerName);
 }

 @Override
 public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
  // TODO Auto-generated method stub
  return super.getEntitySet(entityContainer, entitySetName);
 }

 @Override
 public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
  // TODO Auto-generated method stub
  return super.getEntityType(entityTypeName);
 }

 @Override
 public List<CsdlSchema> getSchemas() throws ODataException {
  // TODO Auto-generated method stub
  return super.getSchemas();
 }

}
Before implementing these methods, lets try to understand the technical terms.

Entity: An entity is an instance of entity type (Entity type can be Employee, Product, Customer etc.,)

EntityType: all the entities are created from entity type.

Entity set: Collection of entities. For example, list of products, group of customers etc.,
Association: Defines the relationship between two entity types. For example, Employee worksFor Department.

Association set: Instances of association are grouped in association sets.

Entity Container: It is the container for entity sets and association sets.

If you are from RDBMS, you can map
         Entity Set -> table
         Entity -> Record in a table
         Entity Container -> Database

Let’s provide the implementation one by one.

Implementing getEntityType method
This method is responsible for giving the information about the meta information of an entity. For example, in case of product, it should give what are the properties of product and what is the type of each property.


Below snippet define 4 properties (ID, Name, Description and Price) of the product. Apart from this, it sets the primary key of this entity. A key is combination of multiple properties.
public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
 if (entityTypeName.equals(ET_PRODUCT_FQN)) {

  // create EntityType properties
  CsdlProperty id = new CsdlProperty().setName("ID")
    .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
  CsdlProperty name = new CsdlProperty().setName("Name")
    .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
  CsdlProperty description = new CsdlProperty().setName("Description")
    .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
  CsdlProperty price = new CsdlProperty().setName("Price")
    .setType(EdmPrimitiveTypeKind.Double.getFullQualifiedName());

  // create CsdlPropertyRef for Key element
  CsdlPropertyRef propertyRef = new CsdlPropertyRef();
  propertyRef.setName("ID");

  // configure EntityType
  CsdlEntityType entityType = new CsdlEntityType();
  entityType.setName(ET_PRODUCT_NAME);
  entityType.setProperties(Arrays.asList(id, name, description, price));
  entityType.setKey(Collections.singletonList(propertyRef));

  return entityType;
 }

 return null;
}


Overriding getEntitySet() method
 public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
  if (entityContainer.equals(CONTAINER)) {
   if (entitySetName.equals(ES_PRODUCTS_NAME)) {
    CsdlEntitySet entitySet = new CsdlEntitySet();
    entitySet.setName(ES_PRODUCTS_NAME);
    entitySet.setType(ET_PRODUCT_FQN);

    return entitySet;
   }
  }

  return null;
 }


getEntitySet method return the entityset details, that takes entitysetName and return an entityset, it tell which type of objects are stored in this entity set.

Overriding getEntityContainer() method
As I said, entity container is a collection of entity sets. We need to provides details of all our entity sets information here.
 @Override
 public CsdlEntityContainer getEntityContainer() throws ODataException {
  // create EntitySets
  List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
  entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));

  // create EntityContainer
  CsdlEntityContainer entityContainer = new CsdlEntityContainer();
  entityContainer.setName(CONTAINER_NAME);
  entityContainer.setEntitySets(entitySets);

  return entityContainer;
 }


Overriding getSchemas()
Till now we defined, entity type, entity set and entity container. We need to put all this information into a schema.
 @Override
 public List<CsdlSchema> getSchemas() throws ODataException {
  // create Schema
  CsdlSchema schema = new CsdlSchema();
  schema.setNamespace(NAMESPACE);

  // add EntityTypes
  List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
  entityTypes.add(getEntityType(ET_PRODUCT_FQN));
  schema.setEntityTypes(entityTypes);

  // add EntityContainer
  schema.setEntityContainer(getEntityContainer());

  // finally
  List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
  schemas.add(schema);

  return schemas;
 }


Overriding getEntityContainerInfo() method
Gives information (like container name) about the container.
 @Override
 public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
  // This method is invoked when displaying the Service Document at e.g.
  // http://localhost:8080/DemoService/DemoService.svc
  if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
   CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
   entityContainerInfo.setContainerName(CONTAINER);
   return entityContainerInfo;
  }

  return null;
 }


Let’s see what we did, we defined a class that represents all the below metadata.
a.   Entity type
b.   Entity set
c.    Entity container
d.   Entity container information
e.   Schema

Complete DemoEdmProvider class looks like below.

DemoEdmProvider.java
package com.app.service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.FullQualifiedName;
import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
import org.apache.olingo.commons.api.ex.ODataException;

/**
 * Class to provide OData services. Edm stands for Entity Data Model.
 * 
 * @author Krishna
 *
 */
public class DemoEdmProvider extends CsdlAbstractEdmProvider {
 // Service Namespace
 public static final String NAMESPACE = "OData.Demo";

 // EDM Container
 public static final String CONTAINER_NAME = "Container";
 public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);

 // Entity Types Names
 public static final String ET_PRODUCT_NAME = "Product";
 public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);

 // Entity Set Names
 public static final String ES_PRODUCTS_NAME = "Products";

 @Override
 public CsdlEntityContainer getEntityContainer() throws ODataException {
  // create EntitySets
  List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
  entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));

  // create EntityContainer
  CsdlEntityContainer entityContainer = new CsdlEntityContainer();
  entityContainer.setName(CONTAINER_NAME);
  entityContainer.setEntitySets(entitySets);

  return entityContainer;
 }

 @Override
 public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
  // This method is invoked when displaying the Service Document at e.g.
  // http://localhost:8080/DemoService/DemoService.svc
  if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
   CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
   entityContainerInfo.setContainerName(CONTAINER);
   return entityContainerInfo;
  }

  return null;
 }

 @Override
 public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
  if (entityContainer.equals(CONTAINER)) {
   if (entitySetName.equals(ES_PRODUCTS_NAME)) {
    CsdlEntitySet entitySet = new CsdlEntitySet();
    entitySet.setName(ES_PRODUCTS_NAME);
    entitySet.setType(ET_PRODUCT_FQN);

    return entitySet;
   }
  }

  return null;
 }

 @Override
 public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
  if (entityTypeName.equals(ET_PRODUCT_FQN)) {

   // create EntityType properties
   CsdlProperty id = new CsdlProperty().setName("ID")
     .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
   CsdlProperty name = new CsdlProperty().setName("Name")
     .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
   CsdlProperty description = new CsdlProperty().setName("Description")
     .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
   CsdlProperty price = new CsdlProperty().setName("Price")
     .setType(EdmPrimitiveTypeKind.Double.getFullQualifiedName());

   // create CsdlPropertyRef for Key element
   CsdlPropertyRef propertyRef = new CsdlPropertyRef();
   propertyRef.setName("ID");

   // configure EntityType
   CsdlEntityType entityType = new CsdlEntityType();
   entityType.setName(ET_PRODUCT_NAME);
   entityType.setProperties(Arrays.asList(id, name, description, price));
   entityType.setKey(Collections.singletonList(propertyRef));

   return entityType;
  }

  return null;
 }

 @Override
 public List<CsdlSchema> getSchemas() throws ODataException {
  // create Schema
  CsdlSchema schema = new CsdlSchema();
  schema.setNamespace(NAMESPACE);

  // add EntityTypes
  List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
  entityTypes.add(getEntityType(ET_PRODUCT_FQN));
  schema.setEntityTypes(entityTypes);

  // add EntityContainer
  schema.setEntityContainer(getEntityContainer());

  // finally
  List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
  schemas.add(schema);

  return schemas;
 }

}


Run the application.

Hit the below url, to get the metadata of the OData service.

You can see below information in browser.
<?xml version="1.0" encoding="UTF-8"?>
<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
   <edmx:DataServices>
      <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OData.Demo">
         <EntityType Name="Product">
            <Key>
               <PropertyRef Name="ID" />
            </Key>
            <Property Name="ID" Type="Edm.Int32" />
            <Property Name="Name" Type="Edm.String" />
            <Property Name="Description" Type="Edm.String" />
            <Property Name="Price" Type="Edm.Double" />
         </EntityType>
         <EntityContainer Name="Container">
            <EntitySet Name="Products" EntityType="OData.Demo.Product" />
         </EntityContainer>
      </Schema>
   </edmx:DataServices>
</edmx:Edmx>


As you see the metadata document, you can observe below things.
a.   EntityType element gives the definition of entity
b.   Entity set has a name Products, it specifies the type of elements that this entity set contains.
c.    EntityContainer is a collection of entity sets
d.   EntityContainer and EntityType is embedded in Schema element.

Lets hit the service document ‘http://localhost:8080/olingoDemo/DemoService.svc/’.

You will see below response.
<?xml version="1.0" encoding="UTF-8"?>
<app:service xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:metadata="http://docs.oasis-open.org/odata/ns/metadata" metadata:context="$metadata">
   <app:workspace>
      <atom:title>OData.Demo.Container</atom:title>
      <app:collection href="Products">
         <atom:title>Products</atom:title>
      </app:collection>
   </app:workspace>
</app:service>


As you see, it contains a collection with href value ‘Products’, it tells you will get list of products information by hitting below url.

Let’s hit the above url in browser, you can see internal server error. It is because, we are not yet implementing this service.


Implementing the service to provide the data
DemoEntityCollectionProcessor takes the responsibility to return the content.

We need to provide implementation for two methods.
a.   init
b.   readEntityCollection
public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {

 public void init(OData arg0, ServiceMetadata arg1) {
  // TODO Auto-generated method stub

 }

 public void readEntityCollection(ODataRequest arg0, ODataResponse arg1, UriInfo arg2, ContentType arg3)
   throws ODataApplicationException, ODataLibraryException {
  // TODO Auto-generated method stub

 }

}


Dummy implementation looks like above.

Implementing readEntityCollection method
readEntityCollection method is responsible indelivering the data to the client who calls the get request on OData service.

readEntityCollection signature looks like below.

void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)

request: It contains raw http information. You can use it while creating new data. For example, you can read the post request body using this argument.

response: Used to send the response data.

uriInfo: Contains information about relevant parts of the url.

responseFormat: Specifies the response format requested by the user.

If the user does not specify any response format, then default value is json.

To send the data to the user we need to perform below steps.
a. Extract the EntitySet information from the uriInfo object.
If the user calls the following URL: http://localhost:8080/olingoDemo/DemoService.svc/Products The readEntityCollection(...) method is invoked and the uriInfo object contains one segment: “Products”
If the user calls the following URL: http://localhost:8080/olingoDemo/DemoService.svc/Products?$filter=ID eq 1 Then the readEntityCollection(...) method is invoked and the uriInfo contains the information about the entity set and furthermore the system query option $filter and its value.

b. Get the data related to given EntitySet

c. Create a serializer depends on the user requested format. Default is json

d. Serialize the content to inputstream

e. Send the inputStream to response.

DemoEntityCollectionProcessor.java
package com.app.service;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;

import org.apache.olingo.commons.api.data.ContextURL;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.OData;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.ODataLibraryException;
import org.apache.olingo.server.api.ODataRequest;
import org.apache.olingo.server.api.ODataResponse;
import org.apache.olingo.server.api.ServiceMetadata;
import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
import org.apache.olingo.server.api.serializer.ODataSerializer;
import org.apache.olingo.server.api.serializer.SerializerResult;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;

public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
 private OData odata;
 private ServiceMetadata serviceMetadata;

 public void init(OData odata, ServiceMetadata serviceMetadata) {
  this.odata = odata;
  this.serviceMetadata = serviceMetadata;
 }

 public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
   ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {

  List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
  UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
  EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();

  EntityCollection entitySet = getData(edmEntitySet);

  ODataSerializer serializer = odata.createSerializer(responseFormat);

  EdmEntityType edmEntityType = edmEntitySet.getEntityType();
  ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();

  final String id = request.getRawBaseUri() + "/" + edmEntitySet.getName();
  EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with().id(id).contextURL(contextUrl)
    .build();
  SerializerResult serializedContent = serializer.entityCollection(serviceMetadata, edmEntityType, entitySet,
    opts);

  response.setContent(serializedContent.getContent());
  response.setStatusCode(HttpStatusCode.OK.getStatusCode());
  response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());

 }

 private EntityCollection getData(EdmEntitySet edmEntitySet) {

  EntityCollection dataToSend = new EntityCollection();

  if (DemoEdmProvider.ES_PRODUCTS_NAME.equals(edmEntitySet.getName())) {
   List<Entity> productList = dataToSend.getEntities();

   // add some sample product entities
   final Entity e1 = new Entity().addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1))
     .addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
     .addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
       "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB"))
     .addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 95000));
   e1.setId(createId("Products", 1));
   productList.add(e1);

   final Entity e2 = new Entity().addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2))
     .addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
     .addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
       "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network"))
     .addProperty(new Property(null, "Price", ValueType.PRIMITIVE, 95000));
   e2.setId(createId("Products", 1));
   productList.add(e2);

  }

  return dataToSend;
 }

 private URI createId(String entitySetName, Object id) {
  try {
   return new URI(entitySetName + "(" + String.valueOf(id) + ")");
  } catch (URISyntaxException e) {
   throw new ODataRuntimeException("Unable to create id for entity: " + entitySetName, e);
  }
 }
}


Run the application on server and hit below url.

You will receive below kind of response.
<?xml version="1.0" encoding="UTF-8"?>
<a:feed xmlns:a="http://www.w3.org/2005/Atom" xmlns:d="http://docs.oasis-open.org/odata/ns/data" xmlns:m="http://docs.oasis-open.org/odata/ns/metadata" m:context="$metadata#Products">
   <a:id>http://localhost:8080/olingoDemo/DemoService.svc/Products</a:id>
   <a:entry>
      <a:id>Products(1)</a:id>
      <a:title />
      <a:summary />
      <a:updated>2018-12-06T21:58:37Z</a:updated>
      <a:author>
         <a:name />
      </a:author>
      <a:link rel="edit" href="Products(1)" />
      <a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#OData.Demo.Product" />
      <a:content type="application/xml">
         <m:properties>
            <d:ID m:type="Int32">1</d:ID>
            <d:Name>Notebook Basic 15</d:Name>
            <d:Description>Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB</d:Description>
            <d:Price m:type="Double">95000</d:Price>
         </m:properties>
      </a:content>
   </a:entry>
   <a:entry>
      <a:id>Products(1)</a:id>
      <a:title />
      <a:summary />
      <a:updated>2018-12-06T21:58:37Z</a:updated>
      <a:author>
         <a:name />
      </a:author>
      <a:link rel="edit" href="Products(1)" />
      <a:category scheme="http://docs.oasis-open.org/odata/ns/scheme" term="#OData.Demo.Product" />
      <a:content type="application/xml">
         <m:properties>
            <d:ID m:type="Int32">2</d:ID>
            <d:Name>1UMTS PDA</d:Name>
            <d:Description>Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network</d:Description>
            <d:Price m:type="Double">95000</d:Price>
         </m:properties>
      </a:content>
   </a:entry>
</a:feed>


If you want to get the json response, set the Accept header to application/json. You will get below response.
{
    "@odata.context": "$metadata#Products",
    "value": [
        {
            "ID": 1,
            "Name": "Notebook Basic 15",
            "Description": "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB",
            "Price": 95000
        },
        {
            "ID": 2,
            "Name": "1UMTS PDA",
            "Description": "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network",
            "Price": 95000
        }
    ]
}


At the time of writing this article, Olingo library support xml, json and atom responses.

Previous                                                    Next                                                    Home

No comments:

Post a Comment