From 23815dc61c5d6c8d1070c1fd5cf7a40a9d8b1a5c Mon Sep 17 00:00:00 2001 From: Klaus Straubinger Date: Fri, 19 Jun 2015 10:29:37 +0200 Subject: [PATCH 1/3] [OLINGO-659] clean-up dispatcher tests Change-Id: I271f84b065a476a0dcf9c13480280e41bf9dfce5 Signed-off-by: Christian Amend --- .../olingo/server/core/ODataHandlerTest.java | 62 ++++++------------- 1 file changed, 19 insertions(+), 43 deletions(-) diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java index 755c4f140..ec5a33d95 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java @@ -29,12 +29,8 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; -import java.util.Arrays; import java.util.Collections; -import java.util.List; import java.util.Locale; -import java.util.Map; -import java.util.Set; import org.apache.commons.io.IOUtils; import org.apache.olingo.commons.api.ODataException; @@ -48,12 +44,13 @@ import org.apache.olingo.commons.api.http.HttpContentType; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpStatusCode; -import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataRequest; 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.batch.BatchFacade; import org.apache.olingo.server.api.edmx.EdmxReference; import org.apache.olingo.server.api.processor.ActionComplexCollectionProcessor; import org.apache.olingo.server.api.processor.ActionComplexProcessor; @@ -247,8 +244,9 @@ public class ODataHandlerTest { final String uri = "$batch"; final BatchProcessor processor = mock(BatchProcessor.class); - dispatch(HttpMethod.POST, uri, processor); - // TODO: Verify that batch processing has been called. + dispatch(HttpMethod.POST, uri, null, HttpHeader.CONTENT_TYPE, ContentType.MULTIPART_MIXED.toContentTypeString(), + processor); + verify(processor).processBatch(any(BatchFacade.class), any(ODataRequest.class), any(ODataResponse.class)); dispatchMethodNotAllowed(HttpMethod.GET, uri, processor); dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor); @@ -650,7 +648,7 @@ public class ODataHandlerTest { @Test public void dispatchReference() throws Exception { final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimOne/$ref"; - final String uriDeleteMany = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref"; + final String uriMany = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref"; final ReferenceProcessor processor = mock(ReferenceProcessor.class); dispatch(HttpMethod.GET, uri, processor); @@ -665,29 +663,25 @@ public class ODataHandlerTest { verify(processor, times(2)).updateReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); - dispatch(HttpMethod.POST, uri.replace("One", "Many"), processor); + dispatchMethodNotAllowed(HttpMethod.POST, uri, processor); + + dispatch(HttpMethod.POST, uriMany, processor); verify(processor).createReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); - - dispatch(HttpMethod.DELETE, uriDeleteMany, "$id=ESTwoPrim(1)", null, Arrays.asList(new Processor[] { processor })); + + dispatch(HttpMethod.DELETE, uriMany, "$id=ESTwoPrim(1)", null, null, processor); verify(processor).deleteReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class)); - - dispatchMethodNotAllowed(HttpMethod.POST, uri, processor); } - + @Test public void dispatchReferenceCollection() throws Exception { final String uri = "ESAllPrim(0)/NavPropertyETTwoPrimMany/$ref"; final ReferenceCollectionProcessor processor = mock(ReferenceCollectionProcessor.class); - final ReferenceProcessor singleProcessor = mock(ReferenceProcessor.class); - + dispatch(HttpMethod.GET, uri, processor); verify(processor).readReferenceCollection(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); - dispatch(HttpMethod.DELETE, uri, singleProcessor); - verify(singleProcessor).deleteReference(any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class)); - dispatchMethodNotAllowed(HttpMethod.PATCH, uri, processor); dispatchMethodNotAllowed(HttpMethod.PUT, uri, processor); } @@ -696,7 +690,7 @@ public class ODataHandlerTest { public void unsupportedRequestContentType() throws Exception { EntityProcessor processor = mock(EntityProcessor.class); ErrorProcessor errorProcessor = mock(ErrorProcessor.class); - dispatch(HttpMethod.POST, "ESAllPrim", "", HttpHeader.CONTENT_TYPE, "some/unsupported", errorProcessor); + dispatch(HttpMethod.POST, "ESAllPrim", null, HttpHeader.CONTENT_TYPE, "some/unsupported", errorProcessor); verifyZeroInteractions(processor); verify(errorProcessor).processError(any(ODataRequest.class), any(ODataResponse.class), any(ODataServerError.class), @@ -705,19 +699,6 @@ public class ODataHandlerTest { private ODataResponse dispatch(final HttpMethod method, final String path, final String query, final String headerName, final String headerValue, final Processor processor) { - Map> headers = null; - if (headerName != null) { - headers = Collections.singletonMap(headerName, Collections.singletonList(headerValue)); - } - List processors = null; - if (processor != null) { - processors = Collections.singletonList(processor); - } - return dispatch(method, path, query, headers, processors); - } - - private ODataResponse dispatch(final HttpMethod method, final String path, final String query, - final Map> headers, final List processors) { ODataRequest request = new ODataRequest(); request.setMethod(method); request.setRawBaseUri(BASE_URI); @@ -727,14 +708,11 @@ public class ODataHandlerTest { request.setRawODataPath(path); request.setRawQueryPath(query); - if (headers != null) { - Set>> headerSet = headers.entrySet(); - for (Map.Entry> headerItem : headerSet) { - request.addHeader(headerItem.getKey(), headerItem.getValue()); - } + if (headerName != null) { + request.addHeader(headerName, Collections.singletonList(headerValue)); } - if (request.getHeaders(HttpHeader.CONTENT_TYPE) == null) { + if (headerName != HttpHeader.CONTENT_TYPE) { request.addHeader(HttpHeader.CONTENT_TYPE, Collections.singletonList( ODataFormat.JSON.getContentType().toContentTypeString())); } @@ -745,10 +723,8 @@ public class ODataHandlerTest { ODataHandler handler = new ODataHandler(odata, metadata); - if (processors != null && !processors.isEmpty()) { - for (Processor p : processors) { - handler.register(p); - } + if (processor != null) { + handler.register(processor); } final ODataResponse response = handler.process(request); From 971deb5539affbd8167464d27b36fb39d30a0349 Mon Sep 17 00:00:00 2001 From: Klaus Straubinger Date: Fri, 19 Jun 2015 10:36:19 +0200 Subject: [PATCH 2/3] [OLINGO-698] clean-up preferences support Signed-off-by: Christian Amend --- .../fit/tecsvc/client/ActionImportITCase.java | 2 +- .../olingo/fit/tecsvc/client/BasicITCase.java | 6 +- .../tecsvc/client/PrimitiveComplexITCase.java | 2 +- .../client/SystemQueryOptionITCase.java | 2 +- .../header/ODataPreferences.java | 33 ++- .../commons/api/ODataPreferenceNames.java | 46 ++++ .../olingo/server/api/prefer/Preferences.java | 5 +- .../server/api/prefer/PreferencesApplied.java | 49 +++-- .../api/prefer/PreferencesAppliedTest.java | 18 +- .../server/core/prefer/PreferencesImpl.java | 35 ++- .../processor/TechnicalActionProcessor.java | 12 +- .../processor/TechnicalBatchProcessor.java | 2 +- .../processor/TechnicalEntityProcessor.java | 8 +- .../TechnicalPrimitiveComplexProcessor.java | 2 +- .../core/PreconditionsValidatorTest.java | 201 +++++++----------- 15 files changed, 210 insertions(+), 213 deletions(-) create mode 100644 lib/commons-api/src/main/java/org/apache/olingo/commons/api/ODataPreferenceNames.java diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java index 0e68a4ab7..f29fbe301 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/ActionImportITCase.java @@ -80,7 +80,7 @@ public class ActionImportITCase extends AbstractBaseTestITCase { request.setPrefer(getClient().newPreferences().returnMinimal()); final ODataInvokeResponse response = request.execute(); assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); - assertEquals("return=\"minimal\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("return=minimal", response.getHeader(HeaderName.preferenceApplied).iterator().next()); } @Test diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java index 0f3a0995a..64062413e 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BasicITCase.java @@ -415,7 +415,7 @@ public class BasicITCase extends AbstractBaseTestITCase { final ODataEntityCreateResponse response = request.execute(); assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); - assertEquals("return=\"minimal\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("return=minimal", response.getHeader(HeaderName.preferenceApplied).iterator().next()); assertEquals(SERVICE_URI + "/ESTwoPrim(1)", response.getHeader(HttpHeader.LOCATION).iterator().next()); } @@ -696,7 +696,7 @@ public class BasicITCase extends AbstractBaseTestITCase { final ODataEntityUpdateResponse response = request.execute(); assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode()); - assertEquals("return=\"representation\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("return=representation", response.getHeader(HeaderName.preferenceApplied).iterator().next()); assertTrue(response.getBody().getProperty("PropertyString").hasNullValue()); assertEquals(34, response.getBody().getProperty("PropertyDecimal").getPrimitiveValue().toValue()); } @@ -843,7 +843,7 @@ public class BasicITCase extends AbstractBaseTestITCase { request.setPrefer(getClient().newPreferences().returnMinimal()); final ODataEntityUpdateResponse response = request.execute(); assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); - assertEquals("return=\"minimal\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("return=minimal", response.getHeader(HeaderName.preferenceApplied).iterator().next()); final String cookie = response.getHeader(HttpHeader.SET_COOKIE).iterator().next(); final ODataEntityRequest entityRequest = client.getRetrieveRequestFactory() diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java index 485aace87..02d77082f 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/PrimitiveComplexITCase.java @@ -380,7 +380,7 @@ public class PrimitiveComplexITCase extends AbstractBaseTestITCase { final ODataValueUpdateResponse response = request.execute(); assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode()); - assertEquals("return=\"minimal\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("return=minimal", response.getHeader(HeaderName.preferenceApplied).iterator().next()); } @Test 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 9cd8e3466..13ca917cb 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 @@ -268,7 +268,7 @@ public class SystemQueryOptionITCase extends AbstractBaseTestITCase { request.setPrefer(getClient().newPreferences().maxPageSize(7)); final ODataRetrieveResponse response = request.execute(); - assertEquals("odata.maxpagesize=\"7\"", response.getHeader(HeaderName.preferenceApplied).iterator().next()); + assertEquals("odata.maxpagesize=7", response.getHeader(HeaderName.preferenceApplied).iterator().next()); assertEquals(SERVICE_URI + '/' + ES_SERVER_SIDE_PAGING + "?%24skiptoken=1%2A" + 7, response.getBody().getNext().toASCIIString()); } diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/header/ODataPreferences.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/header/ODataPreferences.java index e3e4a22bc..1a659de12 100644 --- a/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/header/ODataPreferences.java +++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/communication/header/ODataPreferences.java @@ -18,6 +18,7 @@ */ package org.apache.olingo.client.api.communication.header; +import org.apache.olingo.commons.api.ODataPreferenceNames; /** * Values of the Prefer header. @@ -67,7 +68,7 @@ public class ODataPreferences { * @return preference. */ public String allowEntityReferences() { - return PreferenceNames.allowEntityReferences.toString(); + return ODataPreferenceNames.ALLOW_ENTITY_REFERENCES.toString(); } /** @@ -130,7 +131,7 @@ public class ODataPreferences { * @return preference. */ public String callback(final String url) { - return PreferenceNames.callback.toString() + ";url=\"" + url + "\""; + return ODataPreferenceNames.CALLBACK.toString() + ";url=\"" + url + "\""; } /** @@ -151,7 +152,7 @@ public class ODataPreferences { * @return preference. */ public String continueOnError() { - return PreferenceNames.continueOnError.toString(); + return ODataPreferenceNames.CONTINUE_ON_ERROR.toString(); } /** @@ -198,7 +199,7 @@ public class ODataPreferences { * @return preference. */ public String includeAnnotations(final String value) { - return PreferenceNames.includeAnnotations.toString() + "=" + value; + return ODataPreferenceNames.INCLUDE_ANNOTATIONS.toString() + "=" + value; } /** @@ -231,7 +232,7 @@ public class ODataPreferences { * @return preference. */ public String maxPageSize(final int size) { - return PreferenceNames.maxPageSize.toString() + "=" + size; + return ODataPreferenceNames.MAX_PAGE_SIZE.toString() + "=" + size; } /** @@ -256,7 +257,7 @@ public class ODataPreferences { * @return preference. */ public String trackChanges() { - return PreferenceNames.trackChanges.toString(); + return ODataPreferenceNames.TRACK_CHANGES.toString(); } /** @@ -291,7 +292,7 @@ public class ODataPreferences { * @return preference. */ public String respondAsync() { - return PreferenceNames.respondAsync.toString(); + return ODataPreferenceNames.RESPOND_ASYNC.toString(); } /** @@ -311,7 +312,7 @@ public class ODataPreferences { * @return preference. */ public String wait(final int value) { - return PreferenceNames.wait.toString() + "=" + value; + return ODataPreferenceNames.WAIT.toString() + "=" + value; } /** @@ -341,7 +342,7 @@ public class ODataPreferences { * @return preference. */ public String returnMinimal() { - return PreferenceNames.odataReturn.toString() + "=minimal"; + return ODataPreferenceNames.RETURN.toString() + "=minimal"; } /** @@ -371,23 +372,15 @@ public class ODataPreferences { * @return preference. */ public String returnRepresentation() { - return PreferenceNames.odataReturn.toString() + "=representation"; + return ODataPreferenceNames.RETURN.toString() + "=representation"; } + /** Preferences not in the OData 4.0 standard. */ private static enum PreferenceNames { returnContent("return-content"), returnNoContent("return-no-content"), - keyAsSegment("KeyAsSegment"), - allowEntityReferences("odata.allow-entityreferences"), - callback("odata.callback"), - continueOnError("odata.continue-on-error"), - includeAnnotations("odata.include-annotations"), - maxPageSize("odata.maxpagesize"), - trackChanges("odata.track-changes"), - respondAsync("respond-async"), - wait("wait"), - odataReturn("return"); + keyAsSegment("KeyAsSegment"); private final String preferenceName; diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/ODataPreferenceNames.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/ODataPreferenceNames.java new file mode 100644 index 000000000..cdd489b04 --- /dev/null +++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/ODataPreferenceNames.java @@ -0,0 +1,46 @@ +/* + * 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.commons.api; + +/** + * Names of preferences defined in the OData standard. + */ +public enum ODataPreferenceNames { + + ALLOW_ENTITY_REFERENCES("odata.allow-entityreferences"), + CALLBACK("odata.callback"), + CONTINUE_ON_ERROR("odata.continue-on-error"), + INCLUDE_ANNOTATIONS("odata.include-annotations"), + MAX_PAGE_SIZE("odata.maxpagesize"), + TRACK_CHANGES("odata.track-changes"), + RETURN("return"), + RESPOND_ASYNC("respond-async"), + WAIT("wait"); + + private final String preferenceName; + + private ODataPreferenceNames(final String preferenceName) { + this.preferenceName = preferenceName; + } + + @Override + public String toString() { + return preferenceName; + } +} diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/Preferences.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/Preferences.java index 91f0d4531..20504741c 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/Preferences.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/Preferences.java @@ -19,6 +19,7 @@ package org.apache.olingo.server.api.prefer; import java.net.URI; +import java.util.Collections; import java.util.Map; /** @@ -101,7 +102,9 @@ public interface Preferences { * @return a map from parameter names to parameter values */ public Map getParameters() { - return parameters; + return parameters == null ? + Collections. emptyMap() : + Collections.unmodifiableMap(parameters); } } } diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/PreferencesApplied.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/PreferencesApplied.java index fd89a3ae3..f7a8146b7 100644 --- a/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/PreferencesApplied.java +++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/prefer/PreferencesApplied.java @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.Locale; import java.util.Map; +import org.apache.olingo.commons.api.ODataPreferenceNames; import org.apache.olingo.server.api.prefer.Preferences.Return; /** @@ -46,8 +47,8 @@ public class PreferencesApplied { return Collections.unmodifiableMap(applied); } - @Override - public String toString() { + /** Returns a string representation that can be used as value of a Preference-Applied HTTP response header. */ + public String toValueString() { StringBuilder result = new StringBuilder(); for (final String name : applied.keySet()) { if (result.length() > 0) { @@ -55,14 +56,28 @@ public class PreferencesApplied { } result.append(name); if (applied.get(name) != null) { - result.append('=').append('"') + final boolean safe = ODataPreferenceNames.ALLOW_ENTITY_REFERENCES.toString().equals(name) + || ODataPreferenceNames.CALLBACK.toString().equals(name) + || ODataPreferenceNames.CONTINUE_ON_ERROR.toString().equals(name) + || ODataPreferenceNames.MAX_PAGE_SIZE.toString().equals(name) + || ODataPreferenceNames.TRACK_CHANGES.toString().equals(name) + || ODataPreferenceNames.RETURN.toString().equals(name) + || ODataPreferenceNames.RESPOND_ASYNC.toString().equals(name) + || ODataPreferenceNames.WAIT.toString().equals(name); + result.append('=') + .append(safe ? "" : '"') .append(applied.get(name).replaceAll("\\\\|\"", "\\\\$0")) - .append('"'); + .append(safe ? "" : '"'); } } return result.toString(); } + @Override + public String toString() { + return toValueString(); + } + /** Initializes the builder. */ public static Builder with() { return new Builder(); @@ -71,16 +86,6 @@ public class PreferencesApplied { /** Builder of OData serializer options. */ public static final class Builder { - private static final String ALLOW_ENTITY_REFERENCES = "odata.allow-entityreferences"; - private static final String CALLBACK = "odata.callback"; - private static final String CONTINUE_ON_ERROR = "odata.continue-on-error"; - // private static final String INCLUDE_ANNOTATIONS = "odata.include-annotations"; - private static final String MAX_PAGE_SIZE = "odata.maxpagesize"; - private static final String TRACK_CHANGES = "odata.track-changes"; - private static final String RETURN = "return"; - private static final String RESPOND_ASYNC = "respond-async"; - private static final String WAIT = "wait"; - private final PreferencesApplied preferencesApplied; private Builder() { @@ -89,49 +94,49 @@ public class PreferencesApplied { /** Sets odata.allow-entityreferences. */ public Builder allowEntityReferences() { - add(ALLOW_ENTITY_REFERENCES, null); + add(ODataPreferenceNames.ALLOW_ENTITY_REFERENCES.toString(), null); return this; } /** Sets odata.callback. */ public Builder callback() { - add(CALLBACK, null); + add(ODataPreferenceNames.CALLBACK.toString(), null); return this; } /** Sets odata.continue-on-error. */ public Builder continueOnError() { - add(CONTINUE_ON_ERROR, null); + add(ODataPreferenceNames.CONTINUE_ON_ERROR.toString(), null); return this; } /** Sets the value of the applied preference odata.maxpagesize. */ public Builder maxPageSize(final Integer maxPageSize) { - add(MAX_PAGE_SIZE, Integer.toString(maxPageSize)); + add(ODataPreferenceNames.MAX_PAGE_SIZE.toString(), Integer.toString(maxPageSize)); return this; } /** Sets odata.track-changes. */ public Builder trackChanges() { - add(TRACK_CHANGES, null); + add(ODataPreferenceNames.TRACK_CHANGES.toString(), null); return this; } /** Sets the value of the applied preference return. */ public Builder returnRepresentation(final Return returnRepresentation) { - add(RETURN, returnRepresentation.name().toLowerCase(Locale.ROOT)); + add(ODataPreferenceNames.RETURN.toString(), returnRepresentation.name().toLowerCase(Locale.ROOT)); return this; } /** Sets odata.respond-async. */ public Builder respondAsync() { - add(RESPOND_ASYNC, null); + add(ODataPreferenceNames.RESPOND_ASYNC.toString(), null); return this; } /** Sets the value of the applied preference wait. */ public Builder waitPreference(final Integer wait) { - add(WAIT, Integer.toString(wait)); + add(ODataPreferenceNames.WAIT.toString(), Integer.toString(wait)); return this; } diff --git a/lib/server-api/src/test/java/org/apache/olingo/server/api/prefer/PreferencesAppliedTest.java b/lib/server-api/src/test/java/org/apache/olingo/server/api/prefer/PreferencesAppliedTest.java index 0d5edf9f4..49948ddaa 100644 --- a/lib/server-api/src/test/java/org/apache/olingo/server/api/prefer/PreferencesAppliedTest.java +++ b/lib/server-api/src/test/java/org/apache/olingo/server/api/prefer/PreferencesAppliedTest.java @@ -27,41 +27,41 @@ public class PreferencesAppliedTest { @Test public void empty() { - assertEquals("", PreferencesApplied.with().build().toString()); + assertEquals("", PreferencesApplied.with().build().toValueString()); } @Test public void all() { assertEquals("odata.allow-entityreferences, odata.callback," - + " odata.continue-on-error, odata.include-annotations=\"*\", odata.maxpagesize=\"42\"," - + " odata.track-changes, return=\"representation\", respond-async, wait=\"12345\"", + + " odata.continue-on-error, odata.include-annotations=\"*\", odata.maxpagesize=42," + + " odata.track-changes, return=representation, respond-async, wait=12345", PreferencesApplied.with().allowEntityReferences().callback().continueOnError() .preference("odata.include-annotations", "*").maxPageSize(42).trackChanges() .returnRepresentation(Return.REPRESENTATION).respondAsync().waitPreference(12345) - .build().toString()); + .build().toValueString()); } @Test public void caseSensitivity() { - assertEquals("odata.include-annotations=\"*\", odata.maxpagesize=\"255\"", + assertEquals("odata.include-annotations=\"*\", odata.maxpagesize=255", PreferencesApplied.with() .preference("OData.Include-Annotations", "*").maxPageSize(0xFF) - .build().toString()); + .build().toValueString()); } @Test public void multipleValues() { - assertEquals("return=\"minimal\", wait=\"1\"", + assertEquals("return=minimal, wait=1", PreferencesApplied.with() .returnRepresentation(Return.MINIMAL).returnRepresentation(Return.REPRESENTATION) .preference(null, null).preference(null, "nullValue") .waitPreference(1).waitPreference(2).waitPreference(3) - .build().toString()); + .build().toValueString()); } @Test public void quotedValue() { assertEquals("strangepreference=\"x\\\\y,\\\"abc\\\"z\"", - PreferencesApplied.with().preference("strangePreference", "x\\y,\"abc\"z").build().toString()); + PreferencesApplied.with().preference("strangePreference", "x\\y,\"abc\"z").build().toValueString()); } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/prefer/PreferencesImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/prefer/PreferencesImpl.java index 9661cd363..50cf89e4d 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/prefer/PreferencesImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/prefer/PreferencesImpl.java @@ -23,6 +23,7 @@ import java.util.Collection; import java.util.Locale; import java.util.Map; +import org.apache.olingo.commons.api.ODataPreferenceNames; import org.apache.olingo.server.api.prefer.Preferences; /** @@ -32,16 +33,6 @@ import org.apache.olingo.server.api.prefer.Preferences; */ public class PreferencesImpl implements Preferences { - private static final String ALLOW_ENTITY_REFERENCES = "odata.allow-entityreferences"; - private static final String CALLBACK = "odata.callback"; - private static final String CONTINUE_ON_ERROR = "odata.continue-on-error"; - // private static final String INCLUDE_ANNOTATIONS = "odata.include-annotations"; - private static final String MAX_PAGE_SIZE = "odata.maxpagesize"; - private static final String TRACK_CHANGES = "odata.track-changes"; - private static final String RETURN = "return"; - private static final String RESPOND_ASYNC = "respond-async"; - private static final String WAIT = "wait"; - private static final String URL = "url"; // parameter name for odata.callback private final Map preferences; @@ -55,15 +46,15 @@ public class PreferencesImpl implements Preferences { } public boolean hasAllowEntityReferences() { - return preferences.containsKey(ALLOW_ENTITY_REFERENCES); + return preferences.containsKey(ODataPreferenceNames.ALLOW_ENTITY_REFERENCES.toString()); } public URI getCallback() { - if (preferences.containsKey(CALLBACK) - && preferences.get(CALLBACK).getParameters() != null - && preferences.get(CALLBACK).getParameters().get(URL) != null) { + if (preferences.containsKey(ODataPreferenceNames.CALLBACK.toString()) + && preferences.get(ODataPreferenceNames.CALLBACK.toString()).getParameters() != null + && preferences.get(ODataPreferenceNames.CALLBACK.toString()).getParameters().get(URL) != null) { try { - return URI.create(preferences.get(CALLBACK).getParameters().get(URL)); + return URI.create(preferences.get(ODataPreferenceNames.CALLBACK.toString()).getParameters().get(URL)); } catch (final IllegalArgumentException e) { return null; } @@ -72,20 +63,20 @@ public class PreferencesImpl implements Preferences { } public boolean hasContinueOnError() { - return preferences.containsKey(CONTINUE_ON_ERROR); + return preferences.containsKey(ODataPreferenceNames.CONTINUE_ON_ERROR.toString()); } public Integer getMaxPageSize() { - return getNonNegativeIntegerPreference(MAX_PAGE_SIZE); + return getNonNegativeIntegerPreference(ODataPreferenceNames.MAX_PAGE_SIZE.toString()); } public boolean hasTrackChanges() { - return preferences.containsKey(TRACK_CHANGES); + return preferences.containsKey(ODataPreferenceNames.TRACK_CHANGES.toString()); } public Return getReturn() { - if (preferences.containsKey(RETURN)) { - final String value = preferences.get(RETURN).getValue(); + if (preferences.containsKey(ODataPreferenceNames.RETURN.toString())) { + final String value = preferences.get(ODataPreferenceNames.RETURN.toString()).getValue(); if (Return.REPRESENTATION.toString().toLowerCase(Locale.ROOT).equals(value)) { return Return.REPRESENTATION; } else if (Return.MINIMAL.toString().toLowerCase(Locale.ROOT).equals(value)) { @@ -96,11 +87,11 @@ public class PreferencesImpl implements Preferences { } public boolean hasRespondAsync() { - return preferences.containsKey(RESPOND_ASYNC); + return preferences.containsKey(ODataPreferenceNames.RESPOND_ASYNC.toString()); } public Integer getWait() { - return getNonNegativeIntegerPreference(WAIT); + return getNonNegativeIntegerPreference(ODataPreferenceNames.WAIT.toString()); } private Integer getNonNegativeIntegerPreference(final String name) { diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalActionProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalActionProcessor.java index b2a9ca421..d7fc00f15 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalActionProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalActionProcessor.java @@ -112,7 +112,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } } @@ -160,7 +160,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } if (entityResult.isCreated()) { response.setHeader(HttpHeader.LOCATION, @@ -213,7 +213,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } } @@ -253,7 +253,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } } } @@ -298,7 +298,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } } @@ -339,7 +339,7 @@ public class TechnicalActionProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } } } diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java index fbdeb908c..a2c76292d 100644 --- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java +++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java @@ -80,7 +80,7 @@ public class TechnicalBatchProcessor extends TechnicalProcessor implements Batch response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode()); if (continueOnError) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().continueOnError().build().toString()); + PreferencesApplied.with().continueOnError().build().toValueString()); } } 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 217d7689e..ccf8189e1 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 @@ -176,7 +176,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } response.setHeader(HttpHeader.LOCATION, request.getRawBaseUri() + '/' + odata.createUriHelper().buildCanonicalURL(edmEntitySet, entity)); @@ -232,7 +232,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } if (entity.getETag() != null) { response.setHeader(HttpHeader.ETAG, entity.getETag()); @@ -266,7 +266,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } if (entity.getETag() != null) { response.setHeader(HttpHeader.ETAG, entity.getETag()); @@ -476,7 +476,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString()); if (pageSize != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().maxPageSize(serverPageSize).build().toString()); + PreferencesApplied.with().maxPageSize(serverPageSize).build().toValueString()); } } 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 6a9af47ec..4d1e83468 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 @@ -325,7 +325,7 @@ public class TechnicalPrimitiveComplexProcessor extends TechnicalProcessor } if (returnPreference != null) { response.setHeader(HttpHeader.PREFERENCE_APPLIED, - PreferencesApplied.with().returnRepresentation(returnPreference).build().toString()); + PreferencesApplied.with().returnRepresentation(returnPreference).build().toValueString()); } if (entity.getETag() != null) { response.setHeader(HttpHeader.ETAG, entity.getETag()); 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 acd578c45..a70bbc7bd 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 @@ -20,245 +20,204 @@ package org.apache.olingo.server.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.List; 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.etag.CustomETagSupport; import org.apache.olingo.server.api.etag.PreconditionException; import org.apache.olingo.server.api.uri.UriInfo; +import org.apache.olingo.server.api.uri.UriResource; +import org.apache.olingo.server.api.uri.UriResourceEntitySet; +import org.apache.olingo.server.api.uri.UriResourceValue; 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; -import org.apache.olingo.server.core.uri.validator.UriValidator; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.junit.Ignore; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; public class PreconditionsValidatorTest { + private static final Edm edm = new EdmProviderImpl(new EdmTechProvider()); + // -------------- POSITIVE TESTS -------------------------------------------------------------------------------- @Test public void simpleEntity() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, "*", "*").validatePreconditions(false); + validate("ESAllPrim(1)", null, "*", "*"); } @Test public void simpleEntityValue() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESMedia(1)/$value", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, "*", "*").validatePreconditions(true); + validate("ESMedia(1)/$value", null, "*", "*"); } @Test public void EntityAndToOneNavigation() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/NavPropertyETTwoPrimOne", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESTwoPrim"), uriInfo, "*", "*").validatePreconditions(false); + validate("ESAllPrim(1)/NavPropertyETTwoPrimOne", "ESTwoPrim", "*", "*"); } @Test public void EntityAndToManyNavigationWithKey() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/NavPropertyETTwoPrimMany(1)", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESTwoPrim"), uriInfo, "*", "*").validatePreconditions(false); + validate("ESAllPrim(1)/NavPropertyETTwoPrimMany(1)", "ESTwoPrim", "*", "*"); } @Test public void EntityAndToOneNavigationValue() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESKeyNav(1)/NavPropertyETMediaOne/$value", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESMedia"), uriInfo, "*", "*").validatePreconditions(true); + validate("ESKeyNav(1)/NavPropertyETMediaOne/$value", "ESMedia", "*", "*"); } @Test public void boundActionOnEsKeyNav() throws Exception { - UriInfo uriInfo = - new Parser().parseUri("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESKeyNav"), uriInfo, "*", "*").validatePreconditions(false); + validate("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", "ESKeyNav", "*", "*"); } @Test public void boundActionOnEsKeyNavWithNavigation() throws Exception { - UriInfo uriInfo = - new Parser().parseUri("ESKeyNav(1)/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null, - null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESKeyNav"), uriInfo, "*", "*").validatePreconditions(false); + validate("ESKeyNav(1)/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", + "ESKeyNav", "*", "*"); } @Test public void singleton() throws Exception { - UriInfo uriInfo = new Parser().parseUri("SI", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("SI"), uriInfo, "*", "*").validatePreconditions(false); + validate("SI", "SI", "*", "*"); } @Test public void singletonWithNavigation() throws Exception { - UriInfo uriInfo = new Parser().parseUri("SINav/NavPropertyETKeyNavOne", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESKeyNav"), uriInfo, "*", "*").validatePreconditions(false); + validate("SINav/NavPropertyETKeyNavOne", "ESKeyNav", "*", "*"); } @Test public void singletonWithNavigationValue() throws Exception { - UriInfo uriInfo = - new Parser().parseUri("SINav/NavPropertyETKeyNavOne/NavPropertyETMediaOne/$value", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("ESMedia"), uriInfo, "*", "*").validatePreconditions(false); + validate("SINav/NavPropertyETKeyNavOne/NavPropertyETMediaOne/$value", "ESMedia", "*", "*"); } @Test public void singletonWithAction() throws Exception { - UriInfo uriInfo = new Parser().parseUri("SINav/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport("SINav"), uriInfo, "*", "*").validatePreconditions(false); + validate("SINav/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", "SINav", "*", "*"); } @Test public void singletonWithActionAndNavigation() throws Exception { - UriInfo uriInfo = - new Parser().parseUri("SINav/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null, null, - getEdm()); - new PreconditionsValidator(new ETagSupport("ESKeyNav"), uriInfo, "*", "*").validatePreconditions(false); + validate("SINav/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", "ESKeyNav", "*", "*"); } @Test public void simpleEntityValueValidationNotActiveForMedia() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESMedia(1)/$value", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(true, false), uriInfo, null, null).validatePreconditions(true); + CustomETagSupport support = mock(CustomETagSupport.class); + when(support.hasETag(any(EdmBindingTarget.class))).thenReturn(true); + when(support.hasMediaETag(any(EdmBindingTarget.class))).thenReturn(false); + + final UriInfo uriInfo = new Parser().parseUri("ESMedia(1)/$value", null, null, edm); + new PreconditionsValidator(support, uriInfo, null, null).validatePreconditions(true); } // -------------- IGNORE VALIDATION TESTS ----------------------------------------------------------------------- @Test public void entitySetMustNotLeadToException() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + validate("ESAllPrim", null, null, null); } @Test public void propertyMustNotLeadToException() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/PropertyInt16", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + validate("ESAllPrim(1)/PropertyInt16", null, null, null); } @Test public void propertyValueMustNotLeadToException() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/PropertyInt16/$value", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(true); + validate("ESAllPrim(1)/PropertyInt16/$value", null, null, null); } @Test public void navigationToManyMustNotLeadToException() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/NavPropertyETTwoPrimMany", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + validate("ESAllPrim(1)/NavPropertyETTwoPrimMany", null, null, null); } @Test public void navigationOnPropertyMustNotLeadToException() throws Exception { - UriInfo uriInfo = new Parser().parseUri("ESAllPrim(1)/NavPropertyETTwoPrimOne/PropertyInt16", null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + validate("ESAllPrim(1)/NavPropertyETTwoPrimOne/PropertyInt16", null, null, null); } @Test public void navigationToManyOnActionMustNotLeadToException() throws Exception { - UriInfo uriInfo = - new Parser().parseUri("ESTwoPrim(1)/NavPropertyETAllPrimMany/Namespace1_Alias.BAESAllPrimRTETAllPrim", null, - null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + validate("ESTwoPrim(1)/NavPropertyETAllPrimMany/Namespace1_Alias.BAESAllPrimRTETAllPrim", null, null, null); } @Test - public void navigationWithoutBindingMustNotLeadToAnException() throws Exception { - UriInfo uriInfo = - new Parser() - .parseUri( - "ESTwoBaseTwoKeyNav(PropertyInt16=1,PropertyString='test')" - + "/NavPropertyETBaseTwoKeyNavMany(PropertyInt16=1,PropertyString='test')", - null, null, getEdm()); - new PreconditionsValidator(new ETagSupport(), uriInfo, null, null).validatePreconditions(false); + public void navigationWithoutBindingMustNotLeadToException() throws Exception { + validate("ESTwoBaseTwoKeyNav(PropertyInt16=1,PropertyString='test')" + + "/NavPropertyETBaseTwoKeyNavMany(PropertyInt16=1,PropertyString='test')", + null, null, null); } // -------------- NEGATIVE TESTS -------------------------------------------------------------------------------- @Test public void positiveTestsMustLeadToAnExceptionIfNoHeaderIsPresent() throws Exception { - runException("ESAllPrim(1)", null); - runException("ESMedia(1)/$value", null); - runException("ESAllPrim(1)/NavPropertyETTwoPrimOne", null); - runException("ESAllPrim(1)/NavPropertyETTwoPrimMany(1)", null); - runException("ESKeyNav(1)/NavPropertyETMediaOne/$value", null); - runException("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null); - runException("ESKeyNav(1)/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null); + runException("ESAllPrim(1)"); + runException("ESMedia(1)/$value"); + runException("ESAllPrim(1)/NavPropertyETTwoPrimOne"); + runException("ESAllPrim(1)/NavPropertyETTwoPrimMany(1)"); + runException("ESKeyNav(1)/NavPropertyETMediaOne/$value"); + runException("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav"); + runException("ESKeyNav(1)/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav"); - runException("SI", null); - runException("SINav/NavPropertyETKeyNavOne", null); - runException("SINav/NavPropertyETKeyNavOne/NavPropertyETMediaOne/$value", null); - runException("SINav/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null); - runException("SINav/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav", null); + runException("SI"); + runException("SINav/NavPropertyETKeyNavOne"); + runException("SINav/NavPropertyETKeyNavOne/NavPropertyETMediaOne/$value"); + runException("SINav/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav"); + runException("SINav/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav"); } @Ignore - @Test + @Test(expected = UriParserSemanticException.class) public void resourceSegmentAfterActionMustLeadToUriParserException() throws Exception { - // TODO: Check with URI Parser - UriInfo uriInfo = - new Parser().parseUri("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav/PropertyInt16", null, null, - getEdm()); - new UriValidator().validate(uriInfo, HttpMethod.GET); - new PreconditionsValidator(new ETagSupport("ESKeyNav"), uriInfo, "*", "*").validatePreconditions(false); + validate("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav/PropertyInt16", "ESKeyNav", "*", "*"); } @Test(expected = UriParserSemanticException.class) public void valueMustBeLastSegment() throws Exception { - new Parser().parseUri("ESMedia(1)/$value/PropertyInt16", null, null, getEdm()); + validate("ESMedia(1)/$value/PropertyInt16", null, null, null); } - private void runException(String uri, String expectedEntitySet) throws UriParserException { - UriInfo uriInfo = new Parser().parseUri(uri, null, null, getEdm()); + private void validate(final String uri, final String entitySetName, final String ifMatch, final String ifNoneMatch) + throws UriParserException, PreconditionException { + final UriInfo uriInfo = new Parser().parseUri(uri, null, null, edm); + final List parts = uriInfo.getUriResourceParts(); + final boolean isMedia = parts.get(parts.size() - 1) instanceof UriResourceValue + && parts.get(parts.size() - 2) instanceof UriResourceEntitySet; + + CustomETagSupport support = mock(CustomETagSupport.class); + final Answer answer = new Answer() { + public Boolean answer(final InvocationOnMock invocation) throws Throwable { + if (entitySetName != null) { + assertEquals(entitySetName, ((EdmBindingTarget) invocation.getArguments()[0]).getName()); + } + return true; + }}; + when(support.hasETag(any(EdmBindingTarget.class))).thenAnswer(answer); + when(support.hasMediaETag(any(EdmBindingTarget.class))).thenAnswer(answer); + + new PreconditionsValidator(support, uriInfo, ifMatch, ifNoneMatch).validatePreconditions(isMedia); + } + + private void runException(final String uri) throws UriParserException { try { - CustomETagSupport etagSupport = - expectedEntitySet == null ? new ETagSupport() : new ETagSupport(expectedEntitySet); - boolean isMedia = uri.endsWith("$value"); - new PreconditionsValidator(etagSupport, uriInfo, null, null).validatePreconditions(isMedia); + validate(uri, null, null, null); fail("Expected a PreconditionRequiredException but was not thrown"); - } catch (PreconditionException e) { + } catch (final PreconditionException e) { assertEquals(PreconditionException.MessageKeys.MISSING_HEADER, e.getMessageKey()); } } - - private Edm getEdm() { - return new EdmProviderImpl(new EdmTechProvider()); - } - - public class ETagSupport implements CustomETagSupport { - - private boolean eTag = true; - private boolean mediaETag = true; - private String entitySetName; - - public ETagSupport() {} - - public ETagSupport(String entitySetName) { - this.entitySetName = entitySetName; - } - - public ETagSupport(boolean eTag, boolean mediaETag) { - this.eTag = eTag; - this.mediaETag = mediaETag; - } - - @Override - public boolean hasETag(EdmBindingTarget entitySetOrSingeton) { - if (this.entitySetName != null) { - assertEquals(this.entitySetName, entitySetOrSingeton.getName()); - } - return eTag; - } - - @Override - public boolean hasMediaETag(EdmBindingTarget entitySetOrSingelton) { - if (this.entitySetName != null) { - assertEquals(this.entitySetName, entitySetOrSingelton.getName()); - } - return mediaETag; - } - } } From fd513e22f1d1a63f014702e3b07b929bdece707f Mon Sep 17 00:00:00 2001 From: Klaus Straubinger Date: Fri, 19 Jun 2015 11:17:38 +0200 Subject: [PATCH 3/3] [OLINGO-659] fix for URI parser to disallow anything after actions Change-Id: I578ee4562d13b220cec7fb05f1b6c9d69c0b25e4 Signed-off-by: Christian Amend --- .../core/uri/UriResourceActionImpl.java | 13 ++++++++++-- .../server/core/uri/UriResourceTypedImpl.java | 8 +------- .../queryoption/expression/MemberImpl.java | 5 +++++ .../core/PreconditionsValidatorTest.java | 2 -- .../core/uri/antlr/TestFullResourcePath.java | 12 +++++++++++ .../core/uri/antlr/TestUriParserImpl.java | 2 +- .../expression/ExpressionTest.java | 20 ++++++++++--------- 7 files changed, 41 insertions(+), 21 deletions(-) diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java index a78d79f1a..6acb6ea27 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceActionImpl.java @@ -24,7 +24,12 @@ import org.apache.olingo.commons.api.edm.EdmType; import org.apache.olingo.server.api.uri.UriResourceAction; import org.apache.olingo.server.api.uri.UriResourceKind; -public class UriResourceActionImpl extends UriResourceTypedImpl implements UriResourceAction { +/** + * Implementation of the {@link UriResourceAction} interface. This class does not extend + * {@link org.apache.olingo.server.core.uri.UriResourceTypedImpl UriResourceTypedImpl} + * since that would allow type filters and subsequent path segments. + */ +public class UriResourceActionImpl extends UriResourceImpl implements UriResourceAction { protected EdmAction action; protected EdmActionImport actionImport; @@ -71,8 +76,12 @@ public class UriResourceActionImpl extends UriResourceTypedImpl implements UriRe } @Override - public String toString() { + public String toString(final boolean includeFilters) { return actionImport == null ? (action == null ? "" : action.getName()) : actionImport.getName(); } + @Override + public String toString() { + return toString(false); + } } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java index d5f01eacf..cef7098b7 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/UriResourceTypedImpl.java @@ -20,7 +20,6 @@ package org.apache.olingo.server.core.uri; import org.apache.olingo.commons.api.edm.EdmStructuredType; import org.apache.olingo.commons.api.edm.EdmType; -import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.server.api.uri.UriResourceKind; import org.apache.olingo.server.api.uri.UriResourcePartTyped; @@ -45,16 +44,11 @@ public abstract class UriResourceTypedImpl extends UriResourceImpl implements Ur public String toString(final boolean includeFilters) { if (includeFilters) { if (typeFilter != null) { - return toString() + "/" + getFQN(typeFilter).toString(); + return toString() + "/" + typeFilter.getFullQualifiedName().toString(); } else { return toString(); } } return toString(); } - - private FullQualifiedName getFQN(final EdmType type) { - return new FullQualifiedName(type.getNamespace(), type.getName()); - } - } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java index 8940bcf13..5f6162fd2 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/expression/MemberImpl.java @@ -25,6 +25,7 @@ import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitEx import org.apache.olingo.server.api.uri.queryoption.expression.ExpressionVisitor; import org.apache.olingo.server.api.uri.queryoption.expression.Member; import org.apache.olingo.server.core.uri.UriInfoImpl; +import org.apache.olingo.server.core.uri.UriResourceActionImpl; import org.apache.olingo.server.core.uri.UriResourceImpl; import org.apache.olingo.server.core.uri.UriResourceTypedImpl; import org.apache.olingo.server.core.uri.UriResourceWithKeysImpl; @@ -69,6 +70,8 @@ public class MemberImpl extends ExpressionImpl implements Member { return type; } return lastTyped.getType(); + } else if (lastResourcePart instanceof UriResourceActionImpl) { + return ((UriResourceActionImpl) lastResourcePart).getType(); } else { return null; } @@ -81,6 +84,8 @@ public class MemberImpl extends ExpressionImpl implements Member { if (lastResourcePart instanceof UriResourceTypedImpl) { UriResourceTypedImpl lastTyped = (UriResourceTypedImpl) lastResourcePart; return lastTyped.isCollection(); + } else if (lastResourcePart instanceof UriResourceActionImpl) { + return ((UriResourceActionImpl) lastResourcePart).isCollection(); } return false; } 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 a70bbc7bd..fae780d20 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 @@ -40,7 +40,6 @@ 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; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; -import org.junit.Ignore; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -180,7 +179,6 @@ public class PreconditionsValidatorTest { runException("SINav/NavPropertyETKeyNavOne/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav"); } - @Ignore @Test(expected = UriParserSemanticException.class) public void resourceSegmentAfterActionMustLeadToUriParserException() throws Exception { validate("ESKeyNav(1)/Namespace1_Alias.BAETTwoKeyNavRTETTwoKeyNav/PropertyInt16", "ESKeyNav", "*", "*"); diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java index f5e625ae3..db58288cd 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java @@ -38,6 +38,7 @@ import org.apache.olingo.server.core.uri.testutil.EdmTechTestProvider; import org.apache.olingo.server.core.uri.testutil.FilterValidator; import org.apache.olingo.server.core.uri.testutil.ResourceValidator; import org.apache.olingo.server.core.uri.testutil.TestUriValidator; +import org.apache.olingo.server.core.uri.validator.UriValidationException; import org.apache.olingo.server.tecsvc.provider.ComplexTypeProvider; import org.apache.olingo.server.tecsvc.provider.ContainerProvider; import org.apache.olingo.server.tecsvc.provider.EntityTypeProvider; @@ -5201,6 +5202,17 @@ public class TestFullResourcePath { .isExSemantic(UriParserSemanticException.MessageKeys.ONLY_FOR_ENTITY_TYPES); testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/PropertyCompTwoPrim/$count") .isExSemantic(UriParserSemanticException.MessageKeys.ONLY_FOR_COLLECTIONS); + + // Actions must not be followed by anything. + testUri.runEx(ContainerProvider.AIRT_STRING + "/$value") + .isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_VALUE); + testUri.runEx(ContainerProvider.AIRTCT_TWO_PRIM_PARAM + "/PropertyInt16") + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + testUri.runEx("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/" + + "olingo.odata.test1.BAETTwoKeyNavRTETTwoKeyNav/olingo.odata.test1.ETTwoKeyNav") + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + testUri.runEx("ESTwoKeyNav/olingo.odata.test1.BAESTwoKeyNavRTESTwoKeyNav/$count") + .isExValidation(UriValidationException.MessageKeys.UNALLOWED_KIND_BEFORE_COUNT); } @Test diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java index 068edd748..0d333f3e3 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestUriParserImpl.java @@ -193,7 +193,7 @@ public class TestUriParserImpl { .isType(EntityTypeProvider.nameETTwoKeyTwoPrim, false); testUri.runEx(ContainerProvider.AIRT_STRING + "/invalidElement") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_MUST_BE_PRECEDED_BY_STRUCTURAL_TYPE); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); } @Test diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java index e466f2de2..98abf2034 100644 --- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/queryoption/expression/ExpressionTest.java @@ -19,7 +19,9 @@ package org.apache.olingo.server.core.uri.queryoption.expression; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import java.util.Arrays; @@ -134,7 +136,7 @@ public class ExpressionTest { MemberImpl expression = new MemberImpl(); EdmEntityType entityType = edm.getEntityType(EntityTypeProvider.nameETKeyNav); - // UriResourceImplTyped + // UriResourceImpl EdmAction action = edm.getUnboundAction(ActionProvider.nameUARTString); UriInfoResource uriInfo = new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( new UriResourceActionImpl().setAction(action)).asUriInfoResource(); @@ -146,24 +148,24 @@ public class ExpressionTest { assertEquals("", expression.accept(new FilterTreeToText())); // UriResourceImplTyped check collection = false case - assertEquals(false, expression.isCollection()); + assertFalse(expression.isCollection()); // UriResourceImplTyped check collection = true case action = edm.getUnboundAction(ActionProvider.nameUARTCollStringTwoParam); - expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( - new UriResourceActionImpl().setAction(action)) + expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource) + .addResourcePart(new UriResourceActionImpl().setAction(action)) .asUriInfoResource()); - assertEquals(true, expression.isCollection()); + assertTrue(expression.isCollection()); // UriResourceImplTyped with filter - action = edm.getUnboundAction(ActionProvider.nameUARTString); + EdmFunction function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null); expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( - new UriResourceActionImpl().setAction(action).setTypeFilter(entityType)) + new UriResourceFunctionImpl().setFunction(function).setEntryTypeFilter(entityType)) .asUriInfoResource()); assertEquals(entityType, expression.getType()); // UriResourceImplKeyPred - EdmFunction function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null); + function = edm.getUnboundFunction(FunctionProvider.nameUFCRTETKeyNav, null); expression.setResourcePath(new UriInfoImpl().setKind(UriInfoKind.resource).addResourcePart( new UriResourceFunctionImpl().setFunction(function)) .asUriInfoResource()); @@ -192,7 +194,7 @@ public class ExpressionTest { assertEquals(null, expression.getType()); // no typed collection else case - assertEquals(false, expression.isCollection()); + assertFalse(expression.isCollection()); } @Test