From aac77f05ae8a74273465760bead43bbb5e83d862 Mon Sep 17 00:00:00 2001 From: Michael Bolz Date: Wed, 1 Oct 2014 10:15:25 +0200 Subject: [PATCH] [OLINGO-438] Added count support for entity set --- .../processor/EntityCollectionProcessor.java | 10 +++- .../olingo/server/core/ODataHandler.java | 9 ++++ .../core/uri/validator/UriValidator.java | 1 + .../server/core/ContentNegotiatorTest.java | 5 ++ .../tecsvc/processor/TechnicalProcessor.java | 49 ++++++++++++++++++- .../olingo/server/core/ODataHandlerTest.java | 40 +++++++++++++++ 6 files changed, 112 insertions(+), 2 deletions(-) diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityCollectionProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityCollectionProcessor.java index a3df302b9..c347bf3c5 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityCollectionProcessor.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/EntityCollectionProcessor.java @@ -29,11 +29,19 @@ import org.apache.olingo.server.api.uri.UriInfo; public interface EntityCollectionProcessor extends Processor { /** - * Reads entities data from persistency and puts serialized content and status into the response. + * Reads entities data from persistence and puts serialized content and status into the response. * @param request - OData request object containing raw HTTP information * @param response - OData response object for collecting response data * @param uriInfo - information of a parsed OData URI * @param requestedContentType - requested content type after content negotiation */ void readCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestedContentType); + + /** + * Count entities from persistence and puts serialized content and status into the response. + * @param request - OData request object containing raw http information. + * @param response - OData response object for collecting response data + * @param uriInfo - information of a parsed OData uri + */ + void countCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java index 0893d0933..dedc4a680 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java @@ -227,6 +227,15 @@ public class ODataHandler { } } break; + case count: + if (request.getMethod().equals(HttpMethod.GET)) { + EntityCollectionProcessor cp = selectProcessor(EntityCollectionProcessor.class); + cp.countCollection(request, response, uriInfo); + } else { + throw new ODataHandlerException("not implemented", + ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); + } + break; default: throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java index a16489491..9c03db420 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/validator/UriValidator.java @@ -521,6 +521,7 @@ public class UriValidator { UriResource secondLastPathSegment = uriInfo.getUriResourceParts().get(secondLastPathSegmentIndex); switch (secondLastPathSegment.getKind()) { case entitySet: + case navigationProperty: idx = RowIndexForUriType.entitySetCount; break; case complexProperty: diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java index 017a098d4..f95d2f912 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java @@ -230,5 +230,10 @@ public class ContentNegotiatorTest { final ContentType requestedContentType) { response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); } + + @Override + public void countCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo) { + response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.TEXT_PLAIN.toContentTypeString()); + } } } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java index 77136b5e5..19da171a7 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java @@ -43,8 +43,10 @@ import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; +import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind; import org.apache.olingo.server.tecsvc.data.DataProvider; +import java.io.ByteArrayInputStream; import java.util.List; import java.util.Locale; @@ -134,9 +136,54 @@ public class TechnicalProcessor implements EntityCollectionProcessor, EntityProc } } + @Override + public void countCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo) { + try { + EntitySet entitySet = null; + final UriInfoResource uriResource = uriInfo.asUriInfoResource(); + final List resourceParts = uriResource.getUriResourceParts(); + if(isCount(resourceParts)) { + int pos = resourceParts.size() - 2; + if(pos >= 0) { + final UriResourceEntitySet ur = + (UriResourceEntitySet) uriResource.getUriResourceParts().get(pos); + entitySet = readEntitySetInternal(ur.getEntitySet(), true); + } + } + + if (entitySet == null) { + response.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode()); + } else { + Integer count = entitySet.getCount(); + response.setContent(new ByteArrayInputStream(count.toString().getBytes())); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + response.setHeader(HttpHeader.CONTENT_TYPE, "text/plain"); + } + } catch (final DataProvider.DataProviderException e) { + response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode()); + } + } + + private boolean isCount(List resourceParts) { + if(resourceParts.isEmpty()) { + return false; + } + UriResource part = resourceParts.get(resourceParts.size() - 1); + return SystemQueryOptionKind.COUNT.toString().equals(part.toString()); + } + private EntitySet readEntitySetInternal(final EdmEntitySet edmEntitySet) throws DataProvider.DataProviderException { + return readEntitySetInternal(edmEntitySet, false); + } + + private EntitySet readEntitySetInternal(final EdmEntitySet edmEntitySet, + boolean withCount) throws DataProvider.DataProviderException { EntitySet entitySet = dataProvider.readAll(edmEntitySet); - // TODO: set count and next link + // TODO: set count (correctly) and next link + if(withCount && entitySet.getCount() == null) { + entitySet.setCount(entitySet.getEntities().size()); + } + // return entitySet; } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java index 04ed43496..9f8fbf4c7 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java @@ -35,11 +35,14 @@ import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.processor.EntityCollectionProcessor; import org.apache.olingo.server.api.processor.MetadataProcessor; import org.apache.olingo.server.api.processor.ServiceDocumentProcessor; +import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.junit.Before; import org.junit.Test; +import org.mockito.Mockito; public class ODataHandlerTest { @@ -238,4 +241,41 @@ public class ODataHandlerTest { assertEquals(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), response.getStatusCode()); } + @Test + public void testCount() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("ESAllPrim/$count"); + + EntityCollectionProcessor processor = mock(EntityCollectionProcessor.class); + handler.register(processor); + + ODataResponse response = handler.process(request); + + assertNotNull(response); + Mockito.verify(processor).countCollection( + Mockito.eq(request), + Mockito.any(ODataResponse.class), + Mockito.any(UriInfo.class)); + } + + @Test + public void testCountWithNavigation() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("ESAllPrim/NavPropertyETTwoPrimMany/$count"); + + EntityCollectionProcessor processor = mock(EntityCollectionProcessor.class); + handler.register(processor); + + ODataResponse response = handler.process(request); + + assertNotNull(response); + Mockito.verify(processor).countCollection( + Mockito.eq(request), + Mockito.any(ODataResponse.class), + Mockito.any(UriInfo.class)); + } }