In my previous post, I explained how to read all the
products information using below url.
{SERVER_URL}/DemoService.svc/Products
In this post, I am going to explain how can you get
single product information by hitting the below url.
{SERVER_URL}/DemoService.svc/Products(1)
We need to implement ‘org.apache.olingo.server.api.processor.EntityProcessor’
interface to support CRUD operations on individual entities.
Default implementation looks like below.
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 { } @Override public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException { // TODO Auto-generated method stub } @Override public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException { // TODO Auto-generated method stub } @Override public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException { // TODO Auto-generated method stub } }
We need to implement ‘readEntity’ method correctly, to
read the information about specific entity.
Below step-by-step
procedure explains how can we get the product details from below uri.
{SERVER_URL}/DemoService.svc/Products(1)
Step 1: Check
which entity type data is requested by the user.
List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0); EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet(); List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates(); EdmEntityType edmEntityType = edmEntitySet.getEntityType();
Step 2: Since we
got the entity set and the predicates information, we can use the predicate to
query all the entities and return the entity that matches to given predicates.
Below snippet takes an entity, entityType and property as
an argument and return the value associated with property in the entity as
string.
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); } }
Apart from the business logic, we need to register DemoEntityProcessor
to our ODataHttpHandler.
ODataHttpHandler handler = odata.createHandler(edm); handler.register(new DemoEntityCollectionProcessor()); handler.register(new DemoEntityProcessor());
Project structure looks like below.
Find the below working application.
Product.java
package com.app.model; public class Product { private int id; private String name; private String description; private double price; public Product(int id, String name, String description, double price){ this.id = id; this.name = name; this.description = description; this.price = price; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } }
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; } }
DemoEntityCollectionProcessor.java
package com.app.service; import java.util.List; import org.apache.olingo.commons.api.data.ContextURL; 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.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; import com.app.util.EntityUtil; 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 = EntityUtil.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()); } }
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.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.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 { // TODO Auto-generated method stub } @Override public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) throws ODataApplicationException, ODataLibraryException { // TODO Auto-generated method stub } @Override public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException { // TODO Auto-generated method stub } }
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; import com.app.service.DemoEntityProcessor; 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.register(new DemoEntityProcessor()); handler.process(req, resp); } catch (RuntimeException e) { LOG.error("Server Error occurred in ExampleServlet", e); throw new ServletException(e); } } }
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.server.api.ODataApplicationException; import org.apache.olingo.server.api.uri.UriParameter; 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; } }
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.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.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<>(); 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); } 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; } }
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>
index.jsp
<html> <body> <h2>Hello World!</h2> </body> </html>
Run the application on server and hit the below url in
browser.
http://localhost:8080/olingoReadData/DemoService.svc/Products(1)
You can see below response.
<?xml version="1.0" encoding="UTF-8"?> <a:entry 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>Products(1)</a:id> <a:title /> <a:summary /> <a:updated>2018-12-07T10:40:05Z</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>Washing Machine by AVC</d:Name> <d:Description>Good for morth east countries</d:Description> <d:Price m:type="Double">876544.0</d:Price> </m:properties> </a:content> </a:entry>
Try to access the some other product, which is not exist
in our catalog. For example, below url tries to access the product 11.
http://localhost:8080/olingoReadData/DemoService.svc/Products(11)
You will get below response.
<?xml version="1.0" encoding="UTF-8"?> <error xmlns="http://docs.oasis-open.org/odata/ns/metadata"> <code>404</code> <message>Entity for requested key doesn't exist</message> </error>
No comments:
Post a Comment