diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityReferencesITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityReferencesITCase.java index 30c95d41e..654aea7b7 100644 --- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityReferencesITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityReferencesITCase.java @@ -175,9 +175,8 @@ public class EntityReferencesITCase extends AbstractParamTecSvcITCase { getClient().getRetrieveRequestFactory() .getEntityRequest(uri) .execute(); - fail(); } catch (ODataClientErrorException e) { - assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), e.getStatusLine().getStatusCode()); + assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), e.getStatusLine().getStatusCode()); } } diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/EmptyNavigationPropertiesITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/EmptyNavigationPropertiesITCase.java new file mode 100644 index 000000000..c5a7044fc --- /dev/null +++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/EmptyNavigationPropertiesITCase.java @@ -0,0 +1,136 @@ +/* + * 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.fit.tecsvc.http; + +import static org.junit.Assert.*; + +import java.net.HttpURLConnection; +import java.net.URL; + +import org.apache.commons.io.IOUtils; +import org.apache.olingo.client.api.ODataClient; +import org.apache.olingo.commons.api.http.HttpMethod; +import org.apache.olingo.commons.api.http.HttpStatusCode; +import org.apache.olingo.fit.AbstractBaseTestITCase; +import org.apache.olingo.fit.tecsvc.TecSvcConst; +import org.junit.Test; + +public class EmptyNavigationPropertiesITCase extends AbstractBaseTestITCase { + + private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/"; + + @Test + public void emptyNavigationManyFollowedByToOne() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimMany(32767)" + + "/NavPropertyETAllPrimOne?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void emptyNavigationManyFollowedByToMany() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimMany(32767)" + + "/NavPropertyETAllPrimMany?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void nonemptyNavigationManyFollowedByEmptyToOne() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimMany(-365)" + + "/NavPropertyETAllPrimOne?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void emptyNavigationOneFollowedByToMany() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoPrim(32766)/NavPropertyETAllPrimOne" + + "/NavPropertyETTwoPrimMany?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void nonemptyNavigationManyFollowedByToManyNonExistingKey() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(32767)/NavPropertyETTwoPrimMany(-365)" + + "/NavPropertyETAllPrimMany(123)?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void emptyNavigationOne() throws Exception { + URL url = new URL(SERVICE_URI + "ESTwoPrim(32766)/NavPropertyETAllPrimOne?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void nonExistingEntityToNavigationOne() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(12345)/NavPropertyETTwoPrimOne?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), connection.getResponseCode()); + } + + @Test + public void emptyNavigationMany() throws Exception { + URL url = new URL(SERVICE_URI + "ESAllPrim(-32768)/NavPropertyETTwoPrimMany?$format=json"); + + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(HttpMethod.GET.name()); + connection.connect(); + + assertEquals(HttpStatusCode.OK.getStatusCode(), connection.getResponseCode()); + assertNotNull(IOUtils.toString(connection.getInputStream())); + } + + @Override + protected ODataClient getClient() { + return null; + } +} diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java index 42627eb38..3c5adc296 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 @@ -189,6 +189,8 @@ public abstract class TechnicalProcessor implements Processor { } int navigationCount = 0; + int navigationResCount = getNavigationResourceCount(resourcePaths); + Link previous = null; while (++navigationCount < readAtMostNavigations && resourcePaths.get(navigationCount) instanceof UriResourceNavigation) { final UriResourceNavigation uriNavigationResource = (UriResourceNavigation) resourcePaths.get(navigationCount); @@ -205,13 +207,28 @@ public abstract class TechnicalProcessor implements Processor { EdmEntityType edmEntityType = getEntityTypeBasedOnNavPropertyTypeCast(uriNavigationResource); entity = edmEntityType != null ? dataProvider.readDataFromEntity(edmEntityType, key) : entity; if (entity == null) { - throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + if (key.isEmpty() && (previous != null || navigationResCount == 1)) { + throw new ODataApplicationException("No Content", HttpStatusCode.NO_CONTENT.getStatusCode(), Locale.ROOT); + } else { + throw new ODataApplicationException("Not Found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT); + } } + previous = link; } return entity; } + private int getNavigationResourceCount(List resourcePaths) { + int count = 0; + for (UriResource resource : resourcePaths) { + if (resource instanceof UriResourceNavigation) { + count ++; + } + } + return count; + } + private EdmEntityType getEntityTypeBasedOnNavPropertyTypeCast(UriResourceNavigation uriNavigationResource) { if (uriNavigationResource.getTypeFilterOnCollection() != null) { return (EdmEntityType) uriNavigationResource.getTypeFilterOnCollection();