[OLINGO-545] TecSvc: Request validation added

This commit is contained in:
Christian Holzer 2015-04-06 08:25:00 +02:00
parent 97a0178432
commit 583c4bd078
7 changed files with 546 additions and 32 deletions

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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());
}
}
}

View File

@ -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
}
}

View File

@ -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());