[OLINGO-545] TecSvc: Support of cyclic expands and filtering on arbitrary level
Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/518a3a41 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/518a3a41 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/518a3a41 Branch: refs/heads/OLINGO-573 Commit: 518a3a418e9e79e2a3ce5feb61e175083812c2d8 Parents: 583c4bd Author: Christian Holzer <[email protected]> Authored: Mon Apr 6 08:25:00 2015 +0200 Committer: Christian Holzer <[email protected]> Committed: Tue Apr 7 08:26:05 2015 +0200 ---------------------------------------------------------------------- .../ExpandWithSystemQueryOptionsITCase.java | 160 +++++++++++++- .../processor/TechnicalEntityProcessor.java | 6 +- .../ExpandSystemQueryOptionHandler.java | 208 +++++++++++++------ .../expression/ExpressionVisitorImpl.java | 10 +- .../queryoptions/options/FilterHandler.java | 6 +- .../queryoptions/options/OrderByHandler.java | 12 +- 6 files changed, 320 insertions(+), 82 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithSystemQueryOptionsITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithSystemQueryOptionsITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithSystemQueryOptionsITCase.java index 2db9535..1a6b411 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithSystemQueryOptionsITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ExpandWithSystemQueryOptionsITCase.java @@ -19,6 +19,7 @@ package org.apache.olingo.fit.tecsvc.client; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; import java.net.URI; @@ -119,7 +120,7 @@ public class ExpandWithSystemQueryOptionsITCase extends AbstractBaseTestITCase { } } } - + @Test public void testSkip() { final Map<QueryOption, Object> options = new HashMap<QueryOption, Object>(); @@ -290,7 +291,162 @@ public class ExpandWithSystemQueryOptionsITCase extends AbstractBaseTestITCase { assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); assertEquals(4, entities.size()); } - + + @Test + public void testCyclicExpand() { + // Expand entity in the following order + // 1 => 2 => 1 + // Entity with Key (PropertyInt16=1, PrroperyString='1') holds references to (PropertyInt16=1, PropertyString='1') + // and (PropertyInt16=1, PropertyString='2') + // Entity with Key (PropertyInt16=1, PropertyString='2') holds references to (PropertyInt16=1, PropertyString='1') + // Define filters to select explicit the entities at any level => Circle + + final ODataClient client = getClient(); + final Map<QueryOption, Object> options = new HashMap<QueryOption, Object>(); + options.put(QueryOption.EXPAND, NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + + "($expand=" + NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + + "($expand=" + NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + "))"); + options.put(QueryOption.FILTER, "PropertyString eq '2'"); + + final Map<String, Object> keys = new HashMap<String, Object>(); + keys.put(PROPERTY_INT16, 1); + keys.put(PROPERTY_STRING, "1"); + + final URI uri = client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(keys) + .expandWithOptions(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, options) + .build(); + + final ODataRetrieveResponse<ODataEntity> response = client.getRetrieveRequestFactory() + .getEntityRequest(uri) + .execute(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertNotNull(response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(1, response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final ODataEntity entitySecondLevel = response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .get(0); + + assertEquals(1, entitySecondLevel.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("2", entitySecondLevel.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + + assertNotNull(entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(1, entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final ODataEntity entityThirdLevel = entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .get(0); + + assertEquals(1, entityThirdLevel.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("1", entityThirdLevel.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + + assertNotNull(entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(2, entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final List<ODataEntity> fourthLevelEntites = entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities(); + + assertEquals(1, fourthLevelEntites.get(0).getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("1", fourthLevelEntites.get(0).getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + + assertEquals(1, fourthLevelEntites.get(1).getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("2", fourthLevelEntites.get(1).getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + } + + @Test + public void testSystemQueryOptionOnThirdLevel() { + final ODataClient client = getClient(); + final Map<QueryOption, Object> options = new HashMap<QueryOption, Object>(); + options.put(QueryOption.EXPAND, NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + + "($expand=" + NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + + "($expand=" + NAV_PROPERTY_ET_TWO_KEY_NAV_MANY + + ";$filter=PropertyString eq '1'))"); + options.put(QueryOption.FILTER, "PropertyString eq '2'"); + + final Map<String, Object> keys = new HashMap<String, Object>(); + keys.put(PROPERTY_INT16, 1); + keys.put(PROPERTY_STRING, "1"); + + final URI uri = client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(keys) + .expandWithOptions(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, options) + .build(); + + final ODataRetrieveResponse<ODataEntity> response = client.getRetrieveRequestFactory() + .getEntityRequest(uri) + .execute(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertNotNull(response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(1, response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final ODataEntity entitySecondLevel = response.getBody().getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .get(0); + + assertEquals(1, entitySecondLevel.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("2", entitySecondLevel.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + + assertNotNull(entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(1, entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final ODataEntity entityThirdLevel = entitySecondLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .get(0); + + assertEquals(1, entityThirdLevel.getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("1", entityThirdLevel.getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + + assertNotNull(entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY)); + assertEquals(1, entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities() + .size()); + + final List<ODataEntity> fourthLevelEntites = entityThirdLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY) + .asInlineEntitySet() + .getEntitySet() + .getEntities(); + + assertEquals(1, fourthLevelEntites.get(0).getProperty(PROPERTY_INT16).getPrimitiveValue().toValue()); + assertEquals("1", fourthLevelEntites.get(0).getProperty(PROPERTY_STRING).getPrimitiveValue().toValue()); + } + private ODataRetrieveResponse<ODataEntitySet> buildRequest(final String entitySet, final String navigationProperty, final Map<QueryOption, Object> expandOptions) { return buildRequest(entitySet, navigationProperty, expandOptions, null); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java index ed120b9..a2774e3 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java @@ -125,7 +125,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor // Create a shallow copy of each entity. So the expanded navigation properties can be modified for serialization, // without affecting the data stored in the database. final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler(); - final EntitySet entitySetSerialization = expandHandler.copyEntitySetShallowRekursive(entitySet); + final EntitySet entitySetSerialization = expandHandler.transformEntitySetGraphToTree(entitySet, + edmEntitySet, + expand); expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand); // Serialize @@ -186,7 +188,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final SelectOption select = uriInfo.getSelectOption(); final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler(); - final Entity entitySerialization = expandHandler.copyEntityShallowRekursive(entity); + final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand); expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand); response.setContent(serializer.entity( http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/ExpandSystemQueryOptionHandler.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/ExpandSystemQueryOptionHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/ExpandSystemQueryOptionHandler.java index 3ae3b3a..ce1b774 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/ExpandSystemQueryOptionHandler.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/ExpandSystemQueryOptionHandler.java @@ -18,15 +18,18 @@ */ package org.apache.olingo.server.tecsvc.processor.queryoptions; -import java.util.IdentityHashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; +import java.util.Set; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; import org.apache.olingo.commons.api.data.Link; +import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmNavigationProperty; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.core.data.EntityImpl; import org.apache.olingo.commons.core.data.EntitySetImpl; @@ -47,8 +50,6 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.options.SkipHandle import org.apache.olingo.server.tecsvc.processor.queryoptions.options.TopHandler; public class ExpandSystemQueryOptionHandler { - private IdentityHashMap<Entity, Entity> copiedEntities = new IdentityHashMap<Entity, Entity>(); - private IdentityHashMap<EntitySet, EntitySet> copiedEntitySets = new IdentityHashMap<EntitySet, EntitySet>(); public void applyExpandQueryOptions(final EntitySet entitySet, final EdmEntitySet edmEntitySet, final ExpandOption expandOption) throws ODataApplicationException { @@ -70,20 +71,26 @@ public class ExpandSystemQueryOptionHandler { applyExpandOptionToEntity(entity, edmEntitySet, expandOption); } - private void applyExpandOptionToEntity(final Entity entity, final EdmEntitySet edmEntitySet, + private void applyExpandOptionToEntity(final Entity entity, final EdmBindingTarget edmBindingTarget, final ExpandOption expandOption) throws ODataApplicationException { - final EdmEntityType entityType = edmEntitySet.getEntityType(); + final EdmEntityType entityType = edmBindingTarget.getEntityType(); for (ExpandItem item : expandOption.getExpandItems()) { final List<UriResource> uriResourceParts = item.getResourcePath().getUriResourceParts(); if (uriResourceParts.size() == 1 && uriResourceParts.get(0) instanceof UriResourceNavigation) { final String navPropertyName = ((UriResourceNavigation) uriResourceParts.get(0)).getProperty().getName(); - final EdmEntitySet targetEdmEntitySet = (EdmEntitySet) edmEntitySet.getRelatedBindingTarget(navPropertyName); + final EdmBindingTarget targetEdmEntitySet = edmBindingTarget.getRelatedBindingTarget(navPropertyName); final Link link = entity.getNavigationLink(navPropertyName); if (link != null && entityType.getNavigationProperty(navPropertyName).isCollection()) { - applyOptionsToEntityCollection(link.getInlineEntitySet(), targetEdmEntitySet, item.getFilterOption(), - item.getOrderByOption(), item.getCountOption(), item.getSkipOption(), item.getTopOption()); + applyOptionsToEntityCollection(link.getInlineEntitySet(), + targetEdmEntitySet, + item.getFilterOption(), + item.getOrderByOption(), + item.getCountOption(), + item.getSkipOption(), + item.getTopOption(), + item.getExpandOption()); } } else { throw new ODataApplicationException("Not supported resource part in expand system query option", @@ -92,77 +99,150 @@ public class ExpandSystemQueryOptionHandler { } } - private void applyOptionsToEntityCollection(final EntitySet entitySet, final EdmEntitySet edmEntitySet, + private void applyOptionsToEntityCollection(final EntitySet entitySet, final EdmBindingTarget edmBindingTarget, final FilterOption filterOption, final OrderByOption orderByOption, final CountOption countOption, - final SkipOption skipOption, final TopOption topOption) throws ODataApplicationException { + final SkipOption skipOption, final TopOption topOption, final ExpandOption expandOption) + throws ODataApplicationException { - FilterHandler.applyFilterSystemQuery(filterOption, entitySet, edmEntitySet); - OrderByHandler.applyOrderByOption(orderByOption, entitySet, edmEntitySet); + FilterHandler.applyFilterSystemQuery(filterOption, entitySet, edmBindingTarget); + OrderByHandler.applyOrderByOption(orderByOption, entitySet, edmBindingTarget); // TODO Add CountHandler SkipHandler.applySkipSystemQueryHandler(skipOption, entitySet); TopHandler.applyTopSystemQueryOption(topOption, entitySet); + + // Apply nested expand system query options to remaining entities + if(expandOption != null) { + for(final Entity entity : entitySet.getEntities()) { + applyExpandOptionToEntity(entity, edmBindingTarget, expandOption); + } + } } - public EntitySet copyEntitySetShallowRekursive(final EntitySet entitySet) { - if (!copiedEntitySets.containsKey(entitySet)) { - final EntitySet copiedEntitySet = new EntitySetImpl(); - copiedEntitySet.setCount(entitySet.getCount()); - copiedEntitySet.setDeltaLink(entitySet.getDeltaLink()); - copiedEntitySet.setNext(entitySet.getNext()); - - copiedEntitySets.put(entitySet, copiedEntitySet); - copiedEntitySets.put(copiedEntitySet, copiedEntitySet); - - for (Entity entity : entitySet.getEntities()) { - copiedEntitySet.getEntities().add(copyEntityShallowRekursive(entity)); - } - return copiedEntitySet; + public EntitySet transformEntitySetGraphToTree(final EntitySet entitySet, final EdmBindingTarget edmBindingTarget, + final ExpandOption expand) throws ODataApplicationException { + + final EntitySet newEntitySet = newEntitySet(entitySet); + + for(final Entity entity : entitySet.getEntities()) { + newEntitySet.getEntities().add(transformEntityGraphToTree(entity, edmBindingTarget, expand)); } - return copiedEntitySets.get(entitySet); + + return newEntitySet; } + + public Entity transformEntityGraphToTree(final Entity entity, EdmBindingTarget edmEntitySet, + final ExpandOption expand) throws ODataApplicationException { - public Entity copyEntityShallowRekursive(final Entity entity) { - if (!copiedEntities.containsKey(entity)) { - final Entity copiedEntity = new EntityImpl(); - copiedEntity.getProperties().addAll(entity.getProperties()); - copiedEntity.getAnnotations().addAll(entity.getAnnotations()); - copiedEntity.getAssociationLinks().addAll(entity.getAssociationLinks()); - copiedEntity.setEditLink(entity.getEditLink()); - copiedEntity.setId(entity.getId()); - copiedEntity.setMediaContentSource(entity.getMediaContentSource()); - copiedEntity.setMediaContentType(entity.getMediaContentType()); - copiedEntity.setMediaETag(entity.getMediaETag()); - copiedEntity.getOperations().addAll(entity.getOperations()); - copiedEntity.setSelfLink(entity.getSelfLink()); - copiedEntity.setType(entity.getType()); - copiedEntity.getNavigationBindings().addAll(entity.getNavigationBindings()); - - copiedEntities.put(entity, copiedEntity); - copiedEntities.put(copiedEntity, copiedEntity); - - // The system query options change the amount and sequence of inline entities (feeds) - // So we have to make a shallow copy of all navigation link lists - // Make sure, that each entity is only copied once. - // Otherwise an infinite loop can occur caused by cyclic navigation relationships. + final Entity newEntity = newEntity(entity); + if (hasExpandItems(expand)) { + final boolean expandAll = expandAll(expand); + final Set<String> expanded = expandAll ? null : getExpandedPropertyNames(expand.getExpandItems()); + final EdmEntityType edmType = edmEntitySet.getEntityType(); + for (final Link link : entity.getNavigationLinks()) { - final Link newLink = new LinkImpl(); - newLink.setMediaETag(link.getMediaETag()); - newLink.setTitle(link.getTitle()); - newLink.setType(link.getType()); - newLink.setRel(link.getRel()); - - final EntitySet inlineEntitySet = link.getInlineEntitySet(); - if (inlineEntitySet != null) { - newLink.setInlineEntitySet(copyEntitySetShallowRekursive(inlineEntitySet)); - } else if (link.getInlineEntity() != null) { - newLink.setInlineEntity(copyEntityShallowRekursive(link.getInlineEntity())); + final String propertyName = link.getTitle(); + + if (expandAll || expanded.contains(propertyName)) { + final EdmNavigationProperty edmNavigationProperty = edmType.getNavigationProperty(propertyName); + final EdmBindingTarget edmBindingTarget = edmEntitySet.getRelatedBindingTarget(propertyName); + final Link newLink = newLink(link); + newEntity.getNavigationLinks().add(newLink); + final ExpandOption innerExpandOption = getInnerExpandOption(expand, propertyName); + + if(edmNavigationProperty.isCollection()) { + newLink.setInlineEntitySet(transformEntitySetGraphToTree(link.getInlineEntitySet(), + edmBindingTarget, + innerExpandOption)); + } else { + newLink.setInlineEntity(transformEntityGraphToTree(link.getInlineEntity(), + edmBindingTarget, + innerExpandOption)); + } } - copiedEntity.getNavigationLinks().add(newLink); } + + } + return newEntity; + } + + public EntitySet newEntitySet(final EntitySet entitySet) { + final EntitySet newEntitySet = new EntitySetImpl(); + newEntitySet.setCount(entitySet.getCount()); + newEntitySet.setDeltaLink(entitySet.getDeltaLink()); + newEntitySet.setNext(entitySet.getNext()); + + return newEntitySet; + } + + private Entity newEntity(final Entity entity) { + final Entity newEntity = new EntityImpl(); + + newEntity.getProperties().addAll(entity.getProperties()); + newEntity.getAnnotations().addAll(entity.getAnnotations()); + newEntity.getAssociationLinks().addAll(entity.getAssociationLinks()); + newEntity.setEditLink(entity.getEditLink()); + newEntity.setId(entity.getId()); + newEntity.setMediaContentSource(entity.getMediaContentSource()); + newEntity.setMediaContentType(entity.getMediaContentType()); + newEntity.setMediaETag(entity.getMediaETag()); + newEntity.getOperations().addAll(entity.getOperations()); + newEntity.setSelfLink(entity.getSelfLink()); + newEntity.setType(entity.getType()); + newEntity.getNavigationBindings().addAll(entity.getNavigationBindings()); + + return newEntity; + } + + private Link newLink(Link link) { + final Link newLink = new LinkImpl(); + newLink.setMediaETag(link.getMediaETag()); + newLink.setTitle(link.getTitle()); + newLink.setType(link.getType()); + newLink.setRel(link.getRel()); + + return newLink; + } + + private boolean hasExpandItems(ExpandOption expand) { + return expand != null && expand.getExpandItems() != null && !expand.getExpandItems().isEmpty(); + } + + private boolean expandAll(ExpandOption expand) { + for (final ExpandItem item : expand.getExpandItems()) { + if (item.isStar()) { + return true; + } + } + return false; + } + + private Set<String> getExpandedPropertyNames(List<ExpandItem> expandItems) throws ODataApplicationException { + Set<String> expanded = new HashSet<String>(); + for (final ExpandItem item : expandItems) { + final List<UriResource> resourceParts = item.getResourcePath().getUriResourceParts(); + if (resourceParts.size() == 1) { + final UriResource resource = resourceParts.get(0); + if (resource instanceof UriResourceNavigation) { + expanded.add(((UriResourceNavigation) resource).getProperty().getName()); + } + } else { + throw new ODataApplicationException("Expand is not supported within complex properties.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + } + } + return expanded; + } - return copiedEntity; + private ExpandOption getInnerExpandOption(final ExpandOption expand, final String propertyName) { + for(final ExpandItem item : expand.getExpandItems()) { + final UriResource resource = item.getResourcePath().getUriResourceParts().get(0); + if(resource instanceof UriResourceNavigation + && propertyName.equals(((UriResourceNavigation) resource).getProperty().getName())) { + return item.getExpandOption(); + } } - return copiedEntities.get(entity); + + return null; } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java index 3a91f49..ab0eca3 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/ExpressionVisitorImpl.java @@ -23,8 +23,8 @@ import java.util.Locale; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmComplexType; -import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEnumType; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmType; @@ -49,11 +49,11 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operati public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> { final private Entity entity; - final private EdmEntitySet edmEntitySet; + final private EdmBindingTarget bindingTarget; - public ExpressionVisitorImpl(Entity entity, EdmEntitySet edmEntitySet) { + public ExpressionVisitorImpl(Entity entity, EdmBindingTarget bindingTarget) { this.entity = entity; - this.edmEntitySet = edmEntitySet; + this.bindingTarget = bindingTarget; } @Override @@ -183,7 +183,7 @@ public class ExpressionVisitorImpl implements ExpressionVisitor<VisitorOperand> Property currentProperty = entity.getProperty(uriResourceParts.get(0).toString()); EdmType currentType = ((UriResourcePartTyped) uriResourceParts.get(0)).getType(); - EdmProperty currentEdmProperty = edmEntitySet.getEntityType() + EdmProperty currentEdmProperty = bindingTarget.getEntityType() .getStructuralProperty(uriResourceParts.get(0).toString()); for (int i = 1; i < uriResourceParts.size(); i++) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/FilterHandler.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/FilterHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/FilterHandler.java index f1ba4ee..d4068a1 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/FilterHandler.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/FilterHandler.java @@ -23,7 +23,7 @@ import java.util.Locale; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; -import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.commons.core.edm.primitivetype.EdmBoolean; import org.apache.olingo.server.api.ODataApplicationException; @@ -53,8 +53,8 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand public class FilterHandler { - public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, EdmEntitySet edmEntitySet) - throws ODataApplicationException { + public static void applyFilterSystemQuery(FilterOption filterOption, EntitySet entitySet, + EdmBindingTarget edmEntitySet) throws ODataApplicationException { if (filterOption == null) { return; http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/518a3a41/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/OrderByHandler.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/OrderByHandler.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/OrderByHandler.java index 71b9a81..d166c4e 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/OrderByHandler.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/options/OrderByHandler.java @@ -24,7 +24,7 @@ import java.util.Locale; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntitySet; -import org.apache.olingo.commons.api.edm.EdmEntitySet; +import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.uri.queryoption.OrderByItem; @@ -35,14 +35,14 @@ import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand public class OrderByHandler { public static void applyOrderByOption(final OrderByOption orderByOption, final EntitySet entitySet, - final EdmEntitySet edmEntitySet) throws ODataApplicationException { + final EdmBindingTarget edmBindingTarget) throws ODataApplicationException { if (orderByOption == null) { return; } try { - applyOrderByOptionInternal(orderByOption, entitySet, edmEntitySet); + applyOrderByOptionInternal(orderByOption, entitySet, edmBindingTarget); } catch (SystemQueryOptionsRuntimeException e) { if (e.getCause() instanceof ODataApplicationException) { // Throw the nested exception, to send the correct HTTP status code in the HTTP response @@ -55,7 +55,7 @@ public class OrderByHandler { } private static void applyOrderByOptionInternal(final OrderByOption orderByOption, final EntitySet entitySet, - final EdmEntitySet edmEntitySet) throws ODataApplicationException { + final EdmBindingTarget edmBindingTarget) throws ODataApplicationException { Collections.sort(entitySet.getEntities(), new Comparator<Entity>() { @Override @SuppressWarnings({ "unchecked", "rawtypes" }) @@ -69,9 +69,9 @@ public class OrderByHandler { try { final OrderByItem item = orderByOption.getOrders().get(i); final TypedOperand op1 = - item.getExpression().accept(new ExpressionVisitorImpl(e1, edmEntitySet)).asTypedOperand(); + item.getExpression().accept(new ExpressionVisitorImpl(e1, edmBindingTarget)).asTypedOperand(); final TypedOperand op2 = - item.getExpression().accept(new ExpressionVisitorImpl(e2, edmEntitySet)).asTypedOperand(); + item.getExpression().accept(new ExpressionVisitorImpl(e2, edmBindingTarget)).asTypedOperand(); if (op1.isNull() || op2.isNull()) { if (op1.isNull() && op2.isNull()) {
