Repository: olingo-odata4 Updated Branches: refs/heads/master 97a017843 -> d4c2b89e4
[OLINGO-545] TecSvc: Request validation added Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/583c4bd0 Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/583c4bd0 Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/583c4bd0 Branch: refs/heads/master Commit: 583c4bd07886ce38dae7fa41bcfbd8404d1b6abf Parents: 97a0178 Author: Christian Holzer <[email protected]> Authored: Mon Apr 6 08:25:00 2015 +0200 Committer: Christian Holzer <[email protected]> Committed: Tue Apr 7 08:25:43 2015 +0200 ---------------------------------------------------------------------- .../olingo/fit/tecsvc/client/BasicITCase.java | 38 +++ .../olingo/fit/tecsvc/client/BindingITCase.java | 35 ++- .../fit/tecsvc/client/DeepInsertITCase.java | 176 ++++++++++++- .../tecsvc/client/FilterSystemQueryITCase.java | 25 +- .../olingo/server/tecsvc/data/DataProvider.java | 26 +- .../server/tecsvc/data/RequestValidator.java | 255 +++++++++++++++++++ .../processor/TechnicalEntityProcessor.java | 27 +- 7 files changed, 548 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index b7bac00..5b8949a 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -30,8 +30,10 @@ import static org.junit.Assert.fail; import java.net.URI; import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; +import org.apache.olingo.client.api.EdmEnabledODataClient; import org.apache.olingo.client.api.ODataClient; import org.apache.olingo.client.api.communication.ODataClientErrorException; import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest; @@ -266,6 +268,7 @@ public class BasicITCase extends AbstractBaseTestITCase { ODataEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETAllPrim")); newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt64", factory.newPrimitiveValueBuilder().buildInt32(42))); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").appendKeySegment(32767) .build(); final ODataEntityUpdateRequest<ODataEntity> request = client.getCUDRequestFactory().getEntityUpdateRequest( @@ -373,6 +376,12 @@ public class BasicITCase extends AbstractBaseTestITCase { ODataEntity newEntity = factory.newEntity(new FullQualifiedName("olingo.odata.test1", "ETAllPrim")); newEntity.getProperties().add(factory.newPrimitiveProperty("PropertyInt64", factory.newPrimitiveValueBuilder().buildInt32(42))); + newEntity.addLink(factory.newEntityNavigationLink("NavPropertyETTwoPrimOne", + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .build())); + final ODataEntityCreateRequest<ODataEntity> createRequest = client.getCUDRequestFactory().getEntityCreateRequest( client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").build(), newEntity); @@ -518,6 +527,18 @@ public class BasicITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty("PropertyInt16", of.newPrimitiveValueBuilder().buildInt16((short) 2))) .add(of.newPrimitiveProperty("PropertySingle", of.newPrimitiveValueBuilder().buildSingle(2.0f)))))))); + entity.addLink(of.newEntityNavigationLink("NavPropertyETTwoKeyNavOne", + getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoKeyNav") + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 1L; + + { + put("PropertyInt16", 1); + put("PropertyString", "1"); + } + }).build())); + final ODataEntityCreateResponse<ODataEntity> response = getClient().getCUDRequestFactory().getEntityCreateRequest( getClient().newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESKeyNav").build(), entity).execute(); @@ -576,6 +597,23 @@ public class BasicITCase extends AbstractBaseTestITCase { assertNull(innerComplexProperty2.get("NotAvailableProperty")); } + @Test + public void testComplexPropertyWithNotNullablePrimitiveValue() { + final EdmEnabledODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final ODataObjectFactory of = client.getObjectFactory(); + + // PropertyComp is null, but the primitive values in PropertyComp must not be null + final ODataEntity entity = of.newEntity(new FullQualifiedName("olingo.odata.test1", "ETMixPrimCollComp")); + final URI targetURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESMixPrimCollComp").build(); + + try { + client.getCUDRequestFactory().getEntityCreateRequest(targetURI, entity).execute(); + fail("Expecting bad request"); + } catch (ODataClientErrorException e) { + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode()); + } + } + @Override protected ODataClient getClient() { ODataClient odata = ODataClientFactory.getClient(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BindingITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BindingITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BindingITCase.java index 75cadd0..74b7718 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BindingITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BindingITCase.java @@ -24,6 +24,7 @@ import static org.junit.Assert.fail; import java.net.URI; import java.util.HashMap; import java.util.Iterator; +import java.util.LinkedHashMap; import org.apache.olingo.client.api.EdmEnabledODataClient; import org.apache.olingo.client.api.ODataClient; @@ -69,9 +70,9 @@ public class BindingITCase extends AbstractBaseTestITCase { private static final String PROPERTY_COMP_ALL_PRIM = "PropertyCompAllPrim"; private static final String NAV_PROPERTY_ET_KEY_NAV_ONE = "NavPropertyETKeyNavOne"; private static final String NAV_PROPERTY_ET_KEY_NAV_MANY = "NavPropertyETKeyNavMany"; + private static final String NAV_PROPERTY_ET_TWO_KEY_NAV_ONE = "NavPropertyETTwoKeyNavOne"; private static final String NAV_PROPERTY_ET_TWO_KEY_NAV_MANY = "NavPropertyETTwoKeyNavMany"; - @Test public void testCreateBindingSimple() throws EdmPrimitiveTypeException { final ODataClient client = getClient(); @@ -101,6 +102,17 @@ public class BindingITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 42))))))); // Bind existing entities via binding synatx + entity.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE, + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 3109256773218160485L; + { + put(PROPERTY_INT16, 3); + put(PROPERTY_STRING, "1"); + } + }).build())); + final ODataLink navLinkOne = of.newEntityNavigationLink(NAV_PROPERTY_ET_KEY_NAV_ONE, client.newURIBuilder(SERVICE_URI) .appendEntitySetSegment( @@ -331,10 +343,31 @@ public class BindingITCase extends AbstractBaseTestITCase { innerEntity.getProperties().add(of.newComplexProperty(PROPERTY_COMP_TWO_PRIM, of.newComplexValue(CT_TWO_PRIM) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 1))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString("2"))))); + innerEntity.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE, + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 3109256773218160485L; + { + put(PROPERTY_INT16, 3); + put(PROPERTY_STRING, "1"); + } + }).build())); final ODataInlineEntity inlineLink = of.newDeepInsertEntity(NAV_PROPERTY_ET_KEY_NAV_ONE, innerEntity); entity.addLink(inlineLink); + entity.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE, + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 3109256773218160485L; + { + put(PROPERTY_INT16, 3); + put(PROPERTY_STRING, "1"); + } + }).build())); + final URI bindingURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV) .appendKeySegment(3) .build(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/DeepInsertITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/DeepInsertITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/DeepInsertITCase.java index ba33e3f..5255712 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/DeepInsertITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/DeepInsertITCase.java @@ -20,6 +20,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; import java.util.HashMap; @@ -27,8 +28,12 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; +import org.apache.olingo.client.api.EdmEnabledODataClient; import org.apache.olingo.client.api.ODataClient; +import org.apache.olingo.client.api.communication.ODataClientErrorException; +import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest; import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.core.ODataClientFactory; @@ -62,8 +67,10 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { private static final String CT_TWO_PRIM = "CTTwoPrim"; private static final String CT_ALL_PRIM = "CTAllPrim"; private static final String CT_NAV_FIVE_PROP = "CTNavFiveProp"; + private static final String CT_BASE_PRIM_COMP_NAV = "CTBasePrimCompNav"; private static final String PROPERTY_INT16 = "PropertyInt16"; private static final String PROPERTY_STRING = "PropertyString"; + private static final String PROPERTY_COMP = "PropertyComp"; private static final String PROPERTY_COMP_NAV = "PropertyCompNav"; private static final String PROPERTY_COMP_COMP_NAV = "PropertyCompCompNav"; private static final String PROPERTY_COMP_TWO_PRIM = "PropertyCompTwoPrim"; @@ -71,6 +78,8 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { private static final String NAV_PROPERTY_ET_KEY_NAV_ONE = "NavPropertyETKeyNavOne"; private static final String NAV_PROPERTY_ET_TWO_KEY_NAV_ONE = "NavPropertyETTwoKeyNavOne"; private static final String NAV_PROPERTY_ET_TWO_KEY_NAV_MANY = "NavPropertyETTwoKeyNavMany"; + private static final String COL_PROPERTY_STRING = "CollPropertyString"; + private static final String EDM_STRING = "Edm.String"; @Test public void testDeepInsertExpandedResponse() { @@ -96,6 +105,10 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 42))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString( "String Property level 1, complex level 1"))))); + firstLevelTwoKeyNav.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); + firstLevelTwoKeyNav.getProperties().add( + of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_BASE_PRIM_COMP_NAV))); final ODataInlineEntity firstLevelTwoKeyOneInline = of.newDeepInsertEntity(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE, firstLevelTwoKeyNav); entity.addLink(firstLevelTwoKeyOneInline); @@ -107,7 +120,11 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 421))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString( "String Property level 2, complex level 1"))))); - + secondLevelTwoKeyNav.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); + secondLevelTwoKeyNav.getProperties().add( + of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_BASE_PRIM_COMP_NAV))); + // Binding links secondLevelTwoKeyNav.addLink(of.newEntityNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE, client.newURIBuilder( SERVICE_URI).appendEntitySetSegment(ES_TWO_KEY_NAV).appendKeySegment(new LinkedHashMap<String, Object>() { @@ -129,14 +146,22 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 431))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString( "String Property level 3, complex level 1"))))); - + thirdLevelTwoKeyNavMany1.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); + thirdLevelTwoKeyNavMany1.getProperties().add( + of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_BASE_PRIM_COMP_NAV))); + final ODataEntity thirdLevelTwoKeyNavMany2 = of.newEntity(ET_TWO_KEY_NAV); thirdLevelTwoKeyNavMany2.getProperties().add( of.newComplexProperty(PROPERTY_COMP_TWO_PRIM, of.newComplexValue(CT_TWO_PRIM) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 432))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString( "String Property level 3, complex level 1"))))); - + thirdLevelTwoKeyNavMany2.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); + thirdLevelTwoKeyNavMany2.getProperties().add( + of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_BASE_PRIM_COMP_NAV))); + final ODataEntitySet entitySetThirdLevelTwoKeyNavMany = of.newEntitySet(); entitySetThirdLevelTwoKeyNavMany.getEntities().add(thirdLevelTwoKeyNavMany1); entitySetThirdLevelTwoKeyNavMany.getEntities().add(thirdLevelTwoKeyNavMany2); @@ -150,7 +175,11 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 422))) .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString( "String Property level 1, complex level 1"))))); - + firstLevelTwoKeyNavMany1.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); + firstLevelTwoKeyNavMany1.getProperties().add( + of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_BASE_PRIM_COMP_NAV))); + final ODataEntitySet entitySetfirstLevelTwoKeyNavMany = of.newEntitySet(); entitySetfirstLevelTwoKeyNavMany.getEntities().add(firstLevelTwoKeyNavMany1); entity.addLink(of.newDeepInsertEntitySet(NAV_PROPERTY_ET_TWO_KEY_NAV_MANY, @@ -172,7 +201,8 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { resultEntityFirstLevel.getNavigationLink(NAV_PROPERTY_ET_TWO_KEY_NAV_ONE).asInlineEntity().getEntity(); assertEquals(421, resultEntitySecondLevel.getProperty(PROPERTY_COMP_TWO_PRIM).getComplexValue().get(PROPERTY_INT16) .getPrimitiveValue().toValue()); - assertEquals("String Property level 2, complex level 1", resultEntitySecondLevel.getProperty(PROPERTY_COMP_TWO_PRIM) + assertEquals("String Property level 2, complex level 1", resultEntitySecondLevel + .getProperty(PROPERTY_COMP_TWO_PRIM) .getComplexValue().get(PROPERTY_STRING) .getPrimitiveValue().toValue()); @@ -198,7 +228,7 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { assertEquals("String Property level 1, complex level 1", firstLevelEntitySetNavMany.getEntities().get(0) .getProperty(PROPERTY_COMP_TWO_PRIM).getComplexValue().get(PROPERTY_STRING).getPrimitiveValue().toValue()); } - + @Test public void testSimpleDeepInsert() throws EdmPrimitiveTypeException { final ODataClient client = getClient(); @@ -234,6 +264,8 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 43))); inlineEntitySingle.getProperties() .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString("43"))); + inlineEntitySingle.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); inlineEntitySingle.getProperties() .add(of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_PRIM_COMP) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 431))))); @@ -253,6 +285,8 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { inlineEntityCol1.getProperties() .add(of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_PRIM_COMP) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 441))))); + inlineEntityCol1.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); inlineEntityCol1.getProperties() .add(of.newComplexProperty(PROPERTY_COMP_TWO_PRIM, of.newComplexValue(CT_TWO_PRIM) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 442))) @@ -266,6 +300,8 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { inlineEntityCol2.getProperties() .add(of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_PRIM_COMP) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 451))))); + inlineEntityCol2.getProperties().add( + of.newComplexProperty(PROPERTY_COMP, of.newComplexValue(CT_PRIM_COMP))); inlineEntityCol2.getProperties() .add(of.newComplexProperty(PROPERTY_COMP_TWO_PRIM, of.newComplexValue(CT_TWO_PRIM) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 452))) @@ -412,6 +448,18 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildString("42"))) .add(of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_NAV_FIVE_PROP) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder().buildInt16((short) 42))))))); + entity.addLink(of.newEntityNavigationLink("NavPropertyETTwoKeyNavOne", + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 1L; + + { + put(PROPERTY_INT16, 1); + put(PROPERTY_STRING, "1"); + } + }) + .build())); // Prepare inline entity(EntitySet: ESKeyNav, Type: ETKeyNav) final ODataEntity innerEntity = of.newEntity(ET_KEY_NAV); @@ -436,7 +484,19 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .add(of.newComplexProperty(PROPERTY_COMP_NAV, of.newComplexValue(CT_NAV_FIVE_PROP) .add(of.newPrimitiveProperty(PROPERTY_INT16, of.newPrimitiveValueBuilder() .buildInt16((short) 431))))))); - + innerEntity.addLink(of.newEntityNavigationLink("NavPropertyETTwoKeyNavOne", + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 1L; + + { + put(PROPERTY_INT16, 1); + put(PROPERTY_STRING, "1"); + } + }) + .build())); + ODataInlineEntity inlineEntity = of.newDeepInsertEntity(NAV_PROPERTY_ET_KEY_NAV_ONE, innerEntity); entity.addLink(inlineEntity); @@ -475,6 +535,108 @@ public class DeepInsertITCase extends AbstractBaseTestITCase { .getPrimitiveValue().toValue()); } + @Test + public void testConsistency() throws EdmPrimitiveTypeException { + final EdmEnabledODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final ODataObjectFactory of = client.getObjectFactory(); + final String cookie = getCookie(); + + // Do not set PropertyString(Nullable=false) + final ODataEntity entity = of.newEntity(ET_KEY_NAV); + entity.getProperties().add( + of.newCollectionProperty(COL_PROPERTY_STRING, + of.newCollectionValue(EDM_STRING).add( + of.newPrimitiveValueBuilder().buildString("Test")))); + + final URI targetURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV).build(); + + try { + ODataEntityCreateRequest<ODataEntity> request = client.getCUDRequestFactory() + .getEntityCreateRequest(targetURI, entity); + request.addCustomHeader(HttpHeader.COOKIE, cookie); + request.execute(); + fail("Expecting bad request"); + } catch (ODataClientErrorException e) { + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode()); + } + + // Entity must not be created + validateSet(targetURI, cookie, (short) 1, (short) 2, (short) 3); + } + + @Test + public void testInvalidType() throws EdmPrimitiveTypeException { + final EdmEnabledODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final ODataObjectFactory of = client.getObjectFactory(); + final String cookie = getCookie(); + + final ODataEntity entity = of.newEntity(ET_KEY_NAV); + entity.getProperties().add(of.newPrimitiveProperty(PROPERTY_STRING, of.newPrimitiveValueBuilder().buildInt32(1))); + final URI targetURI = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV).build(); + + try { + ODataEntityCreateRequest<ODataEntity> request = client.getCUDRequestFactory() + .getEntityCreateRequest(targetURI, entity); + request.addCustomHeader(HttpHeader.COOKIE, cookie); + request.execute(); + } catch (ODataClientErrorException e) { + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode()); + } + + validateSet(targetURI, cookie, (short) 1, (short) 2, (short) 3); + + entity.getProperties().add( + of.newCollectionProperty(PROPERTY_STRING, + of.newCollectionValue(EDM_STRING).add( + of.newPrimitiveValueBuilder().buildString("Test")))); + + try { + ODataEntityCreateRequest<ODataEntity> request = client.getCUDRequestFactory() + .getEntityCreateRequest(targetURI, entity); + request.addCustomHeader(HttpHeader.COOKIE, cookie); + request.execute(); + } catch (ODataClientErrorException e) { + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), e.getStatusLine().getStatusCode()); + } + + validateSet(targetURI, cookie, (short) 1, (short) 2, (short) 3); + } + + private String getCookie() { + final EdmEnabledODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final ODataRetrieveResponse<ODataEntitySet> response = client.getRetrieveRequestFactory() + .getEntitySetRequest(client.newURIBuilder(SERVICE_URI).appendEntitySetSegment(ES_KEY_NAV).build()) + .execute(); + + return response.getHeader(HttpHeader.SET_COOKIE).iterator().next(); + } + + private void validateSet(final URI uri, final String cookie, final short... keys) throws EdmPrimitiveTypeException { + final EdmEnabledODataClient client = ODataClientFactory.getEdmEnabledClient(SERVICE_URI); + final ODataEntitySetRequest<ODataEntitySet> request = client.getRetrieveRequestFactory() + .getEntitySetRequest(uri); + request.addCustomHeader(HttpHeader.COOKIE, cookie); + final ODataRetrieveResponse<ODataEntitySet> response = request.execute(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertEquals(3, response.getBody().getEntities().size()); + + for (final ODataEntity responseEntity : response.getBody().getEntities()) { + short propertyInt16 = responseEntity.getProperty(PROPERTY_INT16).getPrimitiveValue().toCastValue(Short.class); + + boolean found = false; + for (int i = 0; i < keys.length && !found; i++) { + if (propertyInt16 == keys[i]) { + found = true; + } + } + + if (!found) { + fail("Invalid key " + propertyInt16); + } + } + } + @Override protected ODataClient getClient() { ODataClient odata = ODataClientFactory.getClient(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java index 8cb249d..16529dd 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/FilterSystemQueryITCase.java @@ -21,6 +21,7 @@ package org.apache.olingo.fit.tecsvc.client; import static org.junit.Assert.assertEquals; import java.net.URI; +import java.util.LinkedHashMap; import org.apache.olingo.client.api.ODataClient; import org.apache.olingo.client.api.communication.ODataClientErrorException; @@ -289,7 +290,12 @@ public class FilterSystemQueryITCase extends AbstractBaseTestITCase { entity.getProperties().add( objectFactory.newPrimitiveProperty("PropertyInt16", objectFactory.newPrimitiveValueBuilder() .buildInt16((short) 1))); - + entity.addLink(objectFactory.newEntityNavigationLink("NavPropertyETTwoPrimOne", + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim") + .appendKeySegment(32766) + .build())); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESAllPrim").build(); ODataEntityCreateResponse<ODataEntity> createResponse = client.getCUDRequestFactory().getEntityCreateRequest(uri, entity).execute(); @@ -921,7 +927,7 @@ public class FilterSystemQueryITCase extends AbstractBaseTestITCase { @Test public void testNullComplexProperty() { // Create a new entry.The complex property PropertyCompComp is set to null. So the structure of the property - // is still there, but filled is null value (primitive types) + // is still there, but filled is null values (primitive types) // We define a filter, which returns all entry where PropertyCompComp/PropertyComp/PropertyInt16 is equals to 1 final ODataClient client = getClient(); @@ -948,7 +954,20 @@ public class FilterSystemQueryITCase extends AbstractBaseTestITCase { .add(factory.newPrimitiveProperty( "PropertyString", factory.newPrimitiveValueBuilder().buildString("Test2"))))); - + + newEntity.addLink(factory.newEntityNavigationLink("NavPropertyETTwoKeyNavOne", + client.newURIBuilder(SERVICE_URI) + .appendEntitySetSegment(ES_TWO_KEY_NAV) + .appendKeySegment(new LinkedHashMap<String, Object>() { + private static final long serialVersionUID = 1L; + + { + put("PropertyInt16", 1); + put("PropertyString", "1"); + } + }) + .build())); + final URI uri = client.newURIBuilder(SERVICE_URI).appendEntitySetSegment("ESKeyNav").build(); ODataEntityCreateRequest<ODataEntity> request = client.getCUDRequestFactory().getEntityCreateRequest(uri, newEntity); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/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 96f0cd7..d47aa46 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 @@ -6,9 +6,9 @@ * 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 @@ -152,7 +152,6 @@ public class DataProvider { private Map<String, Object> findFreeComposedKey(final List<Entity> entities, final EdmEntityType entityType) throws DataProviderException { // Weak key construction - // 3e ⬠entity: (V k ⬠keys: k !⬠e.ki) => e.(k1, k2, k3) !⬠entitySet final HashMap<String, Object> keys = new HashMap<String, Object>(); for (final String keyName : entityType.getKeyPredicateNames()) { final EdmType type = entityType.getProperty(keyName).getType(); @@ -243,15 +242,15 @@ public class DataProvider { patch); } } - - // For insert operations collection navigation property bind operations and deep insert operations can be combined. + + // For insert operations collection navigation property bind operations and deep insert operations can be combined. // In this case, the bind operations MUST appear before the deep insert operations in the payload. // => Apply bindings first final boolean navigationBindingsAvailable = !changedEntity.getNavigationBindings().isEmpty(); if (navigationBindingsAvailable) { applyNavigationBinding(rawBaseUri, edmEntitySet, entity, changedEntity.getNavigationBindings()); } - + // Deep insert (only if not an update) if (isInsert) { handleDeepInsert(rawBaseUri, edmEntitySet, entity, changedEntity); @@ -311,10 +310,6 @@ public class DataProvider { .getKeyPredicatesFromEntityLink(edm, bindingLink, rawBaseUri); final Entity entity = read(edmEntitySetTarget, keys); - if (entity == null) { - throw new DataProviderException("Entity " + bindingLink + " not found", HttpStatusCode.NOT_FOUND); - } - return entity; } catch (DeserializerException e) { throw new DataProviderException("Invalid entity binding link", HttpStatusCode.BAD_REQUEST); @@ -400,9 +395,6 @@ public class DataProvider { if (edmProperty.isPrimitive()) { if (newProperty != null || !patch) { final Object value = newProperty == null ? null : newProperty.getValue(); - if (value == null && !edmProperty.isNullable()) { - throw new DataProviderException("Cannot null non-nullable property!", HttpStatusCode.BAD_REQUEST); - } property.setValue(property.getValueType(), value); } } else if (edmProperty.isCollection()) { @@ -440,7 +432,7 @@ public class DataProvider { private ComplexValue createComplexValue(final EdmProperty edmProperty, final ComplexValue complexValue, final boolean patch) throws DataProviderException { final ComplexValueImpl result = new ComplexValueImpl(); - final EdmComplexType edmType = (EdmComplexType) edmProperty.getType(); + final EdmComplexType edmType = (EdmComplexType) edmProperty.getType(); final List<Property> givenProperties = complexValue.getValue(); // Create ALL properties, even if no value is given. Check if null is allowed @@ -454,12 +446,10 @@ public class DataProvider { updateProperty(innerEdmProperty, newProperty, currentProperty, patch); } else { if (innerEdmProperty.isNullable()) { - // Check complex properties ... may be null is not allowed - if(edmProperty.getType().getKind() == EdmTypeKind.COMPLEX) { + // Check complex properties ... maybe null is not allowed + if (edmProperty.getType().getKind() == EdmTypeKind.COMPLEX) { updateProperty(innerEdmProperty, newProperty, null, patch); } - } else { - throw new DataProviderException("Null is not allowed for property " + edmProperty.getName()); } } } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java new file mode 100644 index 0000000..113b252 --- /dev/null +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java @@ -0,0 +1,255 @@ +/* + * 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.server.tecsvc.data; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.olingo.commons.api.data.ComplexValue; +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.data.Linked; +import org.apache.olingo.commons.api.data.Property; +import org.apache.olingo.commons.api.edm.Edm; +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.EdmEntityType; +import org.apache.olingo.commons.api.edm.EdmNavigationProperty; +import org.apache.olingo.commons.api.edm.EdmProperty; +import org.apache.olingo.commons.api.edm.EdmStructuredType; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.server.api.deserializer.DeserializerException; +import org.apache.olingo.server.api.uri.UriHelper; +import org.apache.olingo.server.api.uri.UriParameter; +import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException; + +public class RequestValidator { + private DataProvider provider; + private boolean isInsert; + private UriHelper uriHelper; + private Edm edm; + private String rawServiceRoot; + + public RequestValidator(final DataProvider provider, final boolean isInsert, final UriHelper uriHelper, + final Edm edm, final String rawServiceRoot) { + this.provider = provider; + this.isInsert = isInsert; + this.uriHelper = uriHelper; + this.edm = edm; + this.rawServiceRoot = rawServiceRoot; + } + + public void validate(final EdmBindingTarget edmBindingTarget, final Entity entity) + throws DataProviderException { + final List<String> path = new ArrayList<String>(); + + validateEntitySetProperties(entity.getProperties(), edmBindingTarget, edmBindingTarget.getEntityType(), path); + validateNavigationProperties(entity, edmBindingTarget, edmBindingTarget.getEntityType(), path); + } + + private void validateNavigationProperties(final Linked entity, final EdmBindingTarget edmBindingTarget, + final EdmStructuredType edmType, final List<String> path) throws DataProviderException { + for (final String navPropertyName : edmType.getNavigationPropertyNames()) { + final EdmNavigationProperty edmProperty = edmType.getNavigationProperty(navPropertyName); + if(entity == null && !edmProperty.isNullable()) { + throw new DataProviderException("Navigation property " + navPropertyName + " must not be null", + HttpStatusCode.BAD_REQUEST); + } else if(entity != null) { + final Link navigationBinding = entity.getNavigationBinding(navPropertyName); + final Link navigationLink = entity.getNavigationLink(navPropertyName); + final List<String> newPath = new ArrayList<String>(path); + newPath.add(edmProperty.getName()); + final EdmBindingTarget target = edmBindingTarget.getRelatedBindingTarget(buildPath(newPath)); + + final ValidatioResult bindingResult = validateBinding(navigationBinding, edmProperty, target); + final ValidatioResult linkResult = validateNavigationLink(navigationLink, + edmProperty, + target); + + if (( isInsert && !edmProperty.isNullable() && (bindingResult != ValidatioResult.FOUND + && linkResult != ValidatioResult.FOUND)) + || (!isInsert && !edmProperty.isNullable() && linkResult == ValidatioResult.EMPTY)) { + throw new DataProviderException("Navigation property " + navPropertyName + " must not be null", + HttpStatusCode.BAD_REQUEST); + } + } + } + } + + private String buildPath(final List<String> path) { + final StringBuilder builder = new StringBuilder(); + + for(final String segment : path) { + if(builder.length() > 0) { + builder.append("/"); + } + + builder.append(segment); + } + + return builder.toString(); + } + + private ValidatioResult validateBinding(final Link navigationBindung, final EdmNavigationProperty edmProperty, + final EdmBindingTarget edmBindingTarget) throws DataProviderException { + if(navigationBindung == null) { + return ValidatioResult.NOT_FOUND; + } + + if (edmProperty.isCollection()) { + if(navigationBindung.getBindingLinks().size() == 0) { + return ValidatioResult.EMPTY; + } + + for (final String bindingLink : navigationBindung.getBindingLinks()) { + validateLink(bindingLink, edmBindingTarget); + } + } else { + if(navigationBindung.getBindingLink() == null) { + return ValidatioResult.EMPTY; + } + + validateLink(navigationBindung.getBindingLink(), edmBindingTarget); + } + + return ValidatioResult.FOUND; + } + + private ValidatioResult validateNavigationLink(final Link navigationLink, final EdmNavigationProperty edmProperty, + final EdmBindingTarget edmBindingTarget) throws DataProviderException { + if(navigationLink == null) { + return ValidatioResult.NOT_FOUND; + } + + if(edmProperty.isCollection()) { + final EntitySet inlineEntitySet = navigationLink.getInlineEntitySet(); + if(!isInsert && inlineEntitySet.getEntities().size() > 0) { + throw new DataProvider.DataProviderException("Deep update is not allowed", HttpStatusCode.BAD_REQUEST); + } else { + for(final Entity entity : navigationLink.getInlineEntitySet().getEntities()) { + validate(edmBindingTarget, entity); + } + } + } else { + final Entity inlineEntity = navigationLink.getInlineEntity(); + if(!isInsert && inlineEntity != null) { + throw new DataProvider.DataProviderException("Deep update is not allowed", HttpStatusCode.BAD_REQUEST); + } else if(inlineEntity != null) { + validate(edmBindingTarget, navigationLink.getInlineEntity()); + } + } + + return ValidatioResult.FOUND; + } + + private void validateLink(final String bindingLink, final EdmBindingTarget edmBindungTarget) + throws DataProviderException { + try { + final List<UriParameter> keys = uriHelper.getKeyPredicatesFromEntityLink(edm, bindingLink, rawServiceRoot); + final Entity entity = provider.read((EdmEntitySet)edmBindungTarget, keys); + + if (entity == null) { + throw new DataProviderException("Entity not found", HttpStatusCode.NOT_FOUND); + } + } catch (DeserializerException e) { + throw new DataProviderException("Invalid binding link", HttpStatusCode.BAD_REQUEST); + } + } + + private void validateEntitySetProperties(final List<Property> properties, final EdmBindingTarget edmBindingTarget, + final EdmEntityType edmType, final List<String> path) throws DataProviderException { + validateProperties(properties, edmBindingTarget, edmType, edmType.getKeyPredicateNames(), path); + } + + private void validateProperties(final List<Property> properties, final EdmBindingTarget edmBingingTarget, + final EdmStructuredType edmType, final List<String> keyPredicateNames, final List<String> path) + throws DataProviderException { + + for(final String propertyName : edmType.getPropertyNames()) { + final EdmProperty edmProperty = (EdmProperty) edmType.getProperty(propertyName); + + // Ignore key properties, they are set automatically + if(!keyPredicateNames.contains(propertyName)) { + final Property property = getProperty(properties, propertyName); + + // Check if all "not nullable" properties are set + if(!edmProperty.isNullable()) { + if((property != null && property.isNull()) // Update,insert; Property is explicit set to null + || (isInsert && property == null) ) { // Insert; Property not provided + throw new DataProviderException("Property " + propertyName + " must not be null", + HttpStatusCode.BAD_REQUEST); + } + } + + // Validate property value + validatePropertyValue(property, edmProperty, edmBingingTarget, path); + } + } + } + + private void validatePropertyValue(final Property property, final EdmProperty edmProperty, + final EdmBindingTarget edmBindingTarget, final List<String> path) throws DataProviderException { + + final ArrayList<String> newPath = new ArrayList<String>(path); + newPath.add(edmProperty.getName()); + + if (edmProperty.isCollection()) { + if (edmProperty.getType() instanceof EdmComplexType && property != null) { + for (final Object value : property.asCollection()) { + validateComplexValue((ComplexValue) value, + edmBindingTarget, + (EdmComplexType) edmProperty.getType(), + newPath); + } + } + } else if (edmProperty.getType() instanceof EdmComplexType) { + validateComplexValue((property == null) ? null : property.asComplex(), + edmBindingTarget, + (EdmComplexType) edmProperty.getType(), + newPath); + } + } + + private void validateComplexValue(final ComplexValue value, final EdmBindingTarget edmBindingTarget, + final EdmComplexType edmType, final List<String> path) throws DataProviderException { + // The whole complex property can be nullable but nested primitive, navigation properties can be not nullable + final List<Property> properties = (value == null) ? new ArrayList<Property>() : value.getValue(); + + validateProperties(properties, edmBindingTarget, edmType, new ArrayList<String>(0), path); + validateNavigationProperties(value, edmBindingTarget, edmType, path); + } + + private Property getProperty(final List<Property> properties, final String name) { + for(final Property property : properties) { + if(property.getName().equals(name)) { + return property; + } + } + + return null; + } + + private static enum ValidatioResult { + FOUND, + NOT_FOUND, + EMPTY + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/583c4bd0/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 e105a2f..ed120b9 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 @@ -60,6 +60,7 @@ import org.apache.olingo.server.api.uri.UriResourceFunction; 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; +import org.apache.olingo.server.tecsvc.data.RequestValidator; import org.apache.olingo.server.tecsvc.processor.queryoptions.ExpandSystemQueryOptionHandler; import org.apache.olingo.server.tecsvc.processor.queryoptions.options.CountHandler; import org.apache.olingo.server.tecsvc.processor.queryoptions.options.FilterHandler; @@ -230,17 +231,25 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0); final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet(); final EdmEntityType edmEntityType = edmEntitySet.getEntityType(); - - Entity entity = dataProvider.create(edmEntitySet); + + final Entity entity; ExpandOption expand = null; if (edmEntityType.hasStream()) { // called from createMediaEntity(...), not directly + entity = dataProvider.create(edmEntitySet); dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), requestFormat.toContentTypeString()); } else { final DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .entity(request.getBody(), edmEntityType); - dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, - deserializerResult.getEntity(), false, true); + new RequestValidator(dataProvider, + true, // Insert + odata.createUriHelper(), + serviceMetadata.getEdm(), + request.getRawBaseUri() + ).validate(edmEntitySet, deserializerResult.getEntity()); + + entity = dataProvider.create(edmEntitySet); + dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, true); expand = deserializerResult.getExpandTree(); } @@ -265,8 +274,16 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); Entity entity = readEntity(uriInfo); checkRequestFormat(requestFormat); - ODataDeserializer deserializer = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)); + final ODataDeserializer deserializer = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)); final Entity changedEntity = deserializer.entity(request.getBody(), edmEntitySet.getEntityType()).getEntity(); + + new RequestValidator(dataProvider, + false, // Update + odata.createUriHelper(), + serviceMetadata.getEdm(), + request.getRawBaseUri() + ).validate(edmEntitySet, changedEntity); + dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity, request.getMethod() == HttpMethod.PATCH, false); response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
