[OLINGO-663] conditional handling in technical service, part 2

Signed-off-by: Christian Amend <chrisam@apache.org>
This commit is contained in:
Klaus Straubinger 2015-05-28 12:35:41 +02:00 committed by Christian Amend
parent ea89f7213e
commit 7ad5b0fb54
10 changed files with 584 additions and 192 deletions

View File

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

View File

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

View File

@ -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,16 +208,114 @@ 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()
@ -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());
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 processActionComplex(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
public void deleteComplex(final ODataRequest request, ODataResponse response, final UriInfo uriInfo)
throws ODataApplicationException {
deleteProperty(request, response, uriInfo);
}
@Override
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 deleteProperty(final ODataResponse response, final UriInfo uriInfo) throws ODataApplicationException {
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 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 {

View File

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