From 07fe6eb7f8041ad115826a9918e3702f00f93a35 Mon Sep 17 00:00:00 2001 From: michaelpede Date: Fri, 23 Apr 2021 23:14:14 -0700 Subject: [PATCH] Request by Key Some code optimization to be done here. Perhaps add a Util class. --- .../GenericEntityCollectionProcessor.java | 11 +- .../service/data/GenericEntityProcessor.java | 206 ++++++++++++++++++ .../service/edmprovider/RESOedmProvider.java | 1 + .../org/reso/service/servlet/RESOservlet.java | 3 + 4 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/reso/service/data/GenericEntityProcessor.java diff --git a/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java b/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java index b48bad5..ed06f52 100644 --- a/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java +++ b/src/main/java/org/reso/service/data/GenericEntityCollectionProcessor.java @@ -19,11 +19,9 @@ 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 org.apache.olingo.server.api.uri.queryoption.*; -import org.apache.olingo.server.api.uri.queryoption.expression.Expression; import org.reso.service.data.meta.FieldInfo; import org.reso.service.data.meta.FilterExpressionVisitor; import org.reso.service.data.meta.ResourceInfo; -import org.reso.service.edmprovider.RESOedmProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,8 +39,8 @@ public class GenericEntityCollectionProcessor implements EntityCollectionProcess private OData odata; private ServiceMetadata serviceMetadata; private Connection connect = null; - private static final Logger LOG = LoggerFactory.getLogger(GenericEntityCollectionProcessor.class); private ResourceInfo resourceInfo = null; + private static final Logger LOG = LoggerFactory.getLogger(GenericEntityCollectionProcessor.class); public GenericEntityCollectionProcessor(Connection connection, ResourceInfo resourceInfo) { @@ -140,7 +138,6 @@ public class GenericEntityCollectionProcessor implements EntityCollectionProcess response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); } - protected EntityCollection getData(EdmEntitySet edmEntitySet, UriInfo uriInfo, boolean isCount) throws ODataApplicationException { ArrayList fields = this.resourceInfo.getFieldList(); @@ -209,14 +206,14 @@ public class GenericEntityCollectionProcessor implements EntityCollectionProcess } } - LOG.info("SQL Query: "+queryString); + LOG.debug("SQL Query: "+queryString); ResultSet resultSet = statement.executeQuery(queryString); // special return logic for $count if (isCount && resultSet.next()) { int size = resultSet.getInt("rowcount"); - LOG.info("Size = "+size); + LOG.debug("Size = "+size); entCollection.setCount(size); return entCollection; } @@ -265,7 +262,7 @@ public class GenericEntityCollectionProcessor implements EntityCollectionProcess private URI createId(String entitySetName, Object id) { try { - return new URI(entitySetName + "(" + String.valueOf(id) + ")"); + return new URI(entitySetName + "('" + String.valueOf(id) + "')"); } catch (URISyntaxException e) { throw new ODataRuntimeException("Unable to create id for entity: " + entitySetName, e); } diff --git a/src/main/java/org/reso/service/data/GenericEntityProcessor.java b/src/main/java/org/reso/service/data/GenericEntityProcessor.java new file mode 100644 index 0000000..125ee2d --- /dev/null +++ b/src/main/java/org/reso/service/data/GenericEntityProcessor.java @@ -0,0 +1,206 @@ +package org.reso.service.data; + + +import org.apache.olingo.commons.api.data.*; +import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; +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.*; +import org.apache.olingo.server.api.processor.EntityProcessor; +import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions; +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 org.apache.olingo.server.api.uri.queryoption.FilterOption; +import org.apache.olingo.server.api.uri.queryoption.SkipOption; +import org.apache.olingo.server.api.uri.queryoption.TopOption; +import org.reso.service.data.meta.FieldInfo; +import org.reso.service.data.meta.FilterExpressionVisitor; +import org.reso.service.data.meta.ResourceInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +public class GenericEntityProcessor implements EntityProcessor +{ + private OData odata; + private ServiceMetadata serviceMetadata; + private Connection connect; + ResourceInfo resourceInfo; + private static final Logger LOG = LoggerFactory.getLogger(GenericEntityCollectionProcessor.class); + + + public GenericEntityProcessor(Connection connect, ResourceInfo resourceInfo) + { + this.connect = connect; + this.resourceInfo = resourceInfo; + } + + + @Override public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat) + throws ODataApplicationException, ODataLibraryException + { + // 1. retrieve the Entity Type + List 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 keyPredicates = uriResourceEntitySet.getKeyPredicates(); + Entity entity = getData(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()); + } + + protected Entity getData(EdmEntitySet edmEntitySet, List keyPredicates) throws ODataApplicationException { + ArrayList fields = this.resourceInfo.getFieldList(); + + EntityCollection entCollection = new EntityCollection(); + + Entity product = null; + + Map properties = System.getenv(); + + try { + + String sqlCriteria = null; + + // Statements allow to issue SQL queries to the database + Statement statement = connect.createStatement(); + // Result set get the result of the SQL query + String queryString = null; + + for (final UriParameter key : keyPredicates) + { + // key + String keyName = key.getName(); + String keyValue = key.getText(); + if (sqlCriteria==null) + { + sqlCriteria = keyName + " = " + keyValue; + } + else + { + sqlCriteria = sqlCriteria + " and " + keyName + " = " + keyValue; + } + } + + queryString = "select * from " + this.resourceInfo.getTableName(); + + if (null!=sqlCriteria && sqlCriteria.length()>0) + { + queryString = queryString + " WHERE " + sqlCriteria; + } + + LOG.debug("SQL Query: "+queryString); + ResultSet resultSet = statement.executeQuery(queryString); + + String primaryFieldName = fields.get(0).getFieldName(); + + // add the lookups from the database. + while (resultSet.next()) + { + + String lookupKey = resultSet.getString(primaryFieldName); + Entity ent = new Entity(); + for (FieldInfo field : fields) + { + String fieldName = field.getFieldName(); + Object value = null; + if (field.getType().equals(EdmPrimitiveTypeKind.String.getFullQualifiedName())) + { + value = resultSet.getString(fieldName); + } + else if (field.getType().equals(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName())) + { + value = resultSet.getTimestamp(fieldName); + } + else + { + LOG.info("Field Name: "+field.getFieldName()+" Field type: "+field.getType()); + } + + ent.addProperty(new Property(null, fieldName, ValueType.PRIMITIVE, value)); + } + + ent.setId(createId(this.resourceInfo.getResourcesName(), lookupKey)); + product = ent; + } + + statement.close(); + + } catch (Exception e) { + LOG.error("Server Error occurred in reading "+this.resourceInfo.getResourceName(), e); + return product; + } + + return product; + } + + 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); + } + } + + @Override public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, ODataLibraryException + { + + } + + + @Override public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, ODataLibraryException + { + + } + + + @Override public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo) throws ODataApplicationException, ODataLibraryException + { + + } + + + @Override public void init(OData odata, ServiceMetadata serviceMetadata) + { + this.odata = odata; + this.serviceMetadata = serviceMetadata; + } +} diff --git a/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java b/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java index 1ee1570..2145059 100644 --- a/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java +++ b/src/main/java/org/reso/service/edmprovider/RESOedmProvider.java @@ -49,6 +49,7 @@ public class RESOedmProvider extends CsdlAbstractEdmProvider // create CsdlPropertyRef for Key element CsdlPropertyRef propertyRef = new CsdlPropertyRef(); propertyRef.setName(primaryFieldName); + LOG.debug("Primary key is: "+primaryFieldName); for (FieldInfo field : fields) { diff --git a/src/main/java/org/reso/service/servlet/RESOservlet.java b/src/main/java/org/reso/service/servlet/RESOservlet.java index 553243e..6bdf467 100644 --- a/src/main/java/org/reso/service/servlet/RESOservlet.java +++ b/src/main/java/org/reso/service/servlet/RESOservlet.java @@ -7,6 +7,7 @@ import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ServiceMetadata; import org.reso.service.data.GenericEntityCollectionProcessor; +import org.reso.service.data.GenericEntityProcessor; import org.reso.service.data.definition.LookupDefinition; import org.reso.service.data.meta.ResourceInfo; import org.reso.service.edmprovider.RESOedmProvider; @@ -83,8 +84,10 @@ public class RESOservlet extends HttpServlet this.handler = odata.createHandler(edm); GenericEntityCollectionProcessor lookupEntityCollectionProcessor = new GenericEntityCollectionProcessor(this.connect, defn); + GenericEntityProcessor lookupEntityProcessor = new GenericEntityProcessor(this.connect, defn); this.handler.register(lookupEntityCollectionProcessor); + this.handler.register(lookupEntityProcessor); }