From c65ef5e9e74064976ab41be4ddc3e5b8eaa1f7b3 Mon Sep 17 00:00:00 2001 From: Klaus Straubinger Date: Tue, 2 Jun 2015 15:14:57 +0200 Subject: [PATCH] [OLINGO-663] clean-up Change-Id: Id1359ca3243e42d83ce0bd3057da3477850730e6 Signed-off-by: Christian Amend --- .../client/SystemQueryOptionITCase.java | 14 +- .../response/ODataLinkOperationResponse.java | 29 ---- .../olingo/server/api/ETagInformation.java | 74 ++++++++++ .../olingo/server/api/EtagInformation.java | 22 +-- .../org/apache/olingo/server/api/OData.java | 6 +- .../apache/olingo/server/core/ETagParser.java | 86 ++++++++++++ .../apache/olingo/server/core/EtagParser.java | 2 +- .../olingo/server/core/ODataHandler.java | 4 +- .../apache/olingo/server/core/ODataImpl.java | 12 +- .../core/PreconditionRequiredException.java | 5 +- ...hFascadeImpl.java => BatchFacadeImpl.java} | 4 +- .../core/batchhandler/BatchHandler.java | 2 +- .../olingo/server/core/ETagParserTest.java | 131 ++++++++++++++++++ .../olingo/server/core/EtagParserTest.java | 98 ++++++------- .../server/tecsvc/data/DataProvider.java | 8 +- .../server/tecsvc/data/RequestValidator.java | 89 +++++------- .../processor/TechnicalEntityProcessor.java | 8 +- .../tecsvc/processor/TechnicalProcessor.java | 14 +- .../expression/operand/TypedOperand.java | 20 +-- .../expression/operand/UntypedOperand.java | 9 +- .../expression/operand/VisitorOperand.java | 2 + .../operation/MethodCallOperator.java | 14 +- .../expression/primitive/EdmNull.java | 88 ++++-------- 23 files changed, 463 insertions(+), 278 deletions(-) delete mode 100644 lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataLinkOperationResponse.java create mode 100644 lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java create mode 100644 lib/server-core/src/main/java/org/apache/olingo/server/core/ETagParser.java rename lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/{BatchFascadeImpl.java => BatchFacadeImpl.java} (93%) create mode 100644 lib/server-core/src/test/java/org/apache/olingo/server/core/ETagParserTest.java diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java index 08ad26c98..c8d1d0c01 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/SystemQueryOptionITCase.java @@ -212,8 +212,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase { // Check initial next link format URI nextLink = response.getBody().getNext(); - assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=1", nextLink - .toASCIIString()); + assertEquals(SERVICE_URI + "/ESServerSidePaging?%24skiptoken=1", nextLink.toASCIIString()); // Check subsequent next links response = client.getRetrieveRequestFactory() @@ -221,8 +220,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase { .execute(); nextLink = response.getBody().getNext(); - assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24skiptoken=2", nextLink - .toASCIIString()); + assertEquals(SERVICE_URI + "/ESServerSidePaging?%24skiptoken=2", nextLink.toASCIIString()); } @Test @@ -239,7 +237,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase { // Check initial next link format URI nextLink = response.getBody().getNext(); - assertEquals("http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken=1", + assertEquals(SERVICE_URI + "/ESServerSidePaging?%24count=true&%24skiptoken=1", nextLink.toASCIIString()); int token = 1; @@ -253,10 +251,8 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase { nextLink = response.getBody().getNext(); if (nextLink != null) { - assertEquals( - "http://localhost:9080/odata-server-tecsvc/odata.svc/ESServerSidePaging?%24count=true&%24skiptoken=" - + token, - nextLink.toASCIIString()); + assertEquals(SERVICE_URI + "/ESServerSidePaging?%24count=true&%24skiptoken=" + token, + nextLink.toASCIIString()); } } diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataLinkOperationResponse.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataLinkOperationResponse.java deleted file mode 100644 index 3a12bd322..000000000 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/response/ODataLinkOperationResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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.client.api.communication.response; - -/** - * This interface defines the response to an OData link operation request. - * - * @see org.apache.olingo.client.api.communication.request.cud.v3.ODataLinkCreateRequest - * @see org.apache.olingo.client.api.communication.request.cud.v3.ODataLinkUpdateRequest - */ -public interface ODataLinkOperationResponse extends ODataResponse { -//No additional methods needed for now. -} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java new file mode 100644 index 000000000..2a628c4af --- /dev/null +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ETagInformation.java @@ -0,0 +1,74 @@ +/* + * 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; + +import java.util.Collection; + +/** + * Information about the values of an ETag-relevant HTTP header. + */ +public class ETagInformation { + private final boolean all; + private final Collection eTags; + + public ETagInformation(final boolean all, final Collection eTags) { + this.all = all; + this.eTags = eTags; + } + + /** + * Gets the information whether the values contain "*". + */ + public boolean isAll() { + return all; + } + + /** + * Gets the collection of ETag values found. + * It is empty if {@link #isAll()} returns true. + */ + public Collection getETags() { + return eTags; + } + + /** + *

Checks whether a given ETag value is matched by this ETag information, + * using weak comparison as described in + * RFC 7232, section 2.3.2.

+ *

If the given value is null, or if this ETag information + * does not contain anything, the result is false.

+ * @param eTag the ETag value to match + * @return a boolean match result + */ + public boolean isMatchedBy(final String eTag) { + if (eTag == null) { + return false; + } else if (all) { + return true; + } else { + for (final String candidate : eTags) { + if ((eTag.startsWith("W/") ? eTag.substring(2) : eTag) + .equals(candidate.startsWith("W/") ? candidate.substring(2) : candidate)) { + return true; + } + } + return false; + } + } +} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java index 87c6a176d..2a628c4af 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/EtagInformation.java @@ -23,13 +23,13 @@ import java.util.Collection; /** * Information about the values of an ETag-relevant HTTP header. */ -public class EtagInformation { +public class ETagInformation { private final boolean all; - private final Collection etags; + private final Collection eTags; - public EtagInformation(final boolean all, final Collection etags) { + public ETagInformation(final boolean all, final Collection eTags) { this.all = all; - this.etags = etags; + this.eTags = eTags; } /** @@ -43,8 +43,8 @@ public class EtagInformation { * Gets the collection of ETag values found. * It is empty if {@link #isAll()} returns true. */ - public Collection getEtags() { - return etags; + public Collection getETags() { + return eTags; } /** @@ -53,17 +53,17 @@ public class EtagInformation { * RFC 7232, section 2.3.2.

*

If the given value is null, or if this ETag information * does not contain anything, the result is false.

- * @param etag the ETag value to match + * @param eTag the ETag value to match * @return a boolean match result */ - public boolean isMatchedBy(final String etag) { - if (etag == null) { + public boolean isMatchedBy(final String eTag) { + if (eTag == null) { return false; } else if (all) { return true; } else { - for (final String candidate : etags) { - if ((etag.startsWith("W/") ? etag.substring(2) : etag) + for (final String candidate : eTags) { + if ((eTag.startsWith("W/") ? eTag.substring(2) : eTag) .equals(candidate.startsWith("W/") ? candidate.substring(2) : candidate)) { return true; } 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 1acd16363..2ea9ec7a8 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 @@ -118,11 +118,11 @@ public abstract class OData { public abstract EdmPrimitiveType createPrimitiveTypeInstance(EdmPrimitiveTypeKind kind); /** - * Creates Etag information from the values of a HTTP header + * 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 + * @return an {@link ETagInformation} instance */ - public abstract EtagInformation createEtagInformation(final Collection values); + public abstract ETagInformation createETagInformation(final Collection values); } 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/ETagParser.java new file mode 100644 index 000000000..268c6c650 --- /dev/null +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ETagParser.java @@ -0,0 +1,86 @@ +/* + * 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; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + *

Parses the values of HTTP header fields that contain a list of entity tags or a + * single star character, i.e., If-Match and If-None-Match.

+ *

See RFC 7232 for details; + * there the following grammar is defined:

+ *
+ *     If-Match      = "*" / 1#entity-tag
+ *     If-None-Match = "*" / 1#entity-tag
+ *     entity-tag    = [ weak ] opaque-tag
+ *     weak          = %x57.2F ; "W/", case-sensitive
+ *     opaque-tag    = DQUOTE *etagc DQUOTE
+ *     etagc         = %x21 / %x23-7E / %x80-FF
+ * 
+ *

Values with illegal syntax do not contribute to the result but no exception is thrown.

+ */ +public class ETagParser { + + private static final Pattern ETAG = Pattern.compile("\\s*(,\\s*)+|((?:W/)?\"[!#-~\\x80-\\xFF]*\")"); + + protected static Collection parse(final Collection values) { + if (values == null) { + return Collections. emptySet(); + } + + Set result = new HashSet(); + for (final String value : values) { + final Collection part = parse(value); + if (part.size() == 1 && part.iterator().next().equals("*")) { + return part; + } else { + result.addAll(part); + } + } + return result; + } + + private static Collection parse(final String value) { + if (value.trim().equals("*")) { + return Collections.singleton("*"); + } else { + Set result = new HashSet(); + String separator = ""; + int start = 0; + Matcher matcher = ETAG.matcher(value.trim()); + while (matcher.find() && matcher.start() == start) { + start = matcher.end(); + if (matcher.group(1) != null) { + separator = matcher.group(1); + } else if (separator != null) { + result.add(matcher.group(2)); + separator = null; + } else { + return Collections. emptySet(); + } + } + return matcher.hitEnd() ? result : Collections. emptySet(); + } + } +} 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/EtagParser.java index f5477c0ef..268c6c650 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/EtagParser.java @@ -40,7 +40,7 @@ import java.util.regex.Pattern; * *

Values with illegal syntax do not contribute to the result but no exception is thrown.

*/ -public class EtagParser { +public class ETagParser { private static final Pattern ETAG = Pattern.compile("\\s*(,\\s*)+|((?:W/)?\"[!#-~\\x80-\\xFF]*\")"); 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 b43497f43..b6468d73e 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 @@ -96,7 +96,7 @@ public class ODataHandler { } catch (PreconditionRequiredException e) { ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); handleException(request, response, serverError); - }catch (ODataHandlerException e) { + } catch (ODataHandlerException e) { ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); handleException(request, response, serverError); } catch (ODataApplicationException e) { @@ -175,7 +175,7 @@ public class ODataHandler { public void register(final CustomContentTypeSupport customContentTypeSupport) { this.customContentTypeSupport = customContentTypeSupport; } - + public CustomContentTypeSupport getCustomContentTypeSupport() { return customContentTypeSupport; } 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 3b13717de..e3cbd6d22 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 @@ -27,7 +27,7 @@ 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.ETagInformation; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; import org.apache.olingo.server.api.ServiceMetadata; @@ -119,10 +119,10 @@ 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 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-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java index c42f7dfee..e9e1e6a54 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/PreconditionRequiredException.java @@ -24,7 +24,9 @@ public class PreconditionRequiredException extends ODataTranslatedException { private static final long serialVersionUID = -8112658467394158700L; public static enum MessageKeys implements MessageKey { + /** no parameter */ MISSING_HEADER, + /** no parameter */ INVALID_URI; @Override @@ -39,8 +41,7 @@ public class PreconditionRequiredException extends ODataTranslatedException { } public PreconditionRequiredException(final String developmentMessage, final Throwable cause, - final MessageKey messageKey, - final String... parameters) { + final MessageKey messageKey, final String... parameters) { super(developmentMessage, cause, messageKey, parameters); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFascadeImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java similarity index 93% rename from lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFascadeImpl.java rename to lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java index 31a73d34a..4a9ca4bcc 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFascadeImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchFacadeImpl.java @@ -28,10 +28,10 @@ import org.apache.olingo.server.api.processor.BatchProcessor; import org.apache.olingo.server.core.ODataHandler; import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon; -public class BatchFascadeImpl implements BatchFacade { +public class BatchFacadeImpl implements BatchFacade { private final BatchPartHandler partHandler; - public BatchFascadeImpl(final ODataHandler oDataHandler, final ODataRequest request, + public BatchFacadeImpl(final ODataHandler oDataHandler, final ODataRequest request, final BatchProcessor batchProcessor, final boolean isStrict) { partHandler = new BatchPartHandler(oDataHandler, batchProcessor, this); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java index 3f6380437..6e6bc90c6 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/batchhandler/BatchHandler.java @@ -45,7 +45,7 @@ public class BatchHandler { throws DeserializerException, SerializerException { validateRequest(request); - final BatchFacade operation = new BatchFascadeImpl(oDataHandler, request, batchProcessor, isStrict); + final BatchFacade operation = new BatchFacadeImpl(oDataHandler, request, batchProcessor, isStrict); batchProcessor.processBatch(operation, request, response); } 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/ETagParserTest.java new file mode 100644 index 000000000..a72921959 --- /dev/null +++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ETagParserTest.java @@ -0,0 +1,131 @@ +/* + * 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; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.hasItems; +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 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(); + + @Test + public void empty() { + final ETagInformation eTagInformation = odata.createETagInformation(null); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); + } + + @Test + public void loneStar() { + final ETagInformation eTagInformation = odata.createETagInformation(Collections.singleton("*")); + assertTrue(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); + } + + @Test + public void starWins() { + final ETagInformation eTagInformation = odata.createETagInformation(Arrays.asList("\"ETag\"", "*")); + assertTrue(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); + } + + @Test + public void starAsEtagAndEmptyEtag() { + final ETagInformation eTagInformation = odata.createETagInformation( + Collections.singleton("\"*\", \"\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems("\"*\"", "\"\"")); + } + + @Test + public void severalEtags() { + final ETagInformation eTagInformation = odata.createETagInformation( + Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(3)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\"")); + } + + @Test + public void duplicateEtagValues() { + final ETagInformation eTagInformation = odata.createETagInformation( + Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(3)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\"")); + } + + @Test + public void specialCharacters() { + final ETagInformation eTagInformation = odata.createETagInformation( + Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\", \"ETag2\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems( + "\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\"", "\"ETag2\"")); + } + + @Test + public void wrongFormat() { + final ETagInformation eTagInformation = odata.createETagInformation( + Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5", + "\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"", + "\"ETag 9\"", "\"ETag10\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag10\"")); + } + + @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\"")) + .isMatchedBy("\"ETag4\"")); + assertFalse(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) + .isMatchedBy("\"ETag5\"")); + } +} 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/EtagParserTest.java index 51c89d3f7..a72921959 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/EtagParserTest.java @@ -28,104 +28,104 @@ 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.ETagInformation; import org.apache.olingo.server.api.OData; import org.junit.Test; -public class EtagParserTest { +public class ETagParserTest { private static final OData odata = OData.newInstance(); @Test public void empty() { - final EtagInformation etagInformation = odata.createEtagInformation(null); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertTrue(etagInformation.getEtags().isEmpty()); + final ETagInformation eTagInformation = odata.createETagInformation(null); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); } @Test public void loneStar() { - final EtagInformation etagInformation = odata.createEtagInformation(Collections.singleton("*")); - assertTrue(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertTrue(etagInformation.getEtags().isEmpty()); + final ETagInformation eTagInformation = odata.createETagInformation(Collections.singleton("*")); + assertTrue(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); } @Test public void starWins() { - final EtagInformation etagInformation = odata.createEtagInformation(Arrays.asList("\"ETag\"", "*")); - assertTrue(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertTrue(etagInformation.getEtags().isEmpty()); + final ETagInformation eTagInformation = odata.createETagInformation(Arrays.asList("\"ETag\"", "*")); + assertTrue(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertTrue(eTagInformation.getETags().isEmpty()); } @Test public void starAsEtagAndEmptyEtag() { - final EtagInformation etagInformation = odata.createEtagInformation( + final ETagInformation eTagInformation = odata.createETagInformation( Collections.singleton("\"*\", \"\"")); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertThat(etagInformation.getEtags().size(), equalTo(2)); - assertThat(etagInformation.getEtags(), hasItems("\"*\"", "\"\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems("\"*\"", "\"\"")); } @Test public void severalEtags() { - final EtagInformation etagInformation = odata.createEtagInformation( + final ETagInformation eTagInformation = odata.createETagInformation( Arrays.asList("\"ETag1\"", "\"ETag2\",, , ,W/\"ETag3\", ,")); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertThat(etagInformation.getEtags().size(), equalTo(3)); - assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(3)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag3\"")); } @Test public void duplicateEtagValues() { - final EtagInformation etagInformation = odata.createEtagInformation( + final ETagInformation eTagInformation = odata.createETagInformation( Arrays.asList("\"ETag1\"", "\"ETag2\", W/\"ETag1\", \"ETag1\"")); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertThat(etagInformation.getEtags().size(), equalTo(3)); - assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(3)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag2\"", "W/\"ETag1\"")); } @Test public void specialCharacters() { - final EtagInformation etagInformation = odata.createEtagInformation( + final ETagInformation eTagInformation = odata.createETagInformation( Collections.singleton("\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\", \"ETag2\"")); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertThat(etagInformation.getEtags().size(), equalTo(2)); - assertThat(etagInformation.getEtags(), hasItems( + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems( "\"!#$%&'()*+,-./:;<=>?@[]^_`{|}~¡\u00FF\"", "\"ETag2\"")); } @Test public void wrongFormat() { - final EtagInformation etagInformation = odata.createEtagInformation( + final ETagInformation eTagInformation = odata.createETagInformation( Arrays.asList("\"ETag1\", ETag2", "w/\"ETag3\"", "W//\"ETag4\"", "W/ETag5", "\"\"ETag6\"\"", " \"ETag7\"\"ETag7\" ", "\"ETag8\" \"ETag8\"", "\"ETag 9\"", "\"ETag10\"")); - assertFalse(etagInformation.isAll()); - assertNotNull(etagInformation.getEtags()); - assertThat(etagInformation.getEtags().size(), equalTo(2)); - assertThat(etagInformation.getEtags(), hasItems("\"ETag1\"", "\"ETag10\"")); + assertFalse(eTagInformation.isAll()); + assertNotNull(eTagInformation.getETags()); + assertThat(eTagInformation.getETags().size(), equalTo(2)); + assertThat(eTagInformation.getETags(), hasItems("\"ETag1\"", "\"ETag10\"")); } @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(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\"")) .isMatchedBy("\"ETag4\"")); - assertFalse(odata.createEtagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) + assertFalse(odata.createETagInformation(Arrays.asList("\"ETag1\",\"ETag2\"", "\"ETag3\",\"ETag4\"")) .isMatchedBy("\"ETag5\"")); } } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java index d891e4c19..911ab25a4 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/DataProvider.java @@ -578,8 +578,8 @@ public class DataProvider { } } } - - private Entity getEntityByReference(final String entityId, final String rawServiceRoot) + + protected Entity getEntityByReference(final String entityId, final String rawServiceRoot) throws DataProviderException { try { final UriResourceEntitySet uriResource = odata.createUriHelper().parseEntityId(edm, entityId, rawServiceRoot); @@ -594,7 +594,7 @@ public class DataProvider { throw new DataProviderException("Invalid entity-id", HttpStatusCode.BAD_REQUEST); } } - + public static class DataProviderException extends ODataApplicationException { private static final long serialVersionUID = 5098059649321796156L; @@ -603,7 +603,7 @@ public class DataProvider { } public DataProviderException(final String message) { - super(message, HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), Locale.ROOT); + this(message, HttpStatusCode.INTERNAL_SERVER_ERROR); } public DataProviderException(final String message, final HttpStatusCode statusCode) { diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java index e6bf64fb6..fbe21b528 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/data/RequestValidator.java @@ -27,7 +27,6 @@ import org.apache.olingo.commons.api.data.EntityCollection; import org.apache.olingo.commons.api.data.Link; import org.apache.olingo.commons.api.data.Linked; import org.apache.olingo.commons.api.data.Property; -import org.apache.olingo.commons.api.edm.Edm; import org.apache.olingo.commons.api.edm.EdmBindingTarget; import org.apache.olingo.commons.api.edm.EdmComplexType; import org.apache.olingo.commons.api.edm.EdmEntityType; @@ -35,35 +34,23 @@ import org.apache.olingo.commons.api.edm.EdmNavigationProperty; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.commons.api.http.HttpStatusCode; -import org.apache.olingo.server.api.deserializer.DeserializerException; -import org.apache.olingo.server.api.uri.UriHelper; -import org.apache.olingo.server.api.uri.UriResourceEntitySet; import org.apache.olingo.server.tecsvc.data.DataProvider.DataProviderException; public class RequestValidator { - private DataProvider provider; - private boolean isInsert; - private boolean isPatch; - private UriHelper uriHelper; - private Edm edm; - private String rawServiceRoot; + private final DataProvider provider; + private final boolean isInsert; + private final boolean isPatch; + private final String rawServiceRoot; - public RequestValidator(final DataProvider provider, final UriHelper uriHelper, - final Edm edm, final String rawServiceRoot) { - this.provider = provider; - isInsert = true; - this.uriHelper = uriHelper; - this.edm = edm; - this.rawServiceRoot = rawServiceRoot; + public RequestValidator(final DataProvider provider, final String rawServiceRoot) { + this(provider, false, false, rawServiceRoot); } public RequestValidator(final DataProvider provider, final boolean isUpdate, final boolean isPatch, - final UriHelper uriHelper, final Edm edm, final String rawServiceRoot) { + final String rawServiceRoot) { this.provider = provider; - isInsert = !isUpdate; + this.isInsert = !isUpdate; this.isPatch = isPatch; - this.uriHelper = uriHelper; - this.edm = edm; this.rawServiceRoot = rawServiceRoot; } @@ -89,15 +76,15 @@ public class RequestValidator { newPath.add(edmProperty.getName()); final EdmBindingTarget target = edmBindingTarget.getRelatedBindingTarget(buildPath(newPath)); - final ValidatioResult bindingResult = validateBinding(navigationBinding, edmProperty, target); - final ValidatioResult linkResult = validateNavigationLink(navigationLink, + final ValidationResult bindingResult = validateBinding(navigationBinding, edmProperty); + final ValidationResult linkResult = validateNavigationLink(navigationLink, edmProperty, target); if ((isInsert && !edmProperty.isNullable() - && (bindingResult != ValidatioResult.FOUND - && linkResult != ValidatioResult.FOUND)) - || (!(isInsert && isPatch) && !edmProperty.isNullable() && linkResult == ValidatioResult.EMPTY)) { + && (bindingResult != ValidationResult.FOUND + && linkResult != ValidationResult.FOUND)) + || (!(isInsert && isPatch) && !edmProperty.isNullable() && linkResult == ValidationResult.EMPTY)) { throw new DataProviderException("Navigation property " + navPropertyName + " must not be null", HttpStatusCode.BAD_REQUEST); } @@ -119,35 +106,35 @@ public class RequestValidator { return builder.toString(); } - private ValidatioResult validateBinding(final Link navigationBindung, final EdmNavigationProperty edmProperty, - final EdmBindingTarget edmBindingTarget) throws DataProviderException { - if (navigationBindung == null) { - return ValidatioResult.NOT_FOUND; + private ValidationResult validateBinding(final Link navigationBinding, final EdmNavigationProperty edmProperty) + throws DataProviderException { + if (navigationBinding == null) { + return ValidationResult.NOT_FOUND; } if (edmProperty.isCollection()) { - if (navigationBindung.getBindingLinks().size() == 0) { - return ValidatioResult.EMPTY; + if (navigationBinding.getBindingLinks().size() == 0) { + return ValidationResult.EMPTY; } - for (final String bindingLink : navigationBindung.getBindingLinks()) { - validateLink(bindingLink, edmBindingTarget); + for (final String bindingLink : navigationBinding.getBindingLinks()) { + validateLink(bindingLink); } } else { - if (navigationBindung.getBindingLink() == null) { - return ValidatioResult.EMPTY; + if (navigationBinding.getBindingLink() == null) { + return ValidationResult.EMPTY; } - validateLink(navigationBindung.getBindingLink(), edmBindingTarget); + validateLink(navigationBinding.getBindingLink()); } - return ValidatioResult.FOUND; + return ValidationResult.FOUND; } - private ValidatioResult validateNavigationLink(final Link navigationLink, final EdmNavigationProperty edmProperty, + private ValidationResult validateNavigationLink(final Link navigationLink, final EdmNavigationProperty edmProperty, final EdmBindingTarget edmBindingTarget) throws DataProviderException { if (navigationLink == null) { - return ValidatioResult.NOT_FOUND; + return ValidationResult.NOT_FOUND; } if (edmProperty.isCollection()) { @@ -168,21 +155,11 @@ public class RequestValidator { } } - return ValidatioResult.FOUND; + return ValidationResult.FOUND; } - private void validateLink(final String bindingLink, final EdmBindingTarget edmBindungTarget) - throws DataProviderException { - try { - final UriResourceEntitySet uriInfo = uriHelper.parseEntityId(edm, bindingLink, rawServiceRoot); - final Entity entity = provider.read(uriInfo.getEntitySet(), uriInfo.getKeyPredicates()); - - if (entity == null) { - throw new DataProviderException("Entity not found", HttpStatusCode.NOT_FOUND); - } - } catch (DeserializerException e) { - throw new DataProviderException("Invalid binding link", HttpStatusCode.BAD_REQUEST); - } + private void validateLink(final String bindingLink) throws DataProviderException { + provider.getEntityByReference(bindingLink, rawServiceRoot); } private void validateEntitySetProperties(final List properties, final EdmBindingTarget edmBindingTarget, @@ -190,7 +167,7 @@ public class RequestValidator { validateProperties(properties, edmBindingTarget, edmType, edmType.getKeyPredicateNames(), path); } - private void validateProperties(final List properties, final EdmBindingTarget edmBingingTarget, + private void validateProperties(final List properties, final EdmBindingTarget edmBindingTarget, final EdmStructuredType edmType, final List keyPredicateNames, final List path) throws DataProviderException { @@ -212,7 +189,7 @@ public class RequestValidator { } // Validate property value - validatePropertyValue(property, edmProperty, edmBingingTarget, path); + validatePropertyValue(property, edmProperty, edmBindingTarget, path); } } } @@ -259,7 +236,7 @@ public class RequestValidator { return null; } - private static enum ValidatioResult { + private static enum ValidationResult { FOUND, NOT_FOUND, EMPTY 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 6ed5669b7..98b88e3c4 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 @@ -159,10 +159,8 @@ public class TechnicalEntityProcessor extends TechnicalProcessor final DeserializerResult deserializerResult = odata.createDeserializer(ODataFormat.fromContentType(requestFormat)) .entity(request.getBody(), edmEntityType); - new RequestValidator(dataProvider, - odata.createUriHelper(), - serviceMetadata.getEdm(), - request.getRawBaseUri()).validate(edmEntitySet, deserializerResult.getEntity()); + new RequestValidator(dataProvider, request.getRawBaseUri()) + .validate(edmEntitySet, deserializerResult.getEntity()); entity = dataProvider.create(edmEntitySet); dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, deserializerResult.getEntity(), false, @@ -213,8 +211,6 @@ public class TechnicalEntityProcessor extends TechnicalProcessor new RequestValidator(dataProvider, true, // Update request.getMethod() == HttpMethod.PATCH, - odata.createUriHelper(), - serviceMetadata.getEdm(), request.getRawBaseUri()).validate(edmEntitySet, changedEntity); dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity, 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 541c6d206..b9e32fe2a 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 @@ -32,7 +32,7 @@ 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.ETagInformation; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ServiceMetadata; @@ -262,12 +262,12 @@ public abstract class TechnicalProcessor implements Processor { final Collection ifMatchHeaders, final Collection ifNoneMatchHeaders) throws ODataApplicationException { if (eTag != null) { - final EtagInformation ifMatch = odata.createEtagInformation(ifMatchHeaders); - if (!ifMatch.isMatchedBy(eTag) && !ifMatch.getEtags().isEmpty()) { + 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)) { + if (odata.createETagInformation(ifNoneMatchHeaders).isMatchedBy(eTag)) { throw new ODataApplicationException("The entity has not been modified.", HttpStatusCode.NOT_MODIFIED.getStatusCode(), Locale.ROOT); } @@ -278,9 +278,9 @@ public abstract class TechnicalProcessor implements Processor { 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() + 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-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/TypedOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/TypedOperand.java index 17097c9da..4eed3db29 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/TypedOperand.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/TypedOperand.java @@ -27,7 +27,6 @@ import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; -import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull; public class TypedOperand extends VisitorOperand { @@ -56,7 +55,7 @@ public class TypedOperand extends VisitorOperand { @Override public TypedOperand asTypedOperand(final EdmPrimitiveType... asTypes) throws ODataApplicationException { - if (type.equals(EdmNull.getInstance())) { + if (is(primNull)) { return this; } else if (isNull()) { return new TypedOperand(null, asTypes[0]); @@ -103,7 +102,7 @@ public class TypedOperand extends VisitorOperand { if (type == oType && value != null && other.getValue() != null && value.getClass() == other.getValue().getClass()) { return this; - } else if (isNullLiteral() || other.isNullLiteral()) { + } else if (is(primNull) || other.is(primNull)) { return this; } @@ -132,16 +131,12 @@ public class TypedOperand extends VisitorOperand { return clazz.cast(value); } - public boolean isNullLiteral() { - return type.equals(EdmNull.getInstance()); - } - public boolean isNull() { - return isNullLiteral() || value == null; + return is(primNull) || value == null; } public boolean isIntegerType() { - return is( + return is(primNull, primByte, primSByte, primInt16, @@ -150,23 +145,18 @@ public class TypedOperand extends VisitorOperand { } public boolean isDecimalType() { - return is( + return is(primNull, primSingle, primDouble, primDecimal); } public boolean is(final EdmPrimitiveType... types) { - if (isNullLiteral()) { - return true; - } - for (EdmPrimitiveType type : types) { if (type.equals(this.type)) { return true; } } - return false; } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/UntypedOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/UntypedOperand.java index f9652da63..ffc4a62ab 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/UntypedOperand.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/UntypedOperand.java @@ -24,7 +24,6 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveType; import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; -import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull; public class UntypedOperand extends VisitorOperand { @@ -43,8 +42,8 @@ public class UntypedOperand extends VisitorOperand { Object newValue = null; // First try the null literal - if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) { - return new TypedOperand(newValue, EdmNull.getInstance()); + if ((newValue = tryCast(literal, primNull)) != null) { + return new TypedOperand(newValue, primNull); } // Than try the given types @@ -65,8 +64,8 @@ public class UntypedOperand extends VisitorOperand { Object newValue = null; // Null literal - if ((newValue = tryCast(literal, EdmNull.getInstance())) != null) { - return new TypedOperand(newValue, EdmNull.getInstance()); + if (primNull.validate(literal, null, null, null, null, null)) { + return new TypedOperand(newValue, primNull); } // String diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/VisitorOperand.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/VisitorOperand.java index 5b2a8086b..bc4bfd582 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/VisitorOperand.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operand/VisitorOperand.java @@ -29,11 +29,13 @@ import org.apache.olingo.commons.api.edm.EdmProperty; import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; +import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull; public abstract class VisitorOperand { final static private HashMap> defaultTypeMapping = new HashMap>(); protected Object value; protected static final OData oData; + protected static final EdmPrimitiveType primNull = EdmNull.getInstance(); protected static final EdmPrimitiveType primString; protected static final EdmPrimitiveType primBoolean; protected static final EdmPrimitiveType primDateTimeOffset; diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operation/MethodCallOperator.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operation/MethodCallOperator.java index 763d458a0..77185af81 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operation/MethodCallOperator.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/operation/MethodCallOperator.java @@ -37,6 +37,7 @@ import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.TypedOperand; import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.operand.VisitorOperand; +import org.apache.olingo.server.tecsvc.processor.queryoptions.expression.primitive.EdmNull; public class MethodCallOperator { @@ -317,8 +318,10 @@ public class MethodCallOperator { throws ODataApplicationException { final TypedOperand operand = parameters.get(0).asTypedOperand(); - if (operand.is(expectedTypes)) { - if (!operand.isNull()) { + if (operand.isNull()) { + return new TypedOperand(null, EdmNull.getInstance()); + } else { + if (operand.is(expectedTypes)) { Calendar calendar = null; if (operand.is(primDate)) { calendar = operand.getTypedValue(Calendar.class); @@ -331,13 +334,10 @@ public class MethodCallOperator { } else { throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); } - return new TypedOperand(f.perform(calendar, operand), returnType); } else { - return new TypedOperand(null, returnType); - } - } else { throw new ODataApplicationException("Invalid type", HttpStatusCode.BAD_REQUEST.getStatusCode(), Locale.ROOT); + } } } @@ -345,7 +345,7 @@ public class MethodCallOperator { throws ODataApplicationException { List stringParameters = getParametersAsString(); if (stringParameters.contains(null)) { - return new TypedOperand(null, returnValue); + return new TypedOperand(null, EdmNull.getInstance()); } else { return new TypedOperand(f.perform(stringParameters), returnValue); } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/primitive/EdmNull.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/primitive/EdmNull.java index ae0f514c7..cf4d5a974 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/primitive/EdmNull.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/queryoptions/expression/primitive/EdmNull.java @@ -31,15 +31,26 @@ public final class EdmNull implements EdmPrimitiveType { return instance; } + @Override + public String getNamespace() { + return EDM_NAMESPACE; + } + + @Override + public String getName() { + return getClass().getSimpleName().substring(3); + } + + @Override + public EdmTypeKind getKind() { + return EdmTypeKind.PRIMITIVE; + } + @Override public Class getDefaultType() { return Object.class; } - protected String uriPrefix = ""; - - protected String uriSuffix = ""; - @Override public FullQualifiedName getFullQualifiedName() { return new FullQualifiedName(getNamespace(), getName()); @@ -54,13 +65,8 @@ public final class EdmNull implements EdmPrimitiveType { public boolean validate(final String value, final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isUnicode) { - - try { - valueOfString(value, isNullable, maxLength, precision, scale, isUnicode, getDefaultType()); - return true; - } catch (final EdmPrimitiveTypeException e) { - return false; - } + return value == null && (isNullable == null || isNullable) + || value.equals("null"); } @Override @@ -68,14 +74,17 @@ public final class EdmNull implements EdmPrimitiveType { final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale, final Boolean isUnicode, final Class returnType) throws EdmPrimitiveTypeException { - if (value == null) { if (isNullable != null && !isNullable) { throw new EdmPrimitiveTypeException("The literal 'null' is not allowed."); } return null; } - return internalValueOfString(value, isNullable, maxLength, precision, scale, isUnicode, returnType); + if (value.equals("null")) { + return null; + } else { + throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content."); + } } @Override @@ -88,28 +97,17 @@ public final class EdmNull implements EdmPrimitiveType { } return null; } - return internalValueToString(value, isNullable, maxLength, precision, scale, isUnicode); + return "null"; } @Override public String toUriLiteral(final String literal) { - return literal == null ? null : - uriPrefix.isEmpty() && uriSuffix.isEmpty() ? literal : uriPrefix + literal + uriSuffix; + return literal == null ? null : literal; } @Override public String fromUriLiteral(final String literal) throws EdmPrimitiveTypeException { - if (literal == null) { - return null; - } else if (uriPrefix.isEmpty() && uriSuffix.isEmpty()) { - return literal; - } else if (literal.length() >= uriPrefix.length() + uriSuffix.length() - && literal.startsWith(uriPrefix) && literal.endsWith(uriSuffix)) { - - return literal.substring(uriPrefix.length(), literal.length() - uriSuffix.length()); - } else { - throw new EdmPrimitiveTypeException("The literal '" + literal + "' has illegal content."); - } + return literal == null ? null : literal; } @Override @@ -117,26 +115,6 @@ public final class EdmNull implements EdmPrimitiveType { return new FullQualifiedName(getNamespace(), getName()).getFullQualifiedNameAsString(); } - protected T internalValueOfString(final String value, final Boolean isNullable, final Integer maxLength, - final Integer precision, - final Integer scale, final Boolean isUnicode, final Class returnType) throws EdmPrimitiveTypeException { - if (!value.equals("null")) { - throw new EdmPrimitiveTypeException("The literal '" + value + "' has illegal content."); - } - - if (returnType.isAssignableFrom(Object.class)) { - return returnType.cast(new Object()); - } else { - throw new ClassCastException("unsupported return type " + returnType.getSimpleName()); - } - } - - protected String internalValueToString(final T value, final Boolean isNullable, final Integer maxLength, - final Integer precision, - final Integer scale, final Boolean isUnicode) throws EdmPrimitiveTypeException { - return "null"; - } - @Override public boolean equals(final Object obj) { return this == obj || obj != null && getClass() == obj.getClass(); @@ -146,20 +124,4 @@ public final class EdmNull implements EdmPrimitiveType { public int hashCode() { return getClass().hashCode(); } - - @Override - public String getNamespace() { - return EDM_NAMESPACE; - } - - @Override - public String getName() { - return getClass().getSimpleName().substring(3); - } - - @Override - public EdmTypeKind getKind() { - return EdmTypeKind.PRIMITIVE; - } - }