diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java index 2ea9ec7a8..c8914ef98 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/OData.java @@ -18,7 +18,6 @@ */ package org.apache.olingo.server.api; -import java.util.Collection; import java.util.List; import org.apache.olingo.commons.api.ODataRuntimeException; @@ -30,6 +29,7 @@ import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer; import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.api.edmx.EdmxReference; +import org.apache.olingo.server.api.etag.ETagHelper; import org.apache.olingo.server.api.serializer.FixedFormatSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; @@ -118,11 +118,8 @@ public abstract class OData { public abstract EdmPrimitiveType createPrimitiveTypeInstance(EdmPrimitiveTypeKind kind); /** - * Creates ETag information from the values of a HTTP header - * containing a list of entity tags or a single star character, i.e., - * If-Match and If-None-Match. - * @param values the collection of header values - * @return an {@link ETagInformation} instance + * Creates a new ETag helper object for performing ETag-related tasks. + * It can be used in Processor implementations. */ - public abstract ETagInformation createETagInformation(final Collection values); + public abstract ETagHelper createETagHelper(); } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java index 37002916b..20ed77eec 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataHttpHandler.java @@ -21,6 +21,7 @@ package org.apache.olingo.server.api; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.olingo.server.api.etag.CustomETagSupport; import org.apache.olingo.server.api.processor.Processor; import org.apache.olingo.server.api.serializer.CustomContentTypeSupport; diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/CustomETagSupport.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/CustomETagSupport.java similarity index 98% rename from lib/server-api/src/main/java/org/apache/olingo/server/api/CustomETagSupport.java rename to lib/server-api/src/main/java/org/apache/olingo/server/api/etag/CustomETagSupport.java index 5e4f50003..c0dba7817 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/CustomETagSupport.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/CustomETagSupport.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.api; +package org.apache.olingo.server.api.etag; import org.apache.olingo.commons.api.edm.EdmBindingTarget; diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/ETagHelper.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/ETagHelper.java new file mode 100644 index 000000000..ae8b0e292 --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/ETagHelper.java @@ -0,0 +1,66 @@ +/* + * 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.api.etag; + +import java.util.Collection; + +/** + * Used for ETag-related tasks. + */ +public interface ETagHelper { + /** + *

Checks the preconditions of a read request with a given ETag value + * against the If-Match and If-None-Match HTTP headers.

+ *

If the given ETag value is not matched by the ETag information in the If-Match headers, + * and there are ETags in the headers to be matched, a "Precondition Failed" exception is + * thrown.

+ *

If the given ETag value is matched by the ETag information in the If-None-Match headers, + * true is returned, and applications are supposed to return an empty response + * with a "Not Modified" status code and the ETag header, false otherwise.

+ *

All matching uses weak comparison as described in + * RFC 7232, section 2.3.2.

+ *

This method does not nothing and returns false if the ETag value is + * null.

+ * @param eTag the ETag value to match + * @param ifMatchHeaders the If-Match header values + * @param ifNoneMatchHeaders the If-None-Match header values + * @return whether a "Not Modified" response should be used + */ + public boolean checkReadPreconditions(String eTag, + Collection ifMatchHeaders, Collection ifNoneMatchHeaders) + throws PreconditionRequiredException; + + /** + *

Checks the preconditions of a change request (with HTTP methods PUT, PATCH, or DELETE) + * with a given ETag value against the If-Match and If-None-Match HTTP headers.

+ *

If the given ETag value is not matched by the ETag information in the If-Match headers, + * and there are ETags in the headers to be matched, or + * if the given ETag value is matched by the ETag information in the If-None-Match headers, + * a "Precondition Failed" exception is thrown.

+ *

All matching uses weak comparison as described in + * RFC 7232, section 2.3.2.

+ *

This method does not nothing if the ETag value is null.

+ * @param eTag the ETag value to match + * @param ifMatchHeaders the If-Match header values + * @param ifNoneMatchHeaders the If-None-Match header values + */ + public void checkChangePreconditions(String eTag, + Collection ifMatchHeaders, Collection ifNoneMatchHeaders) + throws PreconditionRequiredException; +} diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/PreconditionRequiredException.java similarity index 94% rename from lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java rename to lib/server-api/src/main/java/org/apache/olingo/server/api/etag/PreconditionRequiredException.java index 25ba11771..b49298fbc 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/etag/PreconditionRequiredException.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.core; +package org.apache.olingo.server.api.etag; import org.apache.olingo.server.api.ODataLibraryException; @@ -25,7 +25,9 @@ public class PreconditionRequiredException extends ODataLibraryException { public static enum MessageKeys implements MessageKey { /** no parameter */ - MISSING_HEADER, + MISSING_HEADER, + /** no parameter */ + FAILED, /** no parameter */ INVALID_URI; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java index 30edc5a18..d05a98bb4 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataDispatcher.java @@ -33,6 +33,7 @@ import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataLibraryException; import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor; import org.apache.olingo.server.api.processor.ActionComplexProcessor; import org.apache.olingo.server.api.processor.ActionEntityCollectionProcessor; @@ -67,6 +68,7 @@ import org.apache.olingo.server.api.uri.UriResourcePartTyped; import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty; import org.apache.olingo.server.api.uri.UriResourceProperty; import org.apache.olingo.server.core.batchhandler.BatchHandler; +import org.apache.olingo.server.core.etag.PreconditionsValidator; public class ODataDispatcher { diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java index e91e9e2d5..664b50aed 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java @@ -26,6 +26,7 @@ import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataLibraryException; import org.apache.olingo.server.api.ODataLibraryException.ODataErrorMessage; import org.apache.olingo.server.api.deserializer.DeserializerException; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.core.uri.parser.UriParserException; import org.apache.olingo.server.core.uri.parser.UriParserSemanticException; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java index b266549a1..82313f54f 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java @@ -26,7 +26,6 @@ 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.server.api.CustomETagSupport; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataLibraryException; @@ -35,6 +34,8 @@ import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ServiceMetadata; import org.apache.olingo.server.api.deserializer.DeserializerException; +import org.apache.olingo.server.api.etag.CustomETagSupport; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; import org.apache.olingo.server.api.processor.DefaultProcessor; import org.apache.olingo.server.api.processor.ErrorProcessor; import org.apache.olingo.server.api.processor.Processor; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java index 4fb66407a..5563f1b64 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java @@ -33,7 +33,6 @@ import javax.servlet.http.HttpServletResponse; import org.apache.olingo.commons.api.ODataRuntimeException; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; -import org.apache.olingo.server.api.CustomETagSupport; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; @@ -41,6 +40,7 @@ import org.apache.olingo.server.api.ODataRequest; import org.apache.olingo.server.api.ODataResponse; import org.apache.olingo.server.api.ODataLibraryException; import org.apache.olingo.server.api.ServiceMetadata; +import org.apache.olingo.server.api.etag.CustomETagSupport; import org.apache.olingo.server.api.processor.Processor; import org.apache.olingo.server.api.serializer.CustomContentTypeSupport; import org.apache.olingo.server.api.serializer.SerializerException; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java index e3cbd6d22..5c5229f55 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java @@ -18,8 +18,6 @@ */ package org.apache.olingo.server.core; -import java.util.Collection; -import java.util.Collections; import java.util.List; import org.apache.olingo.commons.api.edm.EdmPrimitiveType; @@ -27,7 +25,6 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind; import org.apache.olingo.commons.api.edm.provider.CsdlEdmProvider; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory; -import org.apache.olingo.server.api.ETagInformation; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ServiceMetadata; @@ -35,12 +32,14 @@ import org.apache.olingo.server.api.deserializer.DeserializerException; import org.apache.olingo.server.api.deserializer.FixedFormatDeserializer; import org.apache.olingo.server.api.deserializer.ODataDeserializer; import org.apache.olingo.server.api.edmx.EdmxReference; +import org.apache.olingo.server.api.etag.ETagHelper; import org.apache.olingo.server.api.serializer.FixedFormatSerializer; import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.SerializerException; import org.apache.olingo.server.api.uri.UriHelper; import org.apache.olingo.server.core.deserializer.FixedFormatDeserializerImpl; import org.apache.olingo.server.core.deserializer.json.ODataJsonDeserializer; +import org.apache.olingo.server.core.etag.ETagHelperImpl; import org.apache.olingo.server.core.serializer.FixedFormatSerializerImpl; import org.apache.olingo.server.core.serializer.json.ODataJsonSerializer; import org.apache.olingo.server.core.serializer.xml.ODataXmlSerializerImpl; @@ -96,21 +95,20 @@ public class ODataImpl extends OData { @Override public ODataDeserializer createDeserializer(final ODataFormat format) throws DeserializerException { - ODataDeserializer serializer; + ODataDeserializer deserializer; switch (format) { case JSON: case JSON_NO_METADATA: case JSON_FULL_METADATA: - serializer = new ODataJsonDeserializer(); + deserializer = new ODataJsonDeserializer(); break; case XML: - // We do not support xml deserialization right now so this mus lead to an error + // We do not support XML deserialization right now so this must lead to an error. default: throw new DeserializerException("Unsupported format: " + format, - SerializerException.MessageKeys.UNSUPPORTED_FORMAT, format.toString()); + DeserializerException.MessageKeys.UNSUPPORTED_FORMAT, format.toString()); } - - return serializer; + return deserializer; } @Override @@ -119,10 +117,7 @@ public class ODataImpl extends OData { } @Override - public ETagInformation createETagInformation(final Collection values) { - final Collection eTags = ETagParser.parse(values); - final boolean isAll = eTags.size() == 1 && eTags.iterator().next().equals("*"); - return new ETagInformation(isAll, - isAll ? Collections. emptySet() : Collections.unmodifiableCollection(eTags)); + public ETagHelper createETagHelper() { + return new ETagHelperImpl(); } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagHelperImpl.java new file mode 100644 index 000000000..1d8c6d63d --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagHelperImpl.java @@ -0,0 +1,72 @@ +/* + * 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.core.etag; + +import java.util.Collection; +import java.util.Collections; + +import org.apache.olingo.server.api.etag.ETagHelper; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; + +public class ETagHelperImpl implements ETagHelper { + + @Override + public boolean checkReadPreconditions(final String eTag, + final Collection ifMatchHeaders, final Collection ifNoneMatchHeaders) + throws PreconditionRequiredException { + if (eTag != null) { + final ETagInformation ifMatch = createETagInformation(ifMatchHeaders); + if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getETags().isEmpty()) { + throw new PreconditionRequiredException("The If-Match precondition is not fulfilled.", + PreconditionRequiredException.MessageKeys.FAILED); + } + return createETagInformation(ifNoneMatchHeaders).isMatchedBy(eTag); + } + return false; + } + + @Override + public void checkChangePreconditions(final String eTag, + final Collection ifMatchHeaders, final Collection ifNoneMatchHeaders) + throws PreconditionRequiredException { + if (eTag != null) { + final ETagInformation ifMatch = createETagInformation(ifMatchHeaders); + final ETagInformation ifNoneMatch = createETagInformation(ifNoneMatchHeaders); + if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getETags().isEmpty() + || ifNoneMatch.isMatchedBy(eTag)) { + throw new PreconditionRequiredException("The preconditions are not fulfilled.", + PreconditionRequiredException.MessageKeys.FAILED); + } + } + } + + /** + * Creates ETag information from the values of a HTTP header + * containing a list of entity tags or a single star character, i.e., + * If-Match and If-None-Match. + * @param values the collection of header values + * @return an {@link ETagInformation} instance + */ + protected ETagInformation createETagInformation(final Collection values) { + final Collection eTags = ETagParser.parse(values); + final boolean isAll = eTags.size() == 1 && eTags.iterator().next().equals("*"); + return new ETagInformation(isAll, + isAll ? Collections. emptySet() : Collections.unmodifiableCollection(eTags)); + } +} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagInformation.java similarity index 98% rename from lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java rename to lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagInformation.java index fa65722be..03310eca7 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagInformation.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.api; +package org.apache.olingo.server.core.etag; import java.util.Collection; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ETagParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagParser.java similarity index 98% rename from lib/server-core/src/main/java/org/apache/olingo/server/core/ETagParser.java rename to lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagParser.java index 20332f62a..b8534dd2a 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ETagParser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/ETagParser.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.core; +package org.apache.olingo.server.core.etag; import java.util.Collection; import java.util.Collections; diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionsValidator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/PreconditionsValidator.java similarity index 96% rename from lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionsValidator.java rename to lib/server-core/src/main/java/org/apache/olingo/server/core/etag/PreconditionsValidator.java index 490acc1ec..3adf8af77 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionsValidator.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/etag/PreconditionsValidator.java @@ -16,12 +16,13 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.core; +package org.apache.olingo.server.core.etag; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmFunctionImport; import org.apache.olingo.commons.api.edm.EdmNavigationProperty; -import org.apache.olingo.server.api.CustomETagSupport; +import org.apache.olingo.server.api.etag.CustomETagSupport; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.api.uri.UriResource; import org.apache.olingo.server.api.uri.UriResourceEntitySet; diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ETagParserTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/etag/ETagParserTest.java similarity index 66% rename from lib/server-core/src/test/java/org/apache/olingo/server/core/ETagParserTest.java rename to lib/server-core/src/test/java/org/apache/olingo/server/core/etag/ETagParserTest.java index 7931b2bcd..059d53d11 100644 --- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ETagParserTest.java +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/etag/ETagParserTest.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.olingo.server.core; +package org.apache.olingo.server.core.etag; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.hasItems; @@ -28,17 +28,15 @@ import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.Collections; -import org.apache.olingo.server.api.ETagInformation; -import org.apache.olingo.server.api.OData; import org.junit.Test; public class ETagParserTest { - private static final OData odata = OData.newInstance(); + private static final ETagHelperImpl eTagHelper = new ETagHelperImpl(); @Test public void empty() { - final ETagInformation eTagInformation = odata.createETagInformation(null); + final ETagInformation eTagInformation = eTagHelper.createETagInformation(null); assertFalse(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); assertTrue(eTagInformation.getETags().isEmpty()); @@ -46,7 +44,7 @@ public class ETagParserTest { @Test public void loneStar() { - final ETagInformation eTagInformation = odata.createETagInformation(Collections.singleton("*")); + final ETagInformation eTagInformation = eTagHelper.createETagInformation(Collections.singleton("*")); assertTrue(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); assertTrue(eTagInformation.getETags().isEmpty()); @@ -54,7 +52,7 @@ public class ETagParserTest { @Test public void starWins() { - final ETagInformation eTagInformation = odata.createETagInformation(Arrays.asList("\"ETag\"", "*")); + final ETagInformation eTagInformation = eTagHelper.createETagInformation(Arrays.asList("\"ETag\"", "*")); assertTrue(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); assertTrue(eTagInformation.getETags().isEmpty()); @@ -62,7 +60,7 @@ public class ETagParserTest { @Test public void starAsEtagAndEmptyEtag() { - final ETagInformation eTagInformation = odata.createETagInformation( + final ETagInformation eTagInformation = eTagHelper.createETagInformation( Collections.singleton("\"*\", \"\"")); assertFalse(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); @@ -72,7 +70,7 @@ public class ETagParserTest { @Test public void severalEtags() { - final ETagInformation eTagInformation = odata.createETagInformation( + final ETagInformation eTagInformation = eTagHelper.createETagInformation( Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,")); assertFalse(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); @@ -82,7 +80,7 @@ public class ETagParserTest { @Test public void duplicateEtagValues() { - final ETagInformation eTagInformation = odata.createETagInformation( + final ETagInformation eTagInformation = eTagHelper.createETagInformation( Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\"")); assertFalse(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); @@ -92,7 +90,7 @@ public class ETagParserTest { @Test public void specialCharacters() { - final ETagInformation eTagInformation = odata.createETagInformation( + final ETagInformation eTagInformation = eTagHelper.createETagInformation( Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~ยก\u00FF\", \"ETag2\"")); assertFalse(eTagInformation.isAll()); assertNotNull(eTagInformation.getETags()); @@ -103,7 +101,7 @@ public class ETagParserTest { @Test public void wrongFormat() { - final ETagInformation eTagInformation = odata.createETagInformation( + final ETagInformation eTagInformation = eTagHelper.createETagInformation( Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5", "\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"", "\"ETag 9\"", "\"ETag10\"")); @@ -115,17 +113,17 @@ public class ETagParserTest { @Test public void match() { - assertFalse(odata.createETagInformation(Collections. emptySet()).isMatchedBy("\"ETag\"")); - assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy(null)); - assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("\"ETag\"")); - assertTrue(odata.createETagInformation(Collections.singleton("*")).isMatchedBy("\"ETag\"")); - assertTrue(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag\"")); - assertTrue(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag\"")); - assertFalse(odata.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag2\"")); - assertFalse(odata.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag2\"")); - assertTrue(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) + assertFalse(eTagHelper.createETagInformation(Collections. emptySet()).isMatchedBy("\"ETag\"")); + assertFalse(eTagHelper.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy(null)); + assertTrue(eTagHelper.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("\"ETag\"")); + assertTrue(eTagHelper.createETagInformation(Collections.singleton("*")).isMatchedBy("\"ETag\"")); + assertTrue(eTagHelper.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag\"")); + assertTrue(eTagHelper.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag\"")); + assertFalse(eTagHelper.createETagInformation(Collections.singleton("\"ETag\"")).isMatchedBy("W/\"ETag2\"")); + assertFalse(eTagHelper.createETagInformation(Collections.singleton("W/\"ETag\"")).isMatchedBy("\"ETag2\"")); + assertTrue(eTagHelper.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) .isMatchedBy("\"ETag4\"")); - assertFalse(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) + assertFalse(eTagHelper.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) .isMatchedBy("\"ETag5\"")); } } \ No newline at end of file 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 index 901110707..09d4910c6 100644 --- 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 @@ -19,7 +19,7 @@ package org.apache.olingo.server.tecsvc; import org.apache.olingo.commons.api.edm.EdmBindingTarget; -import org.apache.olingo.server.api.CustomETagSupport; +import org.apache.olingo.server.api.etag.CustomETagSupport; public class ETagSupport implements CustomETagSupport { 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 eaec6d002..086f69c5c 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 @@ -161,9 +161,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor .validate(edmEntitySet, deserializerResult.getEntity()); entity = dataProvider.create(edmEntitySet); - dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, - - true); + dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, true); expand = deserializerResult.getExpandTree(); } @@ -199,7 +197,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } } - checkChangePreconditions(entity.getETag(), + odata.createETagHelper().checkChangePreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), request.getHeaders(HttpHeader.IF_NONE_MATCH)); checkRequestFormat(requestFormat); @@ -232,7 +230,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final EdmEntityType edmEntityType = edmEntitySet.getEntityType(); Entity entity = readEntity(uriInfo); - checkChangePreconditions(entity.getMediaETag(), + odata.createETagHelper().checkChangePreconditions(entity.getMediaETag(), request.getHeaders(HttpHeader.IF_MATCH), request.getHeaders(HttpHeader.IF_NONE_MATCH)); checkRequestFormat(requestFormat); @@ -251,13 +249,13 @@ public class TechnicalEntityProcessor extends TechnicalProcessor @Override public void deleteEntity(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) - throws ODataApplicationException { + throws ODataLibraryException, ODataApplicationException { final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo); final Entity entity = readEntity(uriInfo); final List resourcePaths = uriInfo.getUriResourceParts(); final boolean isValue = resourcePaths.get(resourcePaths.size() - 1) instanceof UriResourceValue; - checkChangePreconditions(isValue ? entity.getMediaETag() : entity.getETag(), + odata.createETagHelper().checkChangePreconditions(isValue ? entity.getMediaETag() : entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), request.getHeaders(HttpHeader.IF_NONE_MATCH)); dataProvider.delete(edmEntitySet, entity); @@ -353,9 +351,13 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final Entity entity = readEntity(uriInfo); - checkReadPreconditions(entity.getETag(), + if (odata.createETagHelper().checkReadPreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), - request.getHeaders(HttpHeader.IF_NONE_MATCH)); + request.getHeaders(HttpHeader.IF_NONE_MATCH))) { + response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); + response.setHeader(HttpHeader.ETAG, entity.getETag()); + return; + } final ODataFormat format = ODataFormat.fromContentType(requestedContentType); final ExpandOption expand = uriInfo.getExpandOption(); 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 4ba708128..58b38c4bb 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 @@ -171,9 +171,13 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final Entity entity = readEntity(uriInfo); if (entity != null && entity.getETag() != null) { - checkReadPreconditions(entity.getETag(), + if (odata.createETagHelper().checkReadPreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), - request.getHeaders(HttpHeader.IF_NONE_MATCH)); + request.getHeaders(HttpHeader.IF_NONE_MATCH))) { + response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); + response.setHeader(HttpHeader.ETAG, entity.getETag()); + return; + } } final Property property = entity == null ? @@ -219,7 +223,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final EdmEntitySet edmEntitySet = getEdmEntitySet(resource); Entity entity = readEntity(uriInfo); - checkChangePreconditions(entity.getETag(), + odata.createETagHelper().checkChangePreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), request.getHeaders(HttpHeader.IF_NONE_MATCH)); @@ -252,13 +256,13 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } private void deleteProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo) - throws ODataApplicationException { + throws ODataLibraryException, ODataApplicationException { final UriInfoResource resource = uriInfo.asUriInfoResource(); validatePath(resource); getEdmEntitySet(uriInfo); // including checks Entity entity = readEntity(uriInfo); - checkChangePreconditions(entity.getETag(), + odata.createETagHelper().checkChangePreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), request.getHeaders(HttpHeader.IF_NONE_MATCH)); @@ -397,9 +401,13 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor final Entity entity = readEntity(uriInfo); if (entity != null && entity.getETag() != null) { - checkReadPreconditions(entity.getETag(), + if (odata.createETagHelper().checkReadPreconditions(entity.getETag(), request.getHeaders(HttpHeader.IF_MATCH), - request.getHeaders(HttpHeader.IF_NONE_MATCH)); + request.getHeaders(HttpHeader.IF_NONE_MATCH))) { + response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode()); + response.setHeader(HttpHeader.ETAG, entity.getETag()); + return; + } } final Property property = entity == null ? 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 b9e32fe2a..c95091d03 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,7 +18,6 @@ */ package org.apache.olingo.server.tecsvc.processor; -import java.util.Collection; import java.util.List; import java.util.Locale; @@ -32,7 +31,6 @@ 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; @@ -257,34 +255,4 @@ public abstract class TechnicalProcessor implements Processor { HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); } } - - protected void checkReadPreconditions(final String eTag, - final Collection ifMatchHeaders, final Collection 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 ifMatchHeaders, final Collection 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); - } - } - } } diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java index 033f9af15..7cab5678d 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/PreconditionsValidatorTest.java @@ -25,8 +25,10 @@ import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.core.edm.EdmProviderImpl; -import org.apache.olingo.server.api.CustomETagSupport; +import org.apache.olingo.server.api.etag.CustomETagSupport; +import org.apache.olingo.server.api.etag.PreconditionRequiredException; import org.apache.olingo.server.api.uri.UriInfo; +import org.apache.olingo.server.core.etag.PreconditionsValidator; import org.apache.olingo.server.core.uri.parser.Parser; import org.apache.olingo.server.core.uri.parser.UriParserException; import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;