Thursday 25 July 2019

Olingo: OData: Update an entity


To update an entity, we need to implement 'updateEntity' method of EntityProcessor interface.

Procedure is almost like getting the object.

a.   Get the entity associated with this id
b.   Update the entity with the properties provided in request body
c.    Return the entity

Below are the updated classes from previous post.

DemoEntityProcessor.java
package com.app.service;

import java.io.InputStream;
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.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.format.ContentType;
import org.apache.olingo.commons.api.http.HttpHeader;
import org.apache.olingo.commons.api.http.HttpMethod;
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.deserializer.DeserializerResult;
import org.apache.olingo.server.api.deserializer.ODataDeserializer;
import org.apache.olingo.server.api.processor.EntityProcessor;
import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
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.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;

import com.app.util.EntityUtil;

public class DemoEntityProcessor implements EntityProcessor {
 private OData odata;
 private ServiceMetadata serviceMetadata;

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

 @Override
 public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
   throws ODataApplicationException, ODataLibraryException {
  // 1. retrieve the Entity Type
  List<UriResource> resourcePaths = uriInfo.getUriResourceParts();

  // Note: only in our example we can assume that the first segment is the
  // EntitySet
  UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
  EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();

  // 2. retrieve the data from backend
  List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
  Entity entity = EntityUtil.readEntityData(edmEntitySet, keyPredicates);

  // 3. serialize
  EdmEntityType entityType = edmEntitySet.getEntityType();

  ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
  // expand and select currently not supported
  EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();

  ODataSerializer serializer = odata.createSerializer(responseFormat);
  SerializerResult serializerResult = serializer.entity(serviceMetadata, entityType, entity, options);
  InputStream entityStream = serializerResult.getContent();

  // 4. configure the response object
  response.setContent(entityStream);
  response.setStatusCode(HttpStatusCode.OK.getStatusCode());
  response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
 }

 @Override
 public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
   ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {
  EdmEntitySet edmEntitySet = EntityUtil.getEntitySetFromURI(uriInfo);

  EdmEntityType edmEntityType = edmEntitySet.getEntityType();

  InputStream requestInputStream = request.getBody();
  ODataDeserializer deserializer = this.odata.createDeserializer(requestFormat);
  DeserializerResult result = deserializer.entity(requestInputStream, edmEntityType);
  Entity requestEntity = result.getEntity();

  Entity createdEntity = EntityUtil.createEntityData(edmEntitySet, requestEntity);

  ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();

  EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();

  ODataSerializer serializer = this.odata.createSerializer(responseFormat);
  SerializerResult serializedResponse = serializer.entity(serviceMetadata, edmEntityType, createdEntity, options);

  response.setContent(serializedResponse.getContent());
  response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
  response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
 }

 @Override
 public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
   ContentType responseFormat) throws ODataApplicationException, ODataLibraryException {

  List<UriResource> resourcePaths = uriInfo.getUriResourceParts();

  UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
  EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
  EdmEntityType edmEntityType = edmEntitySet.getEntityType();

  InputStream requestInputStream = request.getBody();
  ODataDeserializer deserializer = this.odata.createDeserializer(requestFormat);
  DeserializerResult result = deserializer.entity(requestInputStream, edmEntityType);
  Entity requestEntity = result.getEntity();

  List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();

  HttpMethod httpMethod = request.getMethod();
  EntityUtil.updateEntityData(edmEntitySet, keyPredicates, requestEntity, httpMethod);

  response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());

 }

 @Override
 public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
   throws ODataApplicationException, ODataLibraryException {
  // TODO Auto-generated method stub

 }

}


EntityUtil.java
package com.app.util;

import java.util.List;

import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.EntityCollection;
import org.apache.olingo.commons.api.edm.EdmEntitySet;
import org.apache.olingo.commons.api.edm.EdmEntityType;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriInfo;
import org.apache.olingo.server.api.uri.UriParameter;
import org.apache.olingo.server.api.uri.UriResource;
import org.apache.olingo.server.api.uri.UriResourceEntitySet;

import com.app.service.DemoEdmProvider;

/**
 * Responsible to perform CRUD operations on entities.
 * 
 * @author Krishna
 *
 */
public class EntityUtil {

 public static EntityCollection getData(EdmEntitySet edmEntitySet) {
  if (DemoEdmProvider.ES_PRODUCTS_NAME.equals(edmEntitySet.getName())) {
   return ProductUtil.getProductsData();
  }

  return null;
 }

 public static Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
   throws ODataApplicationException {

  EdmEntityType edmEntityType = edmEntitySet.getEntityType();

  // actually, this is only required if we have more than one Entity Type
  if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
   return ProductUtil.getProduct(edmEntityType, keyParams);
  }

  return null;
 }

 public static EdmEntitySet getEntitySetFromURI(UriInfo uriInfo) {
  List<UriResource> resourcePaths = uriInfo.getUriResourceParts();

  UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
  EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();

  return edmEntitySet;
 }

 public static Entity createEntityData(EdmEntitySet edmEntitySet, Entity entityToCreate) {

  EdmEntityType edmEntityType = edmEntitySet.getEntityType();

  // actually, this is only required if we have more than one Entity Type
  if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
   return ProductUtil.createProduct(edmEntityType, entityToCreate);
  }

  return null;
 }

 public static void updateEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyPredicates,
   Entity requestEntity, HttpMethod httpMethod) throws ODataApplicationException {

  EdmEntityType edmEntityType = edmEntitySet.getEntityType();

  if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
   ProductUtil.updateProduct(edmEntityType, keyPredicates, requestEntity, httpMethod);
  }
 }

}


ProductUtil.java
package com.app.util;

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

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.EdmEntityType;
import org.apache.olingo.commons.api.edm.EdmKeyPropertyRef;
import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
import org.apache.olingo.commons.api.edm.EdmProperty;
import org.apache.olingo.commons.api.edm.EdmType;
import org.apache.olingo.commons.api.ex.ODataRuntimeException;
import org.apache.olingo.commons.api.http.HttpMethod;
import org.apache.olingo.commons.api.http.HttpStatusCode;
import org.apache.olingo.server.api.ODataApplicationException;
import org.apache.olingo.server.api.uri.UriParameter;

import com.app.model.Product;

public class ProductUtil {
 private static List<Product> products = new ArrayList<>();
 public static int idCounter = 3;

 static {
  Product prod1 = new Product(1, "Washing Machine by AVC", "Good for morth east countries", 876544);
  Product prod2 = new Product(2, "XYZ Camera", "Catch pics while travelling", 965987);

  products.add(prod1);
  products.add(prod2);
 }

 public static int getId() {
  return idCounter++;
 }

 private static Entity getProductEntity(final Product product) {
  Entity entity = new Entity().addProperty(new Property(null, "ID", ValueType.PRIMITIVE, product.getId()))
    .addProperty(new Property(null, "Name", ValueType.PRIMITIVE, product.getName()))
    .addProperty(new Property(null, "Description", ValueType.PRIMITIVE, product.getDescription()))
    .addProperty(new Property(null, "Price", ValueType.PRIMITIVE, product.getPrice()));
  entity.setId(createId("Products", product.getId()));
  return entity;
 }

 public static EntityCollection getProductsData() {
  EntityCollection dataToSend = new EntityCollection();
  List<Entity> productList = dataToSend.getEntities();

  for (Product prod : products) {
   productList.add(getProductEntity(prod));
  }

  return dataToSend;
 }

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

 public static Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
   throws ODataApplicationException {
  EntityCollection entitySet = getProductsData();

  Entity requestedEntity = findEntity(edmEntityType, entitySet, keyParams);

  if (requestedEntity == null) {
   throw new ODataApplicationException("Entity for requested key doesn't exist",
     HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
  }

  return requestedEntity;
 }

 public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
   List<UriParameter> keyParams) throws ODataApplicationException {

  List<Entity> entityList = entitySet.getEntities();

  for (Entity entity : entityList) {
   boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
   if (foundEntity) {
    return entity;
   }
  }

  return null;
 }

 private static String getValueOfTheProperty(EdmEntityType edmEntityType, Entity entity, String propertyName)
   throws ODataApplicationException {
  EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(propertyName);

  /*
   * Get some basic information to convert the property value of this
   * entity to string
   */
  Boolean isNullable = edmKeyProperty.isNullable();
  Integer maxLength = edmKeyProperty.getMaxLength();
  Integer precision = edmKeyProperty.getPrecision();
  Boolean isUnicode = edmKeyProperty.isUnicode();
  Integer scale = edmKeyProperty.getScale();

  EdmType edmType = edmKeyProperty.getType();
  Object valueObject = entity.getProperty(propertyName).getValue();

  try {
   EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
   return edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode);
  } catch (EdmPrimitiveTypeException e) {
   throw new ODataApplicationException("Failed to retrieve String value",
     HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ENGLISH, e);
  }
 }

 public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity entity, List<UriParameter> keyParams)
   throws ODataApplicationException {

  /* We need to make sure that all the predicates are matched */
  for (final UriParameter key : keyParams) {
   String keyName = key.getName();
   String keyText = key.getText();

   String valueAsString = getValueOfTheProperty(edmEntityType, entity, keyName);

   if (valueAsString == null || !valueAsString.equals(keyText)) {
    return false;
   }
  }

  return true;
 }

 public static Entity createProduct(EdmEntityType edmEntityType, Entity entity) {

  int newId = ProductUtil.getId();

  Property idProperty = entity.getProperty("ID");

  if (idProperty != null) {
   idProperty.setValue(ValueType.PRIMITIVE, Integer.valueOf(newId));
  } else {
   entity.getProperties().add(new Property(null, "ID", ValueType.PRIMITIVE, newId));
  }

  String name = (String) entity.getProperty("Name").getValue();
  String description = (String) entity.getProperty("Description").getValue();
  double price = (Double) entity.getProperty("Price").getValue();

  entity.setId(createId("Products", newId));

  Product prod = new Product(newId, name, description, price);

  products.add(prod);

  return entity;

 }

 public static void updateProduct(EdmEntityType edmEntityType, Entity entity) {

  Property idProperty = entity.getProperty("ID");
  int id = (Integer) idProperty.getValue();

  for (Product prod : products) {

   if (prod.getId() != id) {
    continue;
   }
   String name = null, description = null;
   double price = 0;

   Property property = entity.getProperty("Name");

   if (property != null) {
    name = (String) property.getValue();
   }

   property = entity.getProperty("Description");

   if (property != null) {
    description = (String) property.getValue();
   }

   property = entity.getProperty("Price");

   if (property != null) {
    price = (Double) property.getValue();
   }

   prod.setName(name);
   prod.setDescription(description);
   prod.setPrice(price);
   break;
  }
 }

 public static void updateProduct(EdmEntityType edmEntityType, List<UriParameter> keyPredicates,
   Entity requestEntity, HttpMethod httpMethod) throws ODataApplicationException {
  Entity productEntity = getProduct(edmEntityType, keyPredicates);
  if (productEntity == null) {
   throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(),
     Locale.ENGLISH);
  }

  List<Property> existingProperties = productEntity.getProperties();
  for (Property existingProp : existingProperties) {
   String propName = existingProp.getName();

   if (isKey(edmEntityType, propName)) {
    continue;
   }

   Property updateProperty = requestEntity.getProperty(propName);

   if (updateProperty == null) {
    if (httpMethod.equals(HttpMethod.PATCH)) {
     continue;
    } else if (httpMethod.equals(HttpMethod.PUT)) {
     existingProp.setValue(existingProp.getValueType(), null);
     continue;
    }
   }

   existingProp.setValue(existingProp.getValueType(), updateProperty.getValue());
  }

  updateProduct(edmEntityType, productEntity);

 }

 private static boolean isKey(EdmEntityType edmEntityType, String propertyName) {
  List<EdmKeyPropertyRef> keyPropertyRefs = edmEntityType.getKeyPropertyRefs();
  for (EdmKeyPropertyRef propRef : keyPropertyRefs) {
   String keyPropertyName = propRef.getName();
   if (keyPropertyName.equals(propertyName)) {
    return true;
   }
  }
  return false;
 }
}

Run the application on server and hit below request.

Method: PATCH
uri: http://localhost:8080/olingoWriteData/DemoService.svc/Products(1)

BODY
{
  "Name":"ABC Laser printer"
}


After updating the product 1 details, hit below request.


You can see below products.
{
    "@odata.context": "$metadata#Products",
    "value": [
        {
            "ID": 1,
            "Name": "ABC Laser printer",
            "Description": "Good for morth east countries",
            "Price": 876544
        },
        {
            "ID": 2,
            "Name": "XYZ Camera",
            "Description": "Catch pics while travelling",
            "Price": 965987
        }
    ]
}


As you see name of the product 1 is updated.




Previous                                                    Next                                                    Home

No comments:

Post a Comment