improved server support for property deletion

Change-Id: I1b79ab735bdf5e020970096bbea51a2af6a13bbc

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Klaus Straubinger 2014-12-18 10:53:56 +01:00 committed by Christian Amend
parent 6d9ac226df
commit 56cc9bb6ca
5 changed files with 84 additions and 18 deletions

View File

@ -22,6 +22,7 @@ import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.net.URI;
@ -112,6 +113,27 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase {
}
}
@Test
public void deletePrimitiveCollection() throws Exception {
final URI uri = getClient().newURIBuilder(SERVICE_URI)
.appendEntitySetSegment("ESMixPrimCollComp").appendKeySegment(7).appendPropertySegment("CollPropertyString")
.build();
final ODataDeleteResponse response = getClient().getCUDRequestFactory().getDeleteRequest(uri).execute();
assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode());
// Check that the property is not gone but empty now.
// This check has to be in the same session in order to access the same data provider.
ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()
.getPropertyRequest(uri);
request.addCustomHeader(HttpHeader.COOKIE, response.getHeader(HttpHeader.SET_COOKIE).iterator().next());
final ODataRetrieveResponse<ODataProperty> propertyResponse = request.execute();
assertEquals(HttpStatusCode.OK.getStatusCode(), propertyResponse.getStatusCode());
final ODataProperty property = propertyResponse.getBody();
assertNotNull(property);
assertNotNull(property.getCollectionValue());
assertTrue(property.getCollectionValue().isEmpty());
}
@Test
public void readComplexProperty() throws Exception {
ODataPropertyRequest<ODataProperty> request = getClient().getRetrieveRequestFactory()

View File

@ -43,6 +43,7 @@ import org.apache.olingo.server.api.uri.UriResourceFunction;
import org.apache.olingo.server.api.uri.UriResourceKind;
import org.apache.olingo.server.api.uri.UriResourceNavigation;
import org.apache.olingo.server.api.uri.UriResourcePartTyped;
import org.apache.olingo.server.api.uri.UriResourceProperty;
import org.apache.olingo.server.api.uri.UriResourceSingleton;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOption;
import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
@ -175,6 +176,7 @@ public class UriValidator {
validateForHttpMethod(uriInfo, httpMethod);
validateQueryOptions(uriInfo);
validateKeyPredicates(uriInfo);
validatePropertyOperations(uriInfo, httpMethod);
}
private ColumnIndex colIndex(final SystemQueryOptionKind queryOptionKind) throws UriValidationException {
@ -667,4 +669,26 @@ public class UriValidator {
}
}
}
private void validatePropertyOperations(final UriInfo uriInfo, final HttpMethod method)
throws UriValidationException {
final List<UriResource> parts = uriInfo.getUriResourceParts();
final UriResource last = parts.size() > 0 ? parts.get(parts.size() - 1) : null;
final UriResource previous = parts.size() > 1 ? parts.get(parts.size() - 2) : null;
if (last != null
&& (last.getKind() == UriResourceKind.primitiveProperty
|| last.getKind() == UriResourceKind.complexProperty
|| last.getKind() == UriResourceKind.value && previous.getKind() == UriResourceKind.primitiveProperty)) {
final EdmProperty property = ((UriResourceProperty)
(last.getKind() == UriResourceKind.value ? previous : last)).getProperty();
if (method == HttpMethod.PATCH && property.isCollection()) {
throw new UriValidationException("Attempt to patch collection property.",
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD, method.toString());
}
if (method == HttpMethod.DELETE && property.isNullable() != null && !property.isNullable()) {
throw new UriValidationException("Attempt to delete non-nullable property.",
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD, method.toString());
}
}
}
}

View File

@ -18,6 +18,7 @@
*/
package org.apache.olingo.server.tecsvc.processor;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@ -84,7 +85,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
public void updatePrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new UnsupportedOperationException("Actual not yet supported");
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
@ -103,7 +105,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
public void updatePrimitiveCollection(final ODataRequest request, final ODataResponse response,
final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new UnsupportedOperationException("Actual not yet supported");
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
@ -122,7 +125,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
public void updateComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new UnsupportedOperationException("Actual not yet supported");
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
@ -141,7 +145,8 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
public void updateComplexCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
final ContentType requestFormat, final ContentType responseFormat)
throws ODataApplicationException, DeserializerException, SerializerException {
throw new UnsupportedOperationException("Actual not yet supported");
throw new ODataApplicationException("Not supported yet.",
HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
}
@Override
@ -226,7 +231,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor
final Property property = getPropertyData(resourceEntitySet, path);
if (edmProperty.isNullable() == null || edmProperty.isNullable()) {
property.setValue(property.getValueType(), null);
property.setValue(property.getValueType(), edmProperty.isCollection() ? Collections.emptyList() : null);
response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
} else {
throw new ODataApplicationException("Not nullable.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT);

View File

@ -310,7 +310,7 @@ public class ODataHandlerTest {
@Test
public void dispatchPrimitiveProperty() throws Exception {
final String uri = "ESAllPrim(0)/PropertyInt16";
final String uri = "ESAllPrim(0)/PropertyString";
final PrimitiveProcessor processor = mock(PrimitiveProcessor.class);
dispatch(HttpMethod.GET, uri, processor);
@ -325,7 +325,7 @@ public class ODataHandlerTest {
@Test
public void dispatchPrimitivePropertyValue() throws Exception {
final String uri = "ESAllPrim(0)/PropertyInt16/$value";
final String uri = "ESAllPrim(0)/PropertyString/$value";
final PrimitiveValueProcessor processor = mock(PrimitiveValueProcessor.class);
dispatch(HttpMethod.GET, uri, processor);

View File

@ -346,20 +346,23 @@ public class UriValidatorTest {
public void checkNonValidSystemQueryOption() throws Exception {
for (final String[] uriArray : urisWithNonValidSystemQueryOptions) {
final String[] uri = constructUri(uriArray);
try {
new UriValidator().validate(
new Parser().parseUri(uri[0], uri[1], null, edm),
HttpMethod.GET);
fail("Validation Exception not thrown: " + uri[0] + '?' + uri[1]);
} catch (final UriParserException e) {
fail("Wrong Exception thrown: " + uri[0] + '?' + uri[1]);
} catch (final UriValidationException e) {
assertEquals(UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED,
e.getMessageKey());
}
validateWrong(uri[0], uri[1], HttpMethod.GET,
UriValidationException.MessageKeys.SYSTEM_QUERY_OPTION_NOT_ALLOWED);
}
}
@Test
public void propertyOperations() throws Exception {
validateWrong(URI_PROPERTY_PRIMITIVE_COLLECTION, null, HttpMethod.PATCH,
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD);
validateWrong(URI_PROPERTY_COMPLEX_COLLECTION, null, HttpMethod.PATCH,
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD);
validateWrong("ESKeyNav(1)/PropertyString", null, HttpMethod.DELETE,
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD);
validateWrong("ESKeyNav(1)/PropertyString/$value", null, HttpMethod.DELETE,
UriValidationException.MessageKeys.UNSUPPORTED_HTTP_METHOD);
}
private String[] constructUri(final String[] uriParameterArray) {
final String path = uriParameterArray[0];
String query = "";
@ -371,4 +374,16 @@ public class UriValidatorTest {
}
return new String[] { path, query };
}
private void validateWrong(final String path, final String query, final HttpMethod method,
final UriValidationException.MessageKeys expectedMessageKey) {
try {
new UriValidator().validate(new Parser().parseUri(path, query, null, edm), method);
fail("Validation Exception not thrown: " + method + ' ' + path + '?' + query);
} catch (final UriParserException e) {
fail("Wrong Exception thrown: " + method + ' ' + path + '?' + query);
} catch (final UriValidationException e) {
assertEquals(expectedMessageKey, e.getMessageKey());
}
}
}