Repository: olingo-odata4 Updated Branches: refs/heads/master 90781859b -> 03ad0444f
[OLINGO-545] support for navigation in technical service Change-Id: I53e0330d9d8d73a868361c26569b992cb0bb91f3 Signed-off-by: Christian Amend <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/03ad0444 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/03ad0444 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/03ad0444 Branch: refs/heads/master Commit: 03ad0444fa295ede4dba3ec13b8102b8fa5c56ee Parents: 9078185 Author: Klaus Straubinger <[email protected]> Authored: Tue Feb 17 15:57:48 2015 +0100 Committer: Christian Amend <[email protected]> Committed: Tue Feb 17 16:32:57 2015 +0100 ---------------------------------------------------------------------- .../fit/tecsvc/client/NavigationITCase.java | 142 +++++++++++++++++++ .../apache/olingo/server/api/uri/UriHelper.java | 9 ++ .../olingo/server/core/uri/UriHelperImpl.java | 16 ++- .../olingo/server/tecsvc/data/DataProvider.java | 52 +++---- .../processor/TechnicalEntityProcessor.java | 89 ++++-------- .../TechnicalPrimitiveComplexProcessor.java | 124 +++++++--------- .../tecsvc/processor/TechnicalProcessor.java | 91 +++++++++++- 7 files changed, 349 insertions(+), 174 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java new file mode 100644 index 0000000..0693836 --- /dev/null +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.olingo.fit.tecsvc.client; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.apache.olingo.client.api.CommonODataClient; +import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.client.api.v4.ODataClient; +import org.apache.olingo.client.core.ODataClientFactory; +import org.apache.olingo.commons.api.domain.v4.ODataEntity; +import org.apache.olingo.commons.api.domain.v4.ODataEntitySet; +import org.apache.olingo.commons.api.domain.v4.ODataProperty; +import org.apache.olingo.commons.api.format.ODataFormat; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.fit.AbstractBaseTestITCase; +import org.apache.olingo.fit.tecsvc.TecSvcConst; +import org.junit.Test; + +public final class NavigationITCase extends AbstractBaseTestITCase { + + private final CommonODataClient<?> client = getClient(); + + @Test + public void oneLevelToEntity() throws Exception { + final ODataRetrieveResponse<ODataEntity> response = + client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest( + client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767) + .appendNavigationSegment("NavPropertyETTwoPrimOne").build()) + .execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ODataEntity entity = response.getBody(); + assertNotNull(entity); + final ODataProperty property = entity.getProperty("PropertyString"); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String4", property.getPrimitiveValue().toValue()); + } + + @Test + public void oneLevelToEntityWithKey() throws Exception { + final ODataRetrieveResponse<ODataEntity> response = + client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest( + client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767) + .appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build()) + .execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ODataEntity entity = response.getBody(); + assertNotNull(entity); + final ODataProperty property = entity.getProperty("PropertyString"); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String2", property.getPrimitiveValue().toValue()); + } + + @Test + public void twoLevelsToEntityWithKey() throws Exception { + final ODataRetrieveResponse<ODataEntity> response = + client.getRetrieveRequestFactory().<ODataEntity> getEntityRequest( + client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767) + .appendNavigationSegment("NavPropertyETAllPrimOne") + .appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build()) + .execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ODataEntity entity = response.getBody(); + assertNotNull(entity); + final ODataProperty property = entity.getProperty("PropertyString"); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String2", property.getPrimitiveValue().toValue()); + } + + @Test + public void twoLevelsToEntitySet() throws Exception { + final ODataRetrieveResponse<ODataEntitySet> response = + client.getRetrieveRequestFactory().<ODataEntitySet> getEntitySetRequest( + client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767) + .appendNavigationSegment("NavPropertyETAllPrimOne") + .appendNavigationSegment("NavPropertyETTwoPrimMany").build()) + .execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ODataEntitySet entitySet = response.getBody(); + assertNotNull(entitySet); + assertEquals(1, entitySet.getEntities().size()); + final ODataEntity entity = entitySet.getEntities().get(0); + assertNotNull(entity); + final ODataProperty property = entity.getProperty("PropertyString"); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String2", property.getPrimitiveValue().toValue()); + } + + @Test + public void twoLevelsToProperty() throws Exception { + final ODataRetrieveResponse<ODataProperty> response = + client.getRetrieveRequestFactory().<ODataProperty> getPropertyRequest( + client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESKeyNav").appendKeySegment(1) + .appendNavigationSegment("NavPropertyETKeyNavOne") + .appendNavigationSegment("NavPropertyETKeyNavMany").appendKeySegment(3) + .appendPropertySegment("PropertyComp").appendPropertySegment("PropertyInt16").build()) + .execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ODataProperty property = response.getBody(); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals(1, property.getPrimitiveValue().toValue()); + } + + @Override + protected CommonODataClient<?> getClient() { + ODataClient odata = ODataClientFactory.getV4(); + odata.getConfiguration().setDefaultPubFormat(ODataFormat.JSON); + return odata; + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java ---------------------------------------------------------------------- diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java index 16ec276..672ce4b 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/UriHelper.java @@ -22,6 +22,7 @@ import java.util.List; 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.edm.EdmStructuredType; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; @@ -56,4 +57,12 @@ public interface UriHelper { * @return the relative canonical URL */ String buildCanonicalURL(EdmEntitySet edmEntitySet, Entity entity) throws SerializerException; + + /** + * Builds the key predicate for the given entity. + * @param edmEntityType the entity type of the entity + * @param entity the entity data + * @return the key predicate + */ + String buildKeyPredicate(EdmEntityType edmEntityType, Entity entity) throws SerializerException; } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java ---------------------------------------------------------------------- diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java index 8bbbc3f..6e946de 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriHelperImpl.java @@ -50,10 +50,13 @@ public class UriHelperImpl implements UriHelper { @Override public String buildCanonicalURL(final EdmEntitySet edmEntitySet, final Entity entity) throws SerializerException { - StringBuilder result = new StringBuilder(edmEntitySet.getName()); - result.append('('); - final EdmEntityType entityType = edmEntitySet.getEntityType(); - final List<String> keyNames = entityType.getKeyPredicateNames(); + return edmEntitySet.getName() + '(' + buildKeyPredicate(edmEntitySet.getEntityType(), entity) + ')'; + } + + @Override + public String buildKeyPredicate(final EdmEntityType edmEntityType, final Entity entity) throws SerializerException { + StringBuilder result = new StringBuilder(); + final List<String> keyNames = edmEntityType.getKeyPredicateNames(); boolean first = true; for (final String keyName : keyNames) { if (first) { @@ -64,7 +67,7 @@ public class UriHelperImpl implements UriHelper { if (keyNames.size() > 1) { result.append(Encoder.encode(keyName)).append('='); } - final EdmProperty edmProperty = entityType.getStructuralProperty(keyName); + final EdmProperty edmProperty = edmEntityType.getStructuralProperty(keyName); final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType(); final Object propertyValue = entity.getProperty(keyName).getValue(); try { @@ -78,7 +81,6 @@ public class UriHelperImpl implements UriHelper { SerializerException.MessageKeys.WRONG_PROPERTY_VALUE, edmProperty.getName(), propertyValue.toString()); } } - result.append(')'); return result.toString(); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java index c35ba86..cb94467 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java @@ -58,34 +58,34 @@ public class DataProvider { public Entity read(final EdmEntitySet edmEntitySet, final List<UriParameter> keys) throws DataProviderException { final EntitySet entitySet = readAll(edmEntitySet); - if (entitySet == null) { - return null; - } else { - final EdmEntityType edmEntityType = edmEntitySet.getEntityType(); - try { - for (final Entity entity : entitySet.getEntities()) { - boolean found = true; - for (final UriParameter key : keys) { - final EdmProperty property = (EdmProperty) edmEntityType.getProperty(key.getName()); - final EdmPrimitiveType type = (EdmPrimitiveType) property.getType(); - final Object value = entity.getProperty(key.getName()).getValue(); - final Object keyValue = type.valueOfString(type.fromUriLiteral(key.getText()), - property.isNullable(), property.getMaxLength(), property.getPrecision(), property.getScale(), - property.isUnicode(), - Calendar.class.isAssignableFrom(value.getClass()) ? Calendar.class : value.getClass()); - if (!value.equals(keyValue)) { - found = false; - break; - } - } - if (found) { - return entity; + return entitySet == null ? null : read(edmEntitySet.getEntityType(), entitySet, keys); + } + + public Entity read(final EdmEntityType edmEntityType, final EntitySet entitySet, final List<UriParameter> keys) + throws DataProviderException { + try { + for (final Entity entity : entitySet.getEntities()) { + boolean found = true; + for (final UriParameter key : keys) { + final EdmProperty property = (EdmProperty) edmEntityType.getProperty(key.getName()); + final EdmPrimitiveType type = (EdmPrimitiveType) property.getType(); + final Object value = entity.getProperty(key.getName()).getValue(); + final Object keyValue = type.valueOfString(type.fromUriLiteral(key.getText()), + property.isNullable(), property.getMaxLength(), property.getPrecision(), property.getScale(), + property.isUnicode(), + Calendar.class.isAssignableFrom(value.getClass()) ? Calendar.class : value.getClass()); + if (!value.equals(keyValue)) { + found = false; + break; } } - return null; - } catch (final EdmPrimitiveTypeException e) { - throw new DataProviderException("Wrong key!", e); + if (found) { + return entity; + } } + return null; + } catch (final EdmPrimitiveTypeException e) { + throw new DataProviderException("Wrong key!", e); } } @@ -201,7 +201,7 @@ public class DataProvider { property.setValue(property.getValueType(), value); } } else if (edmProperty.isCollection()) { - if (newProperty != null && !newProperty.asLinkedComplex().getValue().isEmpty()) { + if (newProperty != null && !newProperty.asCollection().isEmpty()) { throw new DataProviderException("Update of a complex-collection property not supported!"); } else { property.asCollection().clear(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/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 6cd3195..9868366 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 @@ -18,7 +18,6 @@ */ package org.apache.olingo.server.tecsvc.processor; -import java.util.List; import java.util.Locale; import org.apache.olingo.commons.api.data.ContextURL; @@ -45,13 +44,11 @@ import org.apache.olingo.server.api.processor.EntityCollectionProcessor; import org.apache.olingo.server.api.processor.EntityProcessor; import org.apache.olingo.server.api.processor.MediaEntityProcessor; import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions; -import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.EntitySerializerOptions; +import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; 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.UriResourceKind; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; import org.apache.olingo.server.tecsvc.data.DataProvider; @@ -71,14 +68,14 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void readEntityCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestedContentType) throws ODataApplicationException, SerializerException { validateOptions(uriInfo.asUriInfoResource()); - blockNavigation(uriInfo); - - final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); - final EntitySet entitySet = readEntitySetInternal(edmEntitySet, - uriInfo.getCountOption() != null && uriInfo.getCountOption().getValue()); + final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); + EntitySet entitySet = readEntityCollection(uriInfo); if (entitySet == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } else { + if (uriInfo.getCountOption() != null && uriInfo.getCountOption().getValue()) { + setCount(entitySet); + } final ODataFormat format = ODataFormat.fromContentType(requestedContentType); ODataSerializer serializer = odata.createSerializer(format); final ExpandOption expand = uriInfo.getExpandOption(); @@ -107,15 +104,12 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void countEntityCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException, SerializerException { validateOptions(uriInfo.asUriInfoResource()); - blockNavigation(uriInfo); - - final List<UriResource> resourceParts = uriInfo.asUriInfoResource().getUriResourceParts(); - final EntitySet entitySet = - readEntitySetInternal(((UriResourceEntitySet) resourceParts.get(resourceParts.size() - 2)).getEntitySet(), - true); + getEdmEntitySet(uriInfo); // including checks + EntitySet entitySet = readEntityCollection(uriInfo); if (entitySet == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); } else { + setCount(entitySet); response.setContent(odata.createFixedFormatSerializer().count(entitySet.getCount())); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, HttpContentType.TEXT_PLAIN); @@ -126,12 +120,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void readEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestedContentType) throws ODataApplicationException, SerializerException { validateOptions(uriInfo.asUriInfoResource()); - blockNavigation(uriInfo); - - final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); - final Entity entity = dataProvider.read(edmEntitySet, resourceEntitySet.getKeyPredicates()); - checkEntity(entity); + final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); + final Entity entity = readEntity(uriInfo); final ODataFormat format = ODataFormat.fromContentType(requestedContentType); ODataSerializer serializer = odata.createSerializer(format); @@ -150,10 +140,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor @Override public void readMediaEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType responseFormat) throws ODataApplicationException, SerializerException { - blockNavigation(uriInfo); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); - final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), resourceEntitySet.getKeyPredicates()); - checkEntity(entity); + getEdmEntitySet(uriInfo); // including checks + final Entity entity = readEntity(uriInfo); response.setContent(odata.createFixedFormatSerializer().binary(dataProvider.readMedia(entity))); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, entity.getMediaContentType()); @@ -170,7 +158,10 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void createEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - blockNavigation(uriInfo); + if (uriInfo.asUriInfoResource().getUriResourceParts().size() > 1) { + throw new ODataApplicationException("Invalid resource type.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + } checkRequestFormat(requestFormat); final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet(); @@ -204,11 +195,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void updateEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - blockNavigation(uriInfo); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); - final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet(); - Entity entity = dataProvider.read(edmEntitySet, resourceEntitySet.getKeyPredicates()); - checkEntity(entity); + final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); + Entity entity = readEntity(uriInfo); checkRequestFormat(requestFormat); ODataDeserializer deserializer = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)); final Entity changedEntity = deserializer.entity(request.getBody(), edmEntitySet.getEntityType()); @@ -220,11 +208,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void updateMediaEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - blockNavigation(uriInfo); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); - final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet(); - final Entity entity = dataProvider.read(edmEntitySet, resourceEntitySet.getKeyPredicates()); - checkEntity(entity); + getEdmEntitySet(uriInfo); // including checks + Entity entity = readEntity(uriInfo); checkRequestFormat(requestFormat); dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), requestFormat.toContentTypeString()); @@ -234,11 +219,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor @Override public void deleteEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { - blockNavigation(uriInfo); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); - final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), resourceEntitySet.getKeyPredicates()); - checkEntity(entity); - dataProvider.delete(resourceEntitySet.getEntitySet(), entity); + final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); + final Entity entity = readEntity(uriInfo); + dataProvider.delete(edmEntitySet, entity); response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } @@ -250,31 +233,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - private void blockNavigation(final UriInfo uriInfo) throws ODataApplicationException { - final List<UriResource> parts = uriInfo.asUriInfoResource().getUriResourceParts(); - if (parts.size() > 2 - || parts.size() == 2 - && parts.get(1).getKind() != UriResourceKind.count - && parts.get(1).getKind() != UriResourceKind.value) { - throw new ODataApplicationException("Invalid resource type.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); - } - } - - private EntitySet readEntitySetInternal(final EdmEntitySet edmEntitySet, final boolean withCount) - throws DataProvider.DataProviderException { - EntitySet entitySet = dataProvider.readAll(edmEntitySet); + private void setCount(EntitySet entitySet) { // TODO: set count (correctly) and next link - if (withCount && entitySet.getCount() == null) { + if (entitySet.getCount() == null) { entitySet.setCount(entitySet.getEntities().size()); } - return entitySet; - } - - private void checkEntity(final Entity entity) throws ODataApplicationException { - if (entity == null) { - throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); - } } private void checkRequestFormat(final ContentType requestFormat) throws ODataApplicationException { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java index c77b9a4..596fe95 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java @@ -61,7 +61,6 @@ import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoResource; import org.apache.olingo.server.api.uri.UriResource; -import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.UriResourceKind; import org.apache.olingo.server.api.uri.UriResourceProperty; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; @@ -73,9 +72,9 @@ import org.apache.olingo.server.tecsvc.data.DataProvider; */ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor implements PrimitiveProcessor, PrimitiveValueProcessor, ActionPrimitiveProcessor, - PrimitiveCollectionProcessor, ActionPrimitiveCollectionProcessor, - ComplexProcessor, ActionComplexProcessor, - ComplexCollectionProcessor, ActionComplexCollectionProcessor { + PrimitiveCollectionProcessor, ActionPrimitiveCollectionProcessor, + ComplexProcessor, ActionComplexProcessor, + ComplexCollectionProcessor, ActionComplexCollectionProcessor { public TechnicalPrimitiveComplexProcessor(final DataProvider dataProvider) { super(dataProvider); @@ -84,11 +83,6 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void readPrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - if(isFunctionImport(uriInfo)) { - throw new ODataApplicationException("Function imports are not supported yet in technical scenario.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); - } - readProperty(response, uriInfo, contentType, RepresentationType.PRIMITIVE); } @@ -108,8 +102,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void processActionPrimitive(final ODataRequest request, final ODataResponse response, - final UriInfo uriInfo, - final ContentType requestFormat, final ContentType responseFormat) + final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported yet.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); @@ -118,10 +111,6 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void readPrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - if(isFunctionImport(uriInfo)) { - throw new ODataApplicationException("Function imports are not supported yet in technical scenario.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); - } readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_PRIMITIVE); } @@ -141,10 +130,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void processActionPrimitiveCollection(final ODataRequest request, final ODataResponse response, - final UriInfo uriInfo, - final ContentType requestFormat, final ContentType responseFormat) - throws ODataApplicationException, DeserializerException, - SerializerException { + final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported yet.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @@ -152,10 +139,6 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void readComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - if(isFunctionImport(uriInfo)) { - throw new ODataApplicationException("Function imports are not supported yet in technical scenario.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); - } readProperty(response, uriInfo, contentType, RepresentationType.COMPLEX); } @@ -168,9 +151,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void processActionComplex(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType - requestFormat, ContentType responseFormat) throws ODataApplicationException, DeserializerException, - SerializerException { + public void processActionComplex(ODataRequest request, ODataResponse response, UriInfo uriInfo, + ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported yet.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @@ -184,10 +167,6 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void readComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - if(isFunctionImport(uriInfo)) { - throw new ODataApplicationException("Function imports are not supported yet in technical scenario.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); - } readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_COMPLEX); } @@ -201,9 +180,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor @Override public void processActionComplexCollection(ODataRequest request, ODataResponse response, - UriInfo uriInfo, ContentType requestFormat, - ContentType responseFormat) - throws ODataApplicationException, DeserializerException, SerializerException { + UriInfo uriInfo, ContentType requestFormat, ContentType responseFormat) + throws ODataApplicationException, DeserializerException, SerializerException { throw new ODataApplicationException("Not supported yet.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @@ -214,22 +192,18 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor deleteProperty(response, uriInfo); } - private boolean isFunctionImport(final UriInfo uriInfo) { - final List<UriResource> resourceParts = uriInfo.asUriInfoResource().getUriResourceParts(); - return !resourceParts.isEmpty() && resourceParts.get(0).getKind() == UriResourceKind.function; - } - private void readProperty(final ODataResponse response, final UriInfo uriInfo, final ContentType contentType, final RepresentationType representationType) throws ODataApplicationException, SerializerException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validateOptions(resource); validatePath(resource); + final EdmEntitySet edmEntitySet = getEdmEntitySet(resource); final List<UriResource> resourceParts = resource.getUriResourceParts(); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0); - final List<String> path = getPropertyPath(resourceParts); + final List<String> path = getPropertyPath(resourceParts, 0); - final Property property = getPropertyData(resourceEntitySet, path); + final Entity entity = readEntity(uriInfo); + final Property property = getPropertyData(entity, path); if (property == null) { throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); @@ -237,8 +211,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (property.getValue() == null) { response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { - final EdmEntitySet edmEntitySet = getEdmEntitySet(resource); - final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty(); + final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(resourceParts.size() - 1)) + .getProperty(); final ODataFormat format = ODataFormat.fromContentType(contentType); ODataSerializer serializer = odata.createSerializer(format); @@ -247,8 +221,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final UriHelper helper = odata.createUriHelper(); final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null : ContextURL.with().entitySet(edmEntitySet) - .keyPath(helper.buildContextURLKeyPredicate( - ((UriResourceEntitySet) resourceParts.get(0)).getKeyPredicates())) + .keyPath(helper.buildKeyPredicate(edmEntitySet.getEntityType(), entity)) .navOrPropertyPath(buildPropertyPath(path)) .selectList(edmProperty.isPrimitive() ? null : helper.buildContextURLSelectList((EdmStructuredType) edmProperty.getType(), expand, select)) @@ -286,13 +259,15 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor private void deleteProperty(final ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validatePath(resource); + getEdmEntitySet(uriInfo); // including checks final List<UriResource> resourceParts = resource.getUriResourceParts(); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0); - final List<String> path = getPropertyPath(resourceParts); + final List<String> path = getPropertyPath(resourceParts, 0); - final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty(); - final Property property = getPropertyData(resourceEntitySet, path); + final Property property = getPropertyData(readEntity(uriInfo), path); + + final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(resourceParts.size() - 1)) + .getProperty(); if (edmProperty.isNullable() == null || edmProperty.isNullable()) { property.setValue(property.getValueType(), edmProperty.isCollection() ? Collections.emptyList() : null); @@ -302,36 +277,31 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } } - private Property getPropertyData(final UriResourceEntitySet resourceEntitySet, final List<String> path) + private Property getPropertyData(final Entity entity, final List<String> path) throws ODataApplicationException { - final Entity entity = dataProvider.read(resourceEntitySet.getEntitySet(), resourceEntitySet.getKeyPredicates()); - if (entity == null) { - throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); - } else { - Property property = entity.getProperty(path.get(0)); - for (final String name : path.subList(1, path.size())) { - if (property != null && (property.isLinkedComplex() || property.isComplex())) { - final List<Property> complex = property.isLinkedComplex() ? - property.asLinkedComplex().getValue() : property.asComplex(); - property = null; - for (final Property innerProperty : complex) { - if (innerProperty.getName().equals(name)) { - property = innerProperty; - break; - } + Property property = entity.getProperty(path.get(0)); + for (final String name : path.subList(1, path.size())) { + if (property != null && (property.isLinkedComplex() || property.isComplex())) { + final List<Property> complex = property.isLinkedComplex() ? + property.asLinkedComplex().getValue() : property.asComplex(); + property = null; + for (final Property innerProperty : complex) { + if (innerProperty.getName().equals(name)) { + property = innerProperty; + break; } } } - return property; } + return property; } - private List<String> getPropertyPath(final List<UriResource> path) { + private List<String> getPropertyPath(final List<UriResource> path, final int trailing) { List<String> result = new LinkedList<String>(); - int index = 1; - while (index < path.size() && path.get(index) instanceof UriResourceProperty) { - result.add(((UriResourceProperty) path.get(index)).getProperty().getName()); - index++; + int index = path.size() - trailing - 1; + while (path.get(index) instanceof UriResourceProperty) { + result.add(0, ((UriResourceProperty) path.get(index)).getProperty().getName()); + index--; } return result; } @@ -350,17 +320,18 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final UriInfoResource resource = uriInfo.asUriInfoResource(); validateOptions(resource); validatePath(resource); + getEdmEntitySet(uriInfo); // including checks final List<UriResource> resourceParts = resource.getUriResourceParts(); - final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0); - final List<String> path = getPropertyPath(resourceParts); + final List<String> path = getPropertyPath(resourceParts, 1); - final Property property = getPropertyData(resourceEntitySet, path); + final Property property = getPropertyData(readEntity(uriInfo), path); if (property == null || property.getValue() == null) { response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { - final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(path.size())).getProperty(); + final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(resourceParts.size() - 2)) + .getProperty(); final EdmPrimitiveType type = (EdmPrimitiveType) edmProperty.getType(); final FixedFormatSerializer serializer = odata.createFixedFormatSerializer(); response.setContent(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Binary) ? @@ -376,7 +347,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); for (final UriResource segment : resourcePaths.subList(1, resourcePaths.size())) { final UriResourceKind kind = segment.getKind(); - if (kind != UriResourceKind.primitiveProperty + if (kind != UriResourceKind.navigationProperty + && kind != UriResourceKind.primitiveProperty && kind != UriResourceKind.complexProperty && kind != UriResourceKind.count && kind != UriResourceKind.value) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/03ad0444/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java ---------------------------------------------------------------------- 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 4fa3d36..3ecb4ed 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 @@ -18,19 +18,25 @@ */ package org.apache.olingo.server.tecsvc.processor; - import java.util.List; 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.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.EdmNavigationProperty; 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.ServiceMetadata; import org.apache.olingo.server.api.processor.Processor; import org.apache.olingo.server.api.uri.UriInfoResource; +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.UriResourceNavigation; import org.apache.olingo.server.tecsvc.data.DataProvider; /** @@ -63,7 +69,88 @@ public abstract class TechnicalProcessor implements Processor { throw new ODataApplicationException("Type filters are not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - return uriResource.getEntitySet(); + EdmEntitySet entitySet = uriResource.getEntitySet(); + + int navigationCount = 0; + while (++navigationCount < resourcePaths.size() + && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) { + final UriResourceNavigation uriNavigationResource = (UriResourceNavigation) resourcePaths.get(navigationCount); + if (uriNavigationResource.getTypeFilterOnCollection() != null + || uriNavigationResource.getTypeFilterOnEntry() != null) { + throw new ODataApplicationException("Type filters are not supported.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + } + if (uriNavigationResource.getProperty().containsTarget()) { + throw new ODataApplicationException("Containment navigation is not supported.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + } + final EdmBindingTarget target = entitySet.getRelatedBindingTarget(uriNavigationResource.getProperty().getName()); + if (target instanceof EdmEntitySet) { + entitySet = (EdmEntitySet) target; + } else { + throw new ODataApplicationException("Singletons are not supported.", + HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + } + } + + return entitySet; + } + + /** + * Reads an entity as specified in the resource path, including navigation. + * If there is navigation and the navigation ends on an entity collection, + * returns the entity before the final navigation segment. + */ + protected Entity readEntity(final UriInfoResource uriInfo) throws ODataApplicationException { + final List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); + final UriResourceEntitySet uriResource = (UriResourceEntitySet) resourcePaths.get(0); + Entity entity = dataProvider.read(uriResource.getEntitySet(), uriResource.getKeyPredicates()); + if (entity == null) { + throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + } + + int navigationCount = 0; + while (++navigationCount < resourcePaths.size() + && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) { + final UriResourceNavigation uriNavigationResource = (UriResourceNavigation) resourcePaths.get(navigationCount); + final EdmNavigationProperty navigationProperty = uriNavigationResource.getProperty(); + final List<UriParameter> key = uriNavigationResource.getKeyPredicates(); + if (navigationProperty.isCollection() && key.isEmpty()) { + return entity; + } + final Link link = entity.getNavigationLink(navigationProperty.getName()); + entity = link == null ? null : + key.isEmpty() ? + link.getInlineEntity() : + dataProvider.read(navigationProperty.getType(), link.getInlineEntitySet(), key); + if (entity == null) { + throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + } + } + + return entity; + } + + protected EntitySet readEntityCollection(final UriInfoResource uriInfo) throws ODataApplicationException { + final List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); + if (resourcePaths.size() > 1 && resourcePaths.get(1) instanceof UriResourceNavigation) { + final Entity entity = readEntity(uriInfo); + final Link link = entity.getNavigationLink(getLastNavigation(uriInfo).getProperty().getName()); + return link == null ? null : link.getInlineEntitySet(); + } else { + return dataProvider.readAll(((UriResourceEntitySet) resourcePaths.get(0)).getEntitySet()); + } + } + + private UriResourceNavigation getLastNavigation(final UriInfoResource uriInfo) { + final List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); + int navigationCount = 1; + while (navigationCount < resourcePaths.size() + && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) { + navigationCount++; + } + + return (UriResourceNavigation) resourcePaths.get(--navigationCount); } protected void validateOptions(final UriInfoResource uriInfo) throws ODataApplicationException {
