Repository: olingo-odata4 Updated Branches: refs/heads/master ea89f7213 -> 7ad5b0fb5
[OLINGO-663] conditional handling in technical service, part 2 Signed-off-by: Christian Amend <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/7ad5b0fb Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/7ad5b0fb Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/7ad5b0fb Branch: refs/heads/master Commit: 7ad5b0fb54dd3f52247716afb32b2e8192fe750c Parents: ea89f72 Author: Klaus Straubinger <[email protected]> Authored: Thu May 28 12:35:41 2015 +0200 Committer: Christian Amend <[email protected]> Committed: Thu May 28 15:12:31 2015 +0200 ---------------------------------------------------------------------- .../fit/tecsvc/client/ConditionalITCase.java | 156 ++++++++-- .../olingo/fit/tecsvc/client/MediaITCase.java | 6 +- .../tecsvc/client/PrimitiveComplexITCase.java | 121 +++++++- .../olingo/server/api/EtagInformation.java | 4 +- .../olingo/server/tecsvc/ETagSupport.java | 34 +++ .../olingo/server/tecsvc/TechnicalServlet.java | 7 +- .../olingo/server/tecsvc/data/DataProvider.java | 10 +- .../processor/TechnicalEntityProcessor.java | 97 +++--- .../TechnicalPrimitiveComplexProcessor.java | 294 ++++++++++++------- .../tecsvc/processor/TechnicalProcessor.java | 47 ++- 10 files changed, 584 insertions(+), 192 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ConditionalITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ConditionalITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ConditionalITCase.java index 2dcbc26..796c2c4 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ConditionalITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ConditionalITCase.java @@ -18,20 +18,35 @@ */ package org.apache.olingo.fit.tecsvc.client; +import static org.hamcrest.CoreMatchers.anyOf; 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.fail; +import java.net.URI; + +import org.apache.commons.io.IOUtils; import org.apache.olingo.client.api.ODataClient; import org.apache.olingo.client.api.communication.ODataClientErrorException; +import org.apache.olingo.client.api.communication.request.ODataBasicRequest; +import org.apache.olingo.client.api.communication.request.cud.ODataDeleteRequest; +import org.apache.olingo.client.api.communication.request.cud.ODataEntityUpdateRequest; +import org.apache.olingo.client.api.communication.request.cud.ODataPropertyUpdateRequest; +import org.apache.olingo.client.api.communication.request.cud.UpdateType; import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; +import org.apache.olingo.client.api.communication.request.retrieve.ODataValueRequest; +import org.apache.olingo.client.api.communication.request.streamed.ODataMediaEntityUpdateRequest; +import org.apache.olingo.client.api.communication.response.ODataDeleteResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; import org.apache.olingo.client.api.domain.ClientEntity; +import org.apache.olingo.client.api.domain.ClientProperty; +import org.apache.olingo.client.api.http.HttpClientException; import org.apache.olingo.client.core.ODataClientFactory; -import org.apache.olingo.commons.api.ODataError; import org.apache.olingo.commons.api.format.ODataFormat; +import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.fit.AbstractBaseTestITCase; import org.apache.olingo.fit.tecsvc.TecSvcConst; @@ -39,31 +54,27 @@ import org.junit.Test; public final class ConditionalITCase extends AbstractBaseTestITCase { + private final ODataClient client = getClient(); + + private final URI uriEntity = client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESCompAllPrim").appendKeySegment(0).build(); + private final URI uriProperty = client.newURIBuilder(uriEntity.toASCIIString()) + .appendPropertySegment("PropertyComp").appendPropertySegment("PropertyDuration").build(); + private final URI uriPropertyValue = client.newURIBuilder(uriProperty.toASCIIString()).appendValueSegment().build(); + private final URI uriMedia = client.newURIBuilder(TecSvcConst.BASE_URI) + .appendEntitySetSegment("ESMedia").appendKeySegment(1).appendValueSegment().build(); + @Test public void readWithWrongIfMatch() throws Exception { - final ODataClient client = getClient(); - ODataEntityRequest<ClientEntity> request = client.getRetrieveRequestFactory().getEntityRequest( - client.newURIBuilder(TecSvcConst.BASE_URI) - .appendEntitySetSegment("ESCompAllPrim").appendKeySegment(0).build()); + ODataEntityRequest<ClientEntity> request = client.getRetrieveRequestFactory().getEntityRequest(uriEntity); request.setIfMatch("W/\"1\""); assertNotNull(request); - - try { - request.execute(); - fail("Expected Exception not thrown!"); - } catch (final ODataClientErrorException e) { - assertEquals(HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), e.getStatusLine().getStatusCode()); - final ODataError error = e.getODataError(); - assertThat(error.getMessage(), containsString("condition")); - } + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); } @Test public void readNotModified() throws Exception { - final ODataClient client = getClient(); - ODataEntityRequest<ClientEntity> request = client.getRetrieveRequestFactory().getEntityRequest( - client.newURIBuilder(TecSvcConst.BASE_URI) - .appendEntitySetSegment("ESCompAllPrim").appendKeySegment(0).build()); + ODataEntityRequest<ClientEntity> request = client.getRetrieveRequestFactory().getEntityRequest(uriEntity); request.setIfNoneMatch("W/\"0\""); assertNotNull(request); @@ -71,6 +82,115 @@ public final class ConditionalITCase extends AbstractBaseTestITCase { assertEquals(HttpStatusCode.NOT_MODIFIED.getStatusCode(), response.getStatusCode()); } + @Test + public void updateWithoutIfMatch() throws Exception { + executeAndExpectError( + client.getCUDRequestFactory().getEntityUpdateRequest( + uriEntity, UpdateType.PATCH, client.getObjectFactory().newEntity(null)), + HttpStatusCode.PRECONDITION_REQUIRED); + } + + @Test + public void updateWithWrongIfMatch() throws Exception { + ODataEntityUpdateRequest<ClientEntity> request = client.getCUDRequestFactory().getEntityUpdateRequest( + uriEntity, UpdateType.PATCH, client.getObjectFactory().newEntity(null)); + request.setIfMatch("W/\"1\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void updateMediaWithWrongIfMatch() throws Exception { + ODataMediaEntityUpdateRequest<ClientEntity> request = client.getCUDRequestFactory().getMediaEntityUpdateRequest( + uriMedia, IOUtils.toInputStream("ignored")); + request.setIfMatch("W/\"42\""); + + try { + request.payloadManager().getResponse(); + fail("Expected Exception not thrown!"); + } catch (final HttpClientException e) { + final ODataClientErrorException ex = (ODataClientErrorException) e.getCause().getCause(); + assertEquals(HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), ex.getStatusLine().getStatusCode()); + assertThat(ex.getODataError().getMessage(), containsString("condition")); + } + } + + @Test + public void deleteWithWrongIfMatch() throws Exception { + ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uriEntity); + request.setIfMatch("W/\"1\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void deleteMediaWithWrongIfMatch() throws Exception { + ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uriMedia); + request.setIfMatch("W/\"42\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void indirectEntityChange() throws Exception { + final String eTag = "W/\"0\""; + ODataDeleteRequest deleteRequest = client.getCUDRequestFactory().getDeleteRequest(uriProperty); + deleteRequest.setIfMatch(eTag); + final ODataDeleteResponse response = deleteRequest.execute(); + + ODataEntityUpdateRequest<ClientEntity> request = client.getCUDRequestFactory().getEntityUpdateRequest( + uriEntity, UpdateType.PATCH, client.getObjectFactory().newEntity(null)); + request.setIfMatch(eTag); + // This request has to be in the same session as the first in order to access the same data provider. + request.addCustomHeader(HttpHeader.COOKIE, response.getHeader(HttpHeader.SET_COOKIE).iterator().next()); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void readPropertyNotModified() throws Exception { + ODataPropertyRequest<ClientProperty> request = client.getRetrieveRequestFactory().getPropertyRequest(uriProperty); + request.setIfNoneMatch("W/\"0\""); + assertEquals(HttpStatusCode.NOT_MODIFIED.getStatusCode(), request.execute().getStatusCode()); + } + + @Test + public void readPropertyValueNotModified() throws Exception { + ODataValueRequest request = client.getRetrieveRequestFactory().getPropertyValueRequest(uriPropertyValue); + request.setIfNoneMatch("W/\"0\""); + assertEquals(HttpStatusCode.NOT_MODIFIED.getStatusCode(), request.execute().getStatusCode()); + } + + @Test + public void updatePropertyWithWrongIfMatch() throws Exception { + ODataPropertyUpdateRequest request = client.getCUDRequestFactory().getPropertyPrimitiveValueUpdateRequest( + uriProperty, + client.getObjectFactory().newPrimitiveProperty("PropertyDuration", + client.getObjectFactory().newPrimitiveValueBuilder().buildString("PT42S"))); + request.setIfMatch("W/\"1\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void deletePropertyWithWrongIfMatch() throws Exception { + ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uriProperty); + request.setIfMatch("W/\"1\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + @Test + public void deletePropertyValueWithWrongIfMatch() throws Exception { + ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uriPropertyValue); + request.setIfMatch("W/\"1\""); + executeAndExpectError(request, HttpStatusCode.PRECONDITION_FAILED); + } + + private void executeAndExpectError(ODataBasicRequest<?> request, final HttpStatusCode status) { + try { + request.execute(); + fail("Expected Exception not thrown!"); + } catch (final ODataClientErrorException e) { + assertEquals(status.getStatusCode(), e.getStatusLine().getStatusCode()); + assertThat(e.getODataError().getMessage(), anyOf(containsString("condition"), containsString("match"))); + } + } + @Override protected ODataClient getClient() { ODataClient odata = ODataClientFactory.getClient(); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java index e48f08c..3bd14c1 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/MediaITCase.java @@ -75,7 +75,8 @@ public final class MediaITCase extends AbstractBaseTestITCase { final ODataClient client = getClient(); final URI uri = client.newURIBuilder(TecSvcConst.BASE_URI) .appendEntitySetSegment("ESMedia").appendKeySegment(4).appendValueSegment().build(); - final ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uri); + ODataDeleteRequest request = client.getCUDRequestFactory().getDeleteRequest(uri); + request.setIfMatch("W/\"4\""); assertNotNull(request); final ODataDeleteResponse response = request.execute(); @@ -102,6 +103,7 @@ public final class MediaITCase extends AbstractBaseTestITCase { client.getCUDRequestFactory().getMediaEntityUpdateRequest(uri, IOUtils.toInputStream("just a test")); request.setContentType(ContentType.TEXT_PLAIN.toContentTypeString()); + request.setIfMatch("W/\"4\""); assertNotNull(request); final ODataMediaEntityUpdateResponse<ClientEntity> response = request.payloadManager().getResponse(); @@ -143,7 +145,7 @@ public final class MediaITCase extends AbstractBaseTestITCase { // This check has to be in the same session in order to access the same data provider. ODataMediaRequest mediaRequest = client.getRetrieveRequestFactory().getMediaRequest( client.newURIBuilder(TecSvcConst.BASE_URI).appendEntitySetSegment("ESMedia") - .appendKeySegment(5).appendValueSegment().build()); + .appendKeySegment(5).appendValueSegment().build()); mediaRequest.addCustomHeader(HttpHeader.COOKIE, response.getHeader(HttpHeader.SET_COOKIE).iterator().next()); ODataRetrieveResponse<InputStream> mediaResponse = mediaRequest.execute(); assertEquals(HttpStatusCode.OK.getStatusCode(), mediaResponse.getStatusCode()); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java ---------------------------------------------------------------------- diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java index 50ab97b..d71e6a0 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java @@ -20,23 +20,31 @@ package org.apache.olingo.fit.tecsvc.client; import static org.hamcrest.CoreMatchers.containsString; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; 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; +import java.util.Iterator; import org.apache.commons.io.IOUtils; 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; +import org.apache.olingo.client.api.communication.request.cud.ODataPropertyUpdateRequest; +import org.apache.olingo.client.api.communication.request.cud.UpdateType; import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest; import org.apache.olingo.client.api.communication.request.retrieve.ODataValueRequest; import org.apache.olingo.client.api.communication.response.ODataDeleteResponse; +import org.apache.olingo.client.api.communication.response.ODataPropertyUpdateResponse; import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse; +import org.apache.olingo.client.api.domain.ClientCollectionValue; +import org.apache.olingo.client.api.domain.ClientComplexValue; import org.apache.olingo.client.api.domain.ClientPrimitiveValue; import org.apache.olingo.client.api.domain.ClientProperty; +import org.apache.olingo.client.api.domain.ClientValue; import org.apache.olingo.client.core.ODataClientFactory; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; @@ -52,13 +60,12 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { @Test public void readSimpleProperty() throws Exception { - ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + final ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESTwoPrim") .appendKeySegment(32766) .appendPropertySegment("PropertyString") .build()); - assertNotNull(request); ODataRetrieveResponse<ClientProperty> response = request.execute(); @@ -135,7 +142,7 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { @Test public void readComplexProperty() throws Exception { - ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + final ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESMixPrimCollComp") .appendKeySegment(7) @@ -153,7 +160,7 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { @Test public void readComplexPropertyContextURL() throws Exception { - ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + final ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESMixPrimCollComp") .appendKeySegment(7) @@ -185,7 +192,7 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { @Test public void readUnknownProperty() throws Exception { - ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + final ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESTwoPrim") .appendKeySegment(32766) @@ -201,17 +208,115 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { @Test public void readNoContentProperty() throws Exception { - ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() + final ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory() .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI) .appendEntitySetSegment("ESTwoPrim") .appendKeySegment(-32766) .appendPropertySegment("PropertyString") .build()); - ODataRetrieveResponse<ClientProperty> response = request.execute(); + final ODataRetrieveResponse<ClientProperty> response = request.execute(); assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); } @Test + public void updatePrimitiveProperty() throws Exception { + final ODataPropertyUpdateRequest request = + getClient().getCUDRequestFactory().getPropertyPrimitiveValueUpdateRequest( + getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32766) + .appendPropertySegment("PropertyString") + .build(), + getClient().getObjectFactory().newPrimitiveProperty("PropertyString", + getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("Test String1"))); + assertNotNull(request); + + final ODataPropertyUpdateResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + assertThat(response.getContentType(), containsString(ContentType.APPLICATION_JSON.toContentTypeString())); + + final ClientProperty property = response.getBody(); + assertNotNull(property); + assertNotNull(property.getPrimitiveValue()); + assertEquals("Test String1", property.getPrimitiveValue().toValue()); + } + + @Test + public void patchComplexProperty() throws Exception { + final ODataPropertyUpdateRequest request = + getClient().getCUDRequestFactory().getPropertyComplexValueUpdateRequest( + getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESMixPrimCollComp").appendKeySegment(7) + .appendPropertySegment("PropertyComp") + .build(), + UpdateType.PATCH, + getClient().getObjectFactory().newComplexProperty("PropertyComp", + getClient().getObjectFactory().newComplexValue(null).add( + getClient().getObjectFactory().newPrimitiveProperty("PropertyString", + getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("Test String42"))))); + assertNotNull(request); + + final ODataPropertyUpdateResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ClientProperty property = response.getBody(); + assertNotNull(property); + assertNotNull(property.getComplexValue()); + final ClientComplexValue value = property.getComplexValue(); + assertEquals("Test String42", value.get("PropertyString").getPrimitiveValue().toValue()); + assertEquals(222, value.get("PropertyInt16").getPrimitiveValue().toValue()); + } + + @Test + public void updatePrimitiveCollection() throws Exception { + final ODataPropertyUpdateRequest request = + getClient().getCUDRequestFactory().getPropertyCollectionValueUpdateRequest( + getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESMixPrimCollComp").appendKeySegment(7) + .appendPropertySegment("CollPropertyString") + .build(), + getClient().getObjectFactory().newCollectionProperty("CollPropertyString", + getClient().getObjectFactory().newCollectionValue(null) + .add(getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("Test String1")) + .add(getClient().getObjectFactory().newPrimitiveValueBuilder().buildString("Test String2")))); + assertNotNull(request); + + final ODataPropertyUpdateResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ClientProperty property = response.getBody(); + assertNotNull(property); + final ClientCollectionValue<ClientValue> value = property.getCollectionValue(); + assertNotNull(value); + Iterator<ClientValue> iterator = value.iterator(); + assertTrue(iterator.hasNext()); + assertEquals("Test String1", iterator.next().asPrimitive().toValue()); + assertEquals("Test String2", iterator.next().asPrimitive().toValue()); + assertFalse(iterator.hasNext()); + } + + @Test + public void updateComplexCollection() throws Exception { + final ODataPropertyUpdateRequest request = + getClient().getCUDRequestFactory().getPropertyCollectionValueUpdateRequest( + getClient().newURIBuilder(SERVICE_URI) + .appendEntitySetSegment("ESMixPrimCollComp").appendKeySegment(7) + .appendPropertySegment("CollPropertyComp") + .build(), + getClient().getObjectFactory().newCollectionProperty("CollPropertyComp", + getClient().getObjectFactory().newCollectionValue(null))); + assertNotNull(request); + + final ODataPropertyUpdateResponse response = request.execute(); + assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); + + final ClientProperty property = response.getBody(); + assertNotNull(property); + final ClientCollectionValue<ClientValue> value = property.getCollectionValue(); + assertNotNull(value); + assertFalse(value.iterator().hasNext()); + } + + @Test public void readPropertyValue() throws Exception { final ODataValueRequest request = getClient().getRetrieveRequestFactory() .getPropertyValueRequest(getClient().newURIBuilder(SERVICE_URI) @@ -220,7 +325,7 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { .appendPropertySegment("PropertyString") .appendValueSegment() .build()); - ODataRetrieveResponse<ClientPrimitiveValue> response = request.execute(); + final ODataRetrieveResponse<ClientPrimitiveValue> response = request.execute(); assertEquals("Test String1", response.getBody().toValue()); } http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java ---------------------------------------------------------------------- diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java index d6be3fa..87c6a17 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java @@ -48,7 +48,9 @@ public class EtagInformation { } /** - * <p>Checks whether a given ETag value is matched by this ETag information.</p> + * <p>Checks whether a given ETag value is matched by this ETag information, + * using weak comparison as described in + * <a href="https://www.ietf.org/rfc/rfc7232.txt">RFC 7232</a>, section 2.3.2.</p> * <p>If the given value is <code>null</code>, or if this ETag information * does not contain anything, the result is <code>false</code>.</p> * @param etag the ETag value to match http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/ETagSupport.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/ETagSupport.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/ETagSupport.java new file mode 100644 index 0000000..825032d --- /dev/null +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/ETagSupport.java @@ -0,0 +1,34 @@ +/* + * 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; + +import org.apache.olingo.server.api.CustomETagSupport; + +public class ETagSupport implements CustomETagSupport { + + @Override + public boolean hasETag(final String entitySetName) { + return entitySetName.equals("ESCompAllPrim"); + } + + @Override + public boolean hasMediaETag(final String entitySetName) { + return entitySetName.equals("ESMedia"); + } +} http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java index 25c86c7..0412c80 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java @@ -48,7 +48,7 @@ public class TechnicalServlet extends HttpServlet { private static final Logger LOG = LoggerFactory.getLogger(TechnicalServlet.class); @Override - protected void service(final HttpServletRequest req, final HttpServletResponse resp) + protected void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { try { OData odata = OData.newInstance(); @@ -57,7 +57,7 @@ public class TechnicalServlet extends HttpServlet { final List<EdmxReference> references = Arrays.asList(reference); final ServiceMetadata serviceMetadata = odata.createServiceMetadata(new EdmTechProvider(references), references); - HttpSession session = req.getSession(true); + HttpSession session = request.getSession(true); DataProvider dataProvider = (DataProvider) session.getAttribute(DataProvider.class.getName()); if (dataProvider == null) { dataProvider = new DataProvider(); @@ -69,7 +69,8 @@ public class TechnicalServlet extends HttpServlet { handler.register(new TechnicalEntityProcessor(dataProvider, serviceMetadata)); handler.register(new TechnicalPrimitiveComplexProcessor(dataProvider, serviceMetadata)); handler.register(new TechnicalBatchProcessor(dataProvider)); - handler.process(req, resp); + handler.register(new ETagSupport()); + handler.process(request, response); } catch (RuntimeException e) { LOG.error("Server Error", e); throw new ServletException(e); http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/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 9de9bea..732d43b 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 @@ -275,6 +275,10 @@ public class DataProvider { } // Update the ETag if present. + updateETag(entity); + } + + public void updateETag(Entity entity) { if (entity.getETag() != null) { entity.setETag("W/\"" + System.nanoTime() + "\""); } @@ -411,8 +415,8 @@ public class DataProvider { } } - @SuppressWarnings({ "unchecked" }) - public void updateProperty(final EdmProperty edmProperty, final Property property, final Property newProperty, + @SuppressWarnings("unchecked") + public void updateProperty(final EdmProperty edmProperty, Property property, final Property newProperty, final boolean patch) throws DataProviderException { if (edmProperty.isPrimitive()) { if (newProperty != null || !patch) { @@ -420,7 +424,7 @@ public class DataProvider { property.setValue(property.getValueType(), value); } } else if (edmProperty.isCollection()) { - // Updating collection properties mean replacing all entites with the given ones + // Updating collection properties means replacing all entries with the given ones. property.asCollection().clear(); if (newProperty != null) { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/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 0ad21bb..489055b 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java @@ -18,6 +18,7 @@ */ package org.apache.olingo.server.tecsvc.processor; +import java.util.List; import java.util.Locale; import org.apache.olingo.commons.api.data.ContextURL; @@ -34,7 +35,6 @@ import org.apache.olingo.commons.api.http.HttpContentType; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpStatusCode; -import org.apache.olingo.server.api.EtagInformation; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; @@ -57,9 +57,11 @@ import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.serializer.SerializerResult; import org.apache.olingo.server.api.uri.UriInfo; +import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResourceAction; import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.api.uri.UriResourceFunction; +import org.apache.olingo.server.api.uri.UriResourceValue; import org.apache.olingo.server.api.uri.queryoption.CountOption; import org.apache.olingo.server.api.uri.queryoption.ExpandOption; import org.apache.olingo.server.api.uri.queryoption.SelectOption; @@ -98,7 +100,10 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void processActionEntityCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); + DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .actionParameters(request.getBody(), action); @@ -148,7 +153,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final ContentType requestedContentType) throws ODataApplicationException, SerializerException { validateOptions(uriInfo.asUriInfoResource()); - processEntity(request, response, uriInfo, requestedContentType, false); + readEntity(request, response, uriInfo, requestedContentType, false); } @Override @@ -238,6 +243,10 @@ public class TechnicalEntityProcessor extends TechnicalProcessor throw e; } } + + checkChangePreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); checkRequestFormat(requestFormat); final ODataDeserializer deserializer = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)); final Entity changedEntity = deserializer.entity(request.getBody(), edmEntitySet.getEntityType()).getEntity(); @@ -252,10 +261,10 @@ public class TechnicalEntityProcessor extends TechnicalProcessor dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity, request.getMethod() == HttpMethod.PATCH, false); + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); final ODataFormat format = ODataFormat.fromContentType(responseFormat); response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, format, null, null) .getContent()); - response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); if (entity.getETag() != null) { response.setHeader(HttpHeader.ETAG, entity.getETag()); @@ -270,6 +279,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final EdmEntityType edmEntityType = edmEntitySet.getEntityType(); Entity entity = readEntity(uriInfo); + checkChangePreconditions(entity.getMediaETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); checkRequestFormat(requestFormat); dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()), requestFormat.toContentTypeString()); @@ -285,10 +297,16 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } @Override - public void deleteEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) + public void deleteEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); final Entity entity = readEntity(uriInfo); + final List<UriResource> resourcePaths = uriInfo.getUriResourceParts(); + final boolean isValue = resourcePaths.get(resourcePaths.size() - 1) instanceof UriResourceValue; + + checkChangePreconditions(isValue ? entity.getMediaETag() : entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); dataProvider.delete(edmEntitySet, entity); response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } @@ -297,7 +315,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor public void processActionEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - final EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource()); final EdmEntityType type = (EdmEntityType) action.getReturnType().getType(); @@ -319,9 +339,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final ODataFormat format = ODataFormat.fromContentType(responseFormat); response.setContent(serializeEntity(entityResult.getEntity(), edmEntitySet, type, format, null, null) .getContent()); - response.setStatusCode((entityResult.isCreated() ? HttpStatusCode.CREATED : HttpStatusCode.OK).getStatusCode - - ()); + response.setStatusCode((entityResult.isCreated() ? HttpStatusCode.CREATED : HttpStatusCode.OK) + .getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); if (entityResult.getEntity().getETag() != null) { response.setHeader(HttpHeader.ETAG, entityResult.getEntity().getETag()); @@ -343,17 +362,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } - private void checkRequestFormat(final ContentType requestFormat) throws ODataApplicationException { - if (requestFormat == null) { - throw new ODataApplicationException("The content type has not been set in the request.", - HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); - } - } - private ContextURL getContextUrl(final EdmEntitySet entitySet, final EdmEntityType entityType, - final boolean isSingleEntity, final ExpandOption expand, final SelectOption select) throws - - SerializerException { + final boolean isSingleEntity, final ExpandOption expand, final SelectOption select) throws SerializerException { Builder builder = ContextURL.with(); builder = entitySet == null ? isSingleEntity ? builder.type(entityType) : builder.asCollection().type(entityType) : @@ -365,30 +375,26 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } @Override - public void readReference(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readReference(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestedContentType) throws ODataApplicationException, SerializerException { - - processEntity(request, response, uriInfo, requestedContentType, true); + readEntity(request, response, uriInfo, requestedContentType, true); } @Override - public void createReference(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void createReference(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat) throws ODataApplicationException, DeserializerException { - throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @Override - public void updateReference(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void updateReference(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat) throws ODataApplicationException, DeserializerException { - throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @Override - public void deleteReference(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) + public void deleteReference(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { - throw new ODataApplicationException("Not implemented", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } @@ -399,7 +405,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor processEntityCollection(request, response, uriInfo, requestedContentType, true); } - private void processEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + private void readEntity(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, final ContentType requestedContentType, final boolean isReference) throws ODataApplicationException, SerializerException { final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); @@ -410,18 +416,9 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final Entity entity = readEntity(uriInfo); - if (entity.getETag() != null) { - final EtagInformation ifMatch = odata.createEtagInformation(request.getHeaders(HttpHeader.IF_MATCH)); - if (!ifMatch.isMatchedBy(entity.getETag()) && !ifMatch.getEtags().isEmpty()) { - throw new ODataApplicationException("The If-Match precondition is not fulfilled.", - HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT); - } - if (odata.createEtagInformation(request.getHeaders(HttpHeader.IF_NONE_MATCH)) - .isMatchedBy(entity.getETag())) { - throw new ODataApplicationException("The entity has not been modified.", - HttpStatusCode.NOT_MODIFIED.getStatusCode(), Locale.ROOT); - } - } + checkReadPreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); final ODataFormat format = ODataFormat.fromContentType(requestedContentType); final ExpandOption expand = uriInfo.getExpandOption(); @@ -430,12 +427,11 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final ExpandSystemQueryOptionHandler expandHandler = new ExpandSystemQueryOptionHandler(); final Entity entitySerialization = expandHandler.transformEntityGraphToTree(entity, edmEntitySet, expand); expandHandler.applyExpandQueryOptions(entitySerialization, edmEntitySet, expand); - - final SerializerResult serializerResult = (isReference) ? - serializeReference(entity, edmEntitySet, format) - : serializeEntity(entitySerialization, edmEntitySet, edmEntityType, format, expand, select); - - + + final SerializerResult serializerResult = isReference ? + serializeReference(entity, edmEntitySet, format) : + serializeEntity(entitySerialization, edmEntitySet, edmEntityType, format, expand, select); + if (entity.getETag() != null) { response.setHeader(HttpHeader.ETAG, entity.getETag()); } @@ -495,15 +491,15 @@ public class TechnicalEntityProcessor extends TechnicalProcessor // Serialize final SerializerResult serializerResult = (isReference) ? serializeReferenceCollection(entitySetSerialization, edmEntitySet, format) : - serializeEntiyCollection(entitySetSerialization, edmEntitySet, edmEntityType, format, - expand, select, countOption); + serializeEntityCollection(entitySetSerialization, edmEntitySet, edmEntityType, format, + expand, select, countOption); response.setContent(serializerResult.getContent()); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); } - private SerializerResult serializeEntiyCollection(final EntityCollection entityCollection, + private SerializerResult serializeEntityCollection(final EntityCollection entityCollection, final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ODataFormat format, final ExpandOption expand, final SelectOption select, final CountOption countOption) throws SerializerException { @@ -541,7 +537,6 @@ public class TechnicalEntityProcessor extends TechnicalProcessor private SerializerResult serializeEntity(final Entity entity, final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ODataFormat format, final ExpandOption expand, final SelectOption select) throws SerializerException { - return odata.createSerializer(format).entity( serviceMetadata, edmEntityType, http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java index 0d911f0..4f1a4ba 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalPrimitiveComplexProcessor.java @@ -40,6 +40,7 @@ import org.apache.olingo.commons.api.edm.constants.EdmTypeKind; import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; +import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataRequest; @@ -68,6 +69,7 @@ import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriInfoResource; import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceAction; import org.apache.olingo.server.api.uri.UriResourceFunction; import org.apache.olingo.server.api.uri.UriResourceKind; import org.apache.olingo.server.api.uri.UriResourceProperty; @@ -90,30 +92,31 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void readPrimitive(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readPrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - readProperty(response, uriInfo, contentType, RepresentationType.PRIMITIVE); + readProperty(request, response, uriInfo, contentType, RepresentationType.PRIMITIVE); } @Override - public void updatePrimitive(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void updatePrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - throw new ODataApplicationException("Not supported yet.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + updateProperty(request, response, uriInfo, requestFormat, responseFormat, RepresentationType.PRIMITIVE); } @Override - public void deletePrimitive(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) + public void deletePrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { - deleteProperty(response, uriInfo); + deleteProperty(request, response, uriInfo); } @Override - public void processActionPrimitive(final ODataRequest request, final ODataResponse response, + public void processActionPrimitive(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .actionParameters(request.getBody(), action); @@ -124,8 +127,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (action.getReturnType().isNullable()) { response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { - // Not nullable return type so we have to give back a 500 - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + // Not nullable return type so we have to give back an Internal Server Error + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } } else { ContextURL contextURL = ContextURL.with().type(type).build(); @@ -141,31 +145,31 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void readPrimitiveCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readPrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_PRIMITIVE); + readProperty(request, response, uriInfo, contentType, RepresentationType.COLLECTION_PRIMITIVE); } @Override - public void updatePrimitiveCollection(final ODataRequest request, final ODataResponse response, + public void updatePrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - throw new ODataApplicationException("Not supported yet.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + updateProperty(request, response, uriInfo, requestFormat, responseFormat, RepresentationType.COLLECTION_PRIMITIVE); } @Override - public void - deletePrimitiveCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) - throws ODataApplicationException { - deleteProperty(response, uriInfo); + public void deletePrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) + throws ODataApplicationException { + deleteProperty(request, response, uriInfo); } @Override - public void processActionPrimitiveCollection(final ODataRequest request, final ODataResponse response, + public void processActionPrimitiveCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .actionParameters(request.getBody(), action); @@ -175,10 +179,12 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (property == null || property.isNull()) { // Collection Propertys must never be null - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } else if (property.asCollection().contains(null) && !action.getReturnType().isNullable()) { // Not nullable return type but array contains a null value - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } EdmPrimitiveType type = (EdmPrimitiveType) action.getReturnType().getType(); ContextURL contextURL = ContextURL.with().type(type).asCollection().build(); @@ -194,24 +200,31 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void readComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - readProperty(response, uriInfo, contentType, RepresentationType.COMPLEX); + readProperty(request, response, uriInfo, contentType, RepresentationType.COMPLEX); } @Override - public void updateComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void updateComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - throw new ODataApplicationException("Not supported yet.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + updateProperty(request, response, uriInfo, requestFormat, responseFormat, RepresentationType.COMPLEX); + } + + @Override + public void deleteComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) + throws ODataApplicationException { + deleteProperty(request, response, uriInfo); } @Override - public void processActionComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void processActionComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .actionParameters(request.getBody(), action); @@ -222,8 +235,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (action.getReturnType().isNullable()) { response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { - // Not nullable return type so we have to give back a 500 - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + // Not nullable return type so we have to give back an Internal Server Error + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } } else { ContextURL contextURL = ContextURL.with().type(type).build(); @@ -240,30 +254,31 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void deleteComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) - throws ODataApplicationException { - deleteProperty(response, uriInfo); - } - - @Override - public void readComplexCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { - readProperty(response, uriInfo, contentType, RepresentationType.COLLECTION_COMPLEX); + readProperty(request, response, uriInfo, contentType, RepresentationType.COLLECTION_COMPLEX); } @Override - public void updateComplexCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void updateComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - throw new ODataApplicationException("Not supported yet.", - HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); + updateProperty(request, response, uriInfo, requestFormat, responseFormat, RepresentationType.COLLECTION_COMPLEX); } @Override - public void processActionComplexCollection(final ODataRequest request, final ODataResponse response, + public void deleteComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) + throws ODataApplicationException { + deleteProperty(request, response, uriInfo); + } + + @Override + public void processActionComplexCollection(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType requestFormat, final ContentType responseFormat) throws ODataApplicationException, DeserializerException, SerializerException { - EdmAction action = checkBoundAndExtractAction(uriInfo); + blockBoundActions(uriInfo); + final EdmAction action = ((UriResourceAction) uriInfo.asUriInfoResource().getUriResourceParts().get(0)) + .getAction(); DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .actionParameters(request.getBody(), action); @@ -273,10 +288,12 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (property == null || property.isNull()) { // Collection Propertys must never be null - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } else if (property.asCollection().contains(null) && !action.getReturnType().isNullable()) { // Not nullable return type but array contains a null value - throw new ODataApplicationException("The action could no be executed", 500, Locale.ROOT); + throw new ODataApplicationException("The action could not be executed.", + HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); } EdmComplexType type = (EdmComplexType) action.getReturnType().getType(); ContextURL contextURL = ContextURL.with().type(type).asCollection().build(); @@ -291,14 +308,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); } - @Override - public void deleteComplexCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo) - throws ODataApplicationException { - deleteProperty(response, uriInfo); - } - - private void readProperty(final ODataResponse response, final UriInfo uriInfo, final ContentType contentType, - final RepresentationType representationType) throws ODataApplicationException, SerializerException { + private void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, + final ContentType contentType, final RepresentationType representationType) + throws ODataApplicationException, SerializerException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validateOptions(resource); validatePath(resource); @@ -308,9 +320,16 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final List<String> path = getPropertyPath(resourceParts, 0); final Entity entity = readEntity(uriInfo); + + if (entity != null && entity.getETag() != null) { + checkReadPreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); + } + final Property property = entity == null ? - getPropertyData(dataProvider.readFunctionPrimitiveComplex(((UriResourceFunction) resourceParts.get(0)) - .getFunction(), + getPropertyData( + dataProvider.readFunctionPrimitiveComplex(((UriResourceFunction) resourceParts.get(0)).getFunction(), ((UriResourceFunction) resourceParts.get(0)).getParameters()), path) : getPropertyData(entity, path); @@ -320,6 +339,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor if (property.getValue() == null) { response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); final EdmProperty edmProperty = path.isEmpty() ? null : ((UriResourceProperty) resourceParts.get(resourceParts.size() - 1)).getProperty(); final EdmType type = edmProperty == null ? @@ -328,69 +348,82 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final EdmReturnType returnType = resourceParts.get(0) instanceof UriResourceFunction ? ((UriResourceFunction) resourceParts.get(0)).getFunction().getReturnType() : null; - final ODataFormat format = ODataFormat.fromContentType(contentType); - ODataSerializer serializer = odata.createSerializer(format); final ExpandOption expand = uriInfo.getExpandOption(); final SelectOption select = uriInfo.getSelectOption(); - final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null : - getContextUrl(edmEntitySet, entity, path, type, representationType, expand, select); - switch (representationType) { - case PRIMITIVE: - response.setContent(serializer.primitive((EdmPrimitiveType) type, property, - PrimitiveSerializerOptions.with().contextURL(contextURL) - .nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable()) - .maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength()) - .precision(edmProperty == null ? returnType.getPrecision() : edmProperty.getPrecision()) - .scale(edmProperty == null ? returnType.getScale() : edmProperty.getScale()) - .unicode(edmProperty == null ? null : edmProperty.isUnicode()) - .build()).getContent()); - break; - case COMPLEX: - response.setContent(serializer.complex(serviceMetadata, (EdmComplexType) type, property, - ComplexSerializerOptions.with().contextURL(contextURL) - .expand(expand).select(select) - .build()).getContent()); - break; - case COLLECTION_PRIMITIVE: - response.setContent(serializer.primitiveCollection((EdmPrimitiveType) type, property, - PrimitiveSerializerOptions.with().contextURL(contextURL) - .nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable()) - .maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength()) - .precision(edmProperty == null ? returnType.getPrecision() : edmProperty.getPrecision()) - .scale(edmProperty == null ? returnType.getScale() : edmProperty.getScale()) - .unicode(edmProperty == null ? null : edmProperty.isUnicode()) - .build()).getContent()); - break; - case COLLECTION_COMPLEX: - response.setContent(serializer.complexCollection(serviceMetadata, (EdmComplexType) type, property, - ComplexSerializerOptions.with().contextURL(contextURL) - .expand(expand).select(select) - .build()).getContent()); - break; - default: - break; - } - response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + final ODataFormat format = ODataFormat.fromContentType(contentType); + final SerializerResult result = serializeProperty(entity, edmEntitySet, path, property, edmProperty, + type, returnType, representationType, format, expand, select); + response.setContent(result.getContent()); response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString()); } + if (entity != null && entity.getETag() != null) { + response.setHeader(HttpHeader.ETAG, entity.getETag()); + } + } + } + + private void updateProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, + final ContentType requestFormat, final ContentType responseFormat, final RepresentationType representationType) + throws ODataApplicationException, DeserializerException, SerializerException { + final UriInfoResource resource = uriInfo.asUriInfoResource(); + validatePath(resource); + final EdmEntitySet edmEntitySet = getEdmEntitySet(resource); + + Entity entity = readEntity(uriInfo); + checkChangePreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); + + final List<UriResource> resourceParts = resource.getUriResourceParts(); + final List<String> path = getPropertyPath(resourceParts, 0); + final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(resourceParts.size() - 1)) + .getProperty(); + + checkRequestFormat(requestFormat); + final Property changedProperty = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) + .property(request.getBody(), edmProperty).getProperty(); + if (changedProperty.isNull() && !edmProperty.isNullable()) { + throw new ODataApplicationException("Not nullable.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); + } + + Property property = getPropertyData(entity, path); + + dataProvider.updateProperty(edmProperty, property, changedProperty, request.getMethod() == HttpMethod.PATCH); + dataProvider.updateETag(entity); + + response.setStatusCode(HttpStatusCode.OK.getStatusCode()); + final ODataFormat format = ODataFormat.fromContentType(responseFormat); + final SerializerResult result = serializeProperty(entity, edmEntitySet, path, property, edmProperty, + edmProperty.getType(), null, representationType, format, null, null); + response.setContent(result.getContent()); + response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString()); + if (entity.getETag() != null) { + response.setHeader(HttpHeader.ETAG, entity.getETag()); } } - private void deleteProperty(final ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException { + private void deleteProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) + throws ODataApplicationException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validatePath(resource); getEdmEntitySet(uriInfo); // including checks + Entity entity = readEntity(uriInfo); + checkChangePreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); + final List<UriResource> resourceParts = resource.getUriResourceParts(); final List<String> path = getPropertyPath(resourceParts, 0); - final Property property = getPropertyData(readEntity(uriInfo), path); + Property property = getPropertyData(entity, path); final EdmProperty edmProperty = ((UriResourceProperty) resourceParts.get(resourceParts.size() - 1)) .getProperty(); if (edmProperty.isNullable()) { property.setValue(property.getValueType(), edmProperty.isCollection() ? Collections.emptyList() : null); + dataProvider.updateETag(entity); response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode()); } else { throw new ODataApplicationException("Not nullable.", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); @@ -436,6 +469,54 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor return result.toString(); } + private SerializerResult serializeProperty(final Entity entity, final EdmEntitySet edmEntitySet, + final List<String> path, final Property property, final EdmProperty edmProperty, + final EdmType type, final EdmReturnType returnType, + final RepresentationType representationType, final ODataFormat format, + final ExpandOption expand, final SelectOption select) throws SerializerException { + ODataSerializer serializer = odata.createSerializer(format); + final ContextURL contextURL = format == ODataFormat.JSON_NO_METADATA ? null : + getContextUrl(edmEntitySet, entity, path, type, representationType, expand, select); + SerializerResult result = null; + switch (representationType) { + case PRIMITIVE: + result = serializer.primitive((EdmPrimitiveType) type, property, + PrimitiveSerializerOptions.with().contextURL(contextURL) + .nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable()) + .maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength()) + .precision(edmProperty == null ? returnType.getPrecision() : edmProperty.getPrecision()) + .scale(edmProperty == null ? returnType.getScale() : edmProperty.getScale()) + .unicode(edmProperty == null ? null : edmProperty.isUnicode()) + .build()); + break; + case COMPLEX: + result = serializer.complex(serviceMetadata, (EdmComplexType) type, property, + ComplexSerializerOptions.with().contextURL(contextURL) + .expand(expand).select(select) + .build()); + break; + case COLLECTION_PRIMITIVE: + result = serializer.primitiveCollection((EdmPrimitiveType) type, property, + PrimitiveSerializerOptions.with().contextURL(contextURL) + .nullable(edmProperty == null ? returnType.isNullable() : edmProperty.isNullable()) + .maxLength(edmProperty == null ? returnType.getMaxLength() : edmProperty.getMaxLength()) + .precision(edmProperty == null ? returnType.getPrecision() : edmProperty.getPrecision()) + .scale(edmProperty == null ? returnType.getScale() : edmProperty.getScale()) + .unicode(edmProperty == null ? null : edmProperty.isUnicode()) + .build()); + break; + case COLLECTION_COMPLEX: + result = serializer.complexCollection(serviceMetadata, (EdmComplexType) type, property, + ComplexSerializerOptions.with().contextURL(contextURL) + .expand(expand).select(select) + .build()); + break; + default: + break; + } + return result; + } + private ContextURL getContextUrl(final EdmEntitySet entitySet, final Entity entity, final List<String> path, final EdmType type, final RepresentationType representationType, final ExpandOption expand, final SelectOption select) throws SerializerException { @@ -455,7 +536,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } @Override - public void readPrimitiveValue(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo, + public void readPrimitiveValue(final ODataRequest request, ODataResponse response, final UriInfo uriInfo, final ContentType contentType) throws ODataApplicationException, SerializerException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validateOptions(resource); @@ -466,6 +547,12 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final List<String> path = getPropertyPath(resourceParts, 1); final Entity entity = readEntity(uriInfo); + if (entity != null && entity.getETag() != null) { + checkReadPreconditions(entity.getETag(), + request.getHeaders(HttpHeader.IF_MATCH), + request.getHeaders(HttpHeader.IF_NONE_MATCH)); + } + final Property property = entity == null ? getPropertyData(dataProvider.readFunctionPrimitiveComplex(((UriResourceFunction) resourceParts.get(0)) .getFunction(), @@ -496,6 +583,9 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString()); response.setStatusCode(HttpStatusCode.OK.getStatusCode()); } + if (entity != null && entity.getETag() != null) { + response.setHeader(HttpHeader.ETAG, entity.getETag()); + } } private void validatePath(final UriInfoResource uriInfo) throws ODataApplicationException { http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/7ad5b0fb/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java ---------------------------------------------------------------------- diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java index e5991bd..3f5c7bb 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java @@ -18,19 +18,21 @@ */ package org.apache.olingo.server.tecsvc.processor; +import java.util.Collection; import java.util.List; import java.util.Locale; import org.apache.olingo.commons.api.data.Entity; import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.Link; -import org.apache.olingo.commons.api.edm.EdmAction; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmEntitySet; import org.apache.olingo.commons.api.edm.EdmEntityType; import org.apache.olingo.commons.api.edm.EdmFunction; import org.apache.olingo.commons.api.edm.EdmNavigationProperty; +import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.server.api.EtagInformation; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ServiceMetadata; @@ -218,12 +220,49 @@ public abstract class TechnicalProcessor implements Processor { } } - protected EdmAction checkBoundAndExtractAction(final UriInfo uriInfo) throws ODataApplicationException { + protected void blockBoundActions(final UriInfo uriInfo) throws ODataApplicationException { final List<UriResource> uriResourceParts = uriInfo.asUriInfoResource().getUriResourceParts(); - if (uriResourceParts.size() > 1) { + if (uriResourceParts.size() > 1 + && uriResourceParts.get(uriResourceParts.size() - 1) instanceof UriResourceAction) { throw new ODataApplicationException("Bound actions are not supported yet.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT); } - return ((UriResourceAction) uriResourceParts.get(0)).getAction(); + } + + protected void checkRequestFormat(final ContentType requestFormat) throws ODataApplicationException { + if (requestFormat == null) { + throw new ODataApplicationException("The content type has not been set in the request.", + HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); + } + } + + protected void checkReadPreconditions(final String eTag, + final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders) + throws ODataApplicationException { + if (eTag != null) { + final EtagInformation ifMatch = odata.createEtagInformation(ifMatchHeaders); + if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getEtags().isEmpty()) { + throw new ODataApplicationException("The If-Match precondition is not fulfilled.", + HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT); + } + if (odata.createEtagInformation(ifNoneMatchHeaders).isMatchedBy(eTag)) { + throw new ODataApplicationException("The entity has not been modified.", + HttpStatusCode.NOT_MODIFIED.getStatusCode(), Locale.ROOT); + } + } + } + + protected void checkChangePreconditions(final String eTag, + final Collection<String> ifMatchHeaders, final Collection<String> ifNoneMatchHeaders) + throws ODataApplicationException { + if (eTag != null) { + final EtagInformation ifMatch = odata.createEtagInformation(ifMatchHeaders); + final EtagInformation ifNoneMatch = odata.createEtagInformation(ifNoneMatchHeaders); + if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getEtags().isEmpty() + || ifNoneMatch.isMatchedBy(eTag)) { + throw new ODataApplicationException("The preconditions are not fulfilled.", + HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.ROOT); + } + } } }
