diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/AbstractOpenType.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/AbstractOpenType.java index a4d9bf231..b28ced970 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/AbstractOpenType.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/AbstractOpenType.java @@ -26,7 +26,9 @@ public interface AbstractOpenType { void removeAdditionalProperty(String name); - Object getAdditionalProperty(String name); + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + Object readAdditionalProperty(String name); - Collection getAdditionalPropertyNames(); + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + Collection readAdditionalPropertyNames(); } diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/Annotatable.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/Annotatable.java index 08af72be5..70048ba73 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/Annotatable.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/Annotatable.java @@ -27,8 +27,10 @@ public interface Annotatable extends Serializable { void removeAnnotation(Class term); - Object getAnnotation(Class term); + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + Object readAnnotation(Class term); - Collection> getAnnotationTerms(); + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + Collection> readAnnotationTerms(); } diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/EntityType.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/EntityType.java index 891b2db86..e68eab9df 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/EntityType.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/api/EntityType.java @@ -32,5 +32,6 @@ public interface EntityType> extends StructuredType< * * @return entity reference ID. */ - String getEntityReferenceID(); + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + String readEntityReferenceID(); } diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java index 43c161f6c..aaae42c5a 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractStructuredInvocationHandler.java @@ -158,41 +158,13 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { - if ("expand".equals(method.getName()) - || "select".equals(method.getName()) - || "refs".equals(method.getName())) { - invokeSelfMethod(method, args); - return proxy; - } else if (isSelfMethod(method, args)) { - return invokeSelfMethod(method, args); - } else if ("load".equals(method.getName()) && ArrayUtils.isEmpty(args)) { - load(); - return proxy; - } else if ("loadAsync".equals(method.getName()) && ArrayUtils.isEmpty(args)) { - return service.getClient().getConfiguration().getExecutor().submit(new Callable() { - @Override - public Object call() throws Exception { - load(); - return proxy; - } - }); - } else if ("operations".equals(method.getName()) && ArrayUtils.isEmpty(args)) { - final Class returnType = method.getReturnType(); + if (method.getName().startsWith("get")) { + // Here need check "get"/"set" first for better get-/set- performance because + // the below if-statements are really time-consuming, even twice slower than "get" body. - return Proxy.newProxyInstance( - Thread.currentThread().getContextClassLoader(), - new Class[] {returnType}, - OperationInvocationHandler.getInstance(getEntityHandler())); - } else if ("annotations".equals(method.getName()) && ArrayUtils.isEmpty(args)) { - final Class returnType = method.getReturnType(); - - return Proxy.newProxyInstance( - Thread.currentThread().getContextClassLoader(), - new Class[] {returnType}, - AnnotatationsInvocationHandler.getInstance(getEntityHandler(), this)); - } else if (method.getName().startsWith("get")) { - // Assumption: for each getter will always exist a setter and viceversa. + // Assumption: for each getter will always exist a setter and viceversa. // get method annotation and check if it exists as expected + final Object res; final Method getter = typeRef.getMethod(method.getName()); @@ -234,6 +206,38 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca } return ClassUtils.returnVoid(); + } else if ("expand".equals(method.getName()) + || "select".equals(method.getName()) + || "refs".equals(method.getName())) { + invokeSelfMethod(method, args); + return proxy; + } else if (isSelfMethod(method, args)) { + return invokeSelfMethod(method, args); + } else if ("load".equals(method.getName()) && ArrayUtils.isEmpty(args)) { + load(); + return proxy; + } else if ("loadAsync".equals(method.getName()) && ArrayUtils.isEmpty(args)) { + return service.getClient().getConfiguration().getExecutor().submit(new Callable() { + @Override + public Object call() throws Exception { + load(); + return proxy; + } + }); + } else if ("operations".equals(method.getName()) && ArrayUtils.isEmpty(args)) { + final Class returnType = method.getReturnType(); + + return Proxy.newProxyInstance( + Thread.currentThread().getContextClassLoader(), + new Class[] {returnType}, + OperationInvocationHandler.getInstance(getEntityHandler())); + } else if ("annotations".equals(method.getName()) && ArrayUtils.isEmpty(args)) { + final Class returnType = method.getReturnType(); + + return Proxy.newProxyInstance( + Thread.currentThread().getContextClassLoader(), + new Class[] {returnType}, + AnnotatationsInvocationHandler.getInstance(getEntityHandler(), this)); } else { throw new NoSuchMethodException(method.getName()); } @@ -517,7 +521,8 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca return navPropValue; } - public Object getAdditionalProperty(final String name) { + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + public Object readAdditionalProperty(final String name) { return getPropertyValue(name, null); } @@ -525,7 +530,7 @@ public abstract class AbstractStructuredInvocationHandler extends AbstractInvoca return propertyChanges; } - public Collection getAdditionalPropertyNames() { + public Collection readAdditionalPropertyNames() { final Set res = new HashSet(propertyChanges.keySet()); final Set propertyNames = new HashSet(); for (Method method : typeRef.getMethods()) { diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java index 6409d24cc..a219cdca7 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AnnotatableInvocationHandler.java @@ -141,7 +141,7 @@ public class AnnotatableInvocationHandler extends AbstractInvocationHandler impl } @Override - public Object getAnnotation(final Class term) { + public Object readAnnotation(final Class term) { Object res = null; if (annotations.containsKey(term)) { @@ -171,7 +171,7 @@ public class AnnotatableInvocationHandler extends AbstractInvocationHandler impl } @Override - public Collection> getAnnotationTerms() { + public Collection> readAnnotationTerms() { return entityHandler.getEntity() instanceof ODataEntity ? CoreUtils.getAnnotationTerms(service, internalAnnotations()) : Collections.>emptyList(); diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java index 32d3b267a..2a23b11cb 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java @@ -406,7 +406,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler } @Override - public Object getAnnotation(final Class term) { + public Object readAnnotation(final Class term) { Object res = null; if (annotations.containsKey(term)) { @@ -436,7 +436,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler } @Override - public Collection> getAnnotationTerms() { + public Collection> readAnnotationTerms() { return getEntity() instanceof ODataEntity ? CoreUtils.getAnnotationTerms(service, ((ODataEntity) getEntity()).getAnnotations()) : Collections.>emptyList(); @@ -493,7 +493,8 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler return getEntity() == null ? null : getEntity().getProperty(name); } - public String getEntityReferenceID() { + // use read- instead of get- for .invoke() to distinguish it from entity property getter. + public String readEntityReferenceID() { URI id = getEntity() == null ? null : getClient().getServiceVersion().compareTo(ODataServiceVersion.V30) <= 0 ? ((org.apache.olingo.commons.api.domain.v3.ODataEntity) getEntity()).getLink() diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/ClassUtils.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/ClassUtils.java index 8d5c08c0e..d22eb2835 100644 --- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/ClassUtils.java +++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/ClassUtils.java @@ -32,6 +32,7 @@ import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.HashSet; @@ -49,6 +50,10 @@ public final class ClassUtils { } public static Type[] extractGenericType(final Class paramType, final Class... references) { + if (Proxy.class.isAssignableFrom(paramType)) { + return extractGenericType(Class.class.cast(paramType.getGenericInterfaces()[0]), references); + } + if (paramType.getGenericInterfaces().length > 0) { if (references == null || references.length == 0) { return ((ParameterizedType) paramType.getGenericInterfaces()[0]).getActualTypeArguments(); diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v3/OpenTypeTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v3/OpenTypeTestITCase.java index a0e8b9972..5e51ad661 100644 --- a/fit/src/test/java/org/apache/olingo/fit/proxy/v3/OpenTypeTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v3/OpenTypeTestITCase.java @@ -72,11 +72,11 @@ public class OpenTypeTestITCase extends AbstractTestITCase { @Test public void read() { Row row = otcontainer.getRow().getByKey(UUID.fromString("71f7d0dc-ede4-45eb-b421-555a2aa1e58f")).load(); - assertEquals(Double.class, row.getAdditionalProperty("Double").getClass()); + assertEquals(Double.class, row.readAdditionalProperty("Double").getClass()); assertEquals("71f7d0dc-ede4-45eb-b421-555a2aa1e58f", row.getId().toString()); row = otcontainer.getRow().getByKey(UUID.fromString("672b8250-1e6e-4785-80cf-b94b572e42b3")).load(); - assertEquals(BigDecimal.class, row.getAdditionalProperty("Decimal").getClass()); + assertEquals(BigDecimal.class, row.readAdditionalProperty("Decimal").getClass()); } @Test @@ -119,13 +119,13 @@ public class OpenTypeTestITCase extends AbstractTestITCase { otcontainer.flush(); rowIndex = otcontainer.getRowIndex().getByKey(id).load(); - assertEquals(String.class, rowIndex.getAdditionalProperty("aString").getClass()); - assertEquals(Boolean.class, rowIndex.getAdditionalProperty("aBoolean").getClass()); - assertEquals(Double.class, rowIndex.getAdditionalProperty("aDouble").getClass()); - assertEquals(Byte.class, rowIndex.getAdditionalProperty("aByte").getClass()); - assertEquals(Byte.MAX_VALUE, rowIndex.getAdditionalProperty("aByte")); - assertTrue(Timestamp.class.isAssignableFrom(rowIndex.getAdditionalProperty("aDate").getClass())); - assertEquals(ContactDetails.class, rowIndex.getAdditionalProperty("aContact").getClass().getInterfaces()[0]); + assertEquals(String.class, rowIndex.readAdditionalProperty("aString").getClass()); + assertEquals(Boolean.class, rowIndex.readAdditionalProperty("aBoolean").getClass()); + assertEquals(Double.class, rowIndex.readAdditionalProperty("aDouble").getClass()); + assertEquals(Byte.class, rowIndex.readAdditionalProperty("aByte").getClass()); + assertEquals(Byte.MAX_VALUE, rowIndex.readAdditionalProperty("aByte")); + assertTrue(Timestamp.class.isAssignableFrom(rowIndex.readAdditionalProperty("aDate").getClass())); + assertEquals(ContactDetails.class, rowIndex.readAdditionalProperty("aContact").getClass().getInterfaces()[0]); otservice.getContext().detachAll(); diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java index 2a7d6126e..2f9191657 100644 --- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java @@ -100,11 +100,11 @@ public class APIBasicDesignTestITCase extends AbstractTestITCase { public void readWithReferences() { final Person person = container.getOrders().getByKey(8).getCustomerForOrder().refs().load(); assertEquals("http://localhost:9080/stub/StaticService/V40/Static.svc/Customers(PersonID=1)", - person.getEntityReferenceID()); + person.readEntityReferenceID()); final OrderCollection orders = container.getCustomers().getByKey(1).getOrders().refs().execute(); assertEquals("http://localhost:9080/stub/StaticService/V40/Static.svc/Orders(7)", - orders.iterator().next().getEntityReferenceID()); + orders.iterator().next().readEntityReferenceID()); } @Test diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/OpenTypeTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/OpenTypeTestITCase.java index 2cbd7bdab..082331e8a 100644 --- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/OpenTypeTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/OpenTypeTestITCase.java @@ -72,11 +72,11 @@ public class OpenTypeTestITCase extends AbstractTestITCase { @Test public void read() { Row row = otcontainer.getRow().getByKey(UUID.fromString("71f7d0dc-ede4-45eb-b421-555a2aa1e58f")).load(); - assertEquals(Double.class, row.getAdditionalProperty("Double").getClass()); + assertEquals(Double.class, row.readAdditionalProperty("Double").getClass()); assertEquals("71f7d0dc-ede4-45eb-b421-555a2aa1e58f", row.getId().toString()); row = otcontainer.getRow().getByKey(UUID.fromString("672b8250-1e6e-4785-80cf-b94b572e42b3")).load(); - assertEquals(BigDecimal.class, row.getAdditionalProperty("Decimal").getClass()); + assertEquals(BigDecimal.class, row.readAdditionalProperty("Decimal").getClass()); } @Test @@ -126,19 +126,19 @@ public class OpenTypeTestITCase extends AbstractTestITCase { otcontainer.flush(); rowIndex = otcontainer.getRowIndex().getByKey(id).load(); - assertEquals(String.class, rowIndex.getAdditionalProperty("aString").getClass()); - assertEquals(Boolean.class, rowIndex.getAdditionalProperty("aBoolean").getClass()); - assertEquals(Double.class, rowIndex.getAdditionalProperty("aDouble").getClass()); - assertEquals(Byte.class, rowIndex.getAdditionalProperty("aByte").getClass()); - assertEquals(Byte.MAX_VALUE, rowIndex.getAdditionalProperty("aByte")); - assertTrue(Calendar.class.isAssignableFrom(rowIndex.getAdditionalProperty("aDate").getClass())); - assertEquals(ContactDetails.class, rowIndex.getAdditionalProperty("aContact").getClass().getInterfaces()[0]); - assertEquals(Color.class, rowIndex.getAdditionalProperty("aColor").getClass()); - assertEquals(Color.Green, rowIndex.getAdditionalProperty("aColor")); - assertEquals("Fabio", AccountInfo.class.cast(rowIndex.getAdditionalProperty("info")).getFirstName()); - assertEquals("Martelli", AccountInfo.class.cast(rowIndex.getAdditionalProperty("info")).getLastName()); - assertEquals("fabio.martelli@tirasa.net", AccountInfo.class.cast(rowIndex.getAdditionalProperty("info")). - getAdditionalProperty("email")); + assertEquals(String.class, rowIndex.readAdditionalProperty("aString").getClass()); + assertEquals(Boolean.class, rowIndex.readAdditionalProperty("aBoolean").getClass()); + assertEquals(Double.class, rowIndex.readAdditionalProperty("aDouble").getClass()); + assertEquals(Byte.class, rowIndex.readAdditionalProperty("aByte").getClass()); + assertEquals(Byte.MAX_VALUE, rowIndex.readAdditionalProperty("aByte")); + assertTrue(Calendar.class.isAssignableFrom(rowIndex.readAdditionalProperty("aDate").getClass())); + assertEquals(ContactDetails.class, rowIndex.readAdditionalProperty("aContact").getClass().getInterfaces()[0]); + assertEquals(Color.class, rowIndex.readAdditionalProperty("aColor").getClass()); + assertEquals(Color.Green, rowIndex.readAdditionalProperty("aColor")); + assertEquals("Fabio", AccountInfo.class.cast(rowIndex.readAdditionalProperty("info")).getFirstName()); + assertEquals("Martelli", AccountInfo.class.cast(rowIndex.readAdditionalProperty("info")).getLastName()); + assertEquals("fabio.martelli@tirasa.net", AccountInfo.class.cast(rowIndex.readAdditionalProperty("info")). + readAdditionalProperty("email")); otservice.getContext().detachAll(); diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/SingletonTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/SingletonTestITCase.java index 5c0b8c672..f3ab08fb2 100644 --- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/SingletonTestITCase.java +++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/SingletonTestITCase.java @@ -51,26 +51,26 @@ public class SingletonTestITCase extends AbstractTestITCase { @Test public void readWithAnnotations() { final Company company = container.getCompany().load(); - assertTrue(company.getAnnotationTerms().isEmpty()); + assertTrue(company.readAnnotationTerms().isEmpty()); final Person boss = container.getBoss().load(); assertEquals(2, boss.getPersonID(), 0); - assertEquals(1, boss.getAnnotationTerms().size()); - Object isBoss = boss.getAnnotation(IsBoss.class); + assertEquals(1, boss.readAnnotationTerms().size()); + Object isBoss = boss.readAnnotation(IsBoss.class); assertTrue(isBoss instanceof Boolean); assertTrue((Boolean) isBoss); Annotatable annotations = boss.annotations().getFirstNameAnnotations(); - assertTrue(annotations.getAnnotationTerms().isEmpty()); + assertTrue(annotations.readAnnotationTerms().isEmpty()); annotations = boss.annotations().getLastNameAnnotations(); - isBoss = annotations.getAnnotation(IsBoss.class); + isBoss = annotations.readAnnotation(IsBoss.class); assertTrue(isBoss instanceof Boolean); assertFalse((Boolean) isBoss); annotations = boss.annotations().getParentAnnotations(); - isBoss = annotations.getAnnotation(IsBoss.class); + isBoss = annotations.readAnnotation(IsBoss.class); assertTrue(isBoss instanceof Boolean); assertFalse((Boolean) isBoss); } diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIUtils.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIUtils.java index 0fa78d201..fa3609542 100644 --- a/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIUtils.java +++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/uri/URIUtils.java @@ -366,11 +366,10 @@ public final class URIUtils { } public static HttpEntity buildInputStreamEntity(final CommonODataClient client, final InputStream input) { - HttpEntity entity; + AbstractHttpEntity entity; + boolean useChunked = client.getConfiguration().isUseChuncked(); - if (!shouldUseRepeatableHttpBodyEntry(client)) { - entity = new InputStreamEntity(input, -1); - } else { + if (shouldUseRepeatableHttpBodyEntry(client) || !useChunked) { byte[] bytes = new byte[0]; try { bytes = IOUtils.toByteArray(input); @@ -380,10 +379,18 @@ public final class URIUtils { } entity = new ByteArrayEntity(bytes); + } else { + entity = new InputStreamEntity(input, -1); } + + if (!useChunked && entity.getContentLength() < 0) { + LOG.error("Could not determine length - request will be sent as chunked."); + useChunked = true; + } // both entities can be sent in chunked way or not - ((AbstractHttpEntity) entity).setChunked(client.getConfiguration().isUseChuncked()); + entity.setChunked(useChunked); + return entity; } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java deleted file mode 100644 index dbdf80445..000000000 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java +++ /dev/null @@ -1,54 +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.server.core; - -import java.util.Locale; - -import org.apache.olingo.commons.api.format.ODataFormat; -import org.apache.olingo.commons.api.http.HttpStatusCode; -import org.apache.olingo.server.api.OData; -import org.apache.olingo.server.api.ODataResponse; -import org.apache.olingo.server.api.ODataServerError; -import org.apache.olingo.server.api.ODataTranslatedException; -import org.apache.olingo.server.api.serializer.ODataSerializer; -import org.apache.olingo.server.api.serializer.ODataSerializerException; - -public class ODataExceptionHandler { - - public Locale requestedLocale; - public ODataFormat requestedFormat = ODataFormat.JSON; - - public void handle(ODataResponse resp, Exception e) { - if (resp.getStatusCode() == 0) { - resp.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode()); - } - ODataServerError error = new ODataServerError(); - if (e instanceof ODataTranslatedException) { - error.setMessage(((ODataTranslatedException) e).getTranslatedMessage(requestedLocale).getMessage()); - } else { - error.setMessage(e.getMessage()); - } - - try { - ODataSerializer serializer = OData.newInstance().createSerializer(requestedFormat); - resp.setContent(serializer.error(error)); - } catch (final ODataSerializerException e1) {} - // Set header - } -} diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java index 3ba30c706..d0f248fc3 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHelper.java @@ -20,30 +20,75 @@ package org.apache.olingo.server.core; import java.util.Locale; +import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.ODataApplicationException; import org.apache.olingo.server.api.ODataServerError; import org.apache.olingo.server.api.ODataTranslatedException; import org.apache.olingo.server.api.ODataTranslatedException.ODataErrorMessage; +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.parser.UriParserSyntaxException; +import org.apache.olingo.server.core.uri.validator.UriValidationException; public class ODataExceptionHelper { - - public static ODataServerError createServerErrorObject(Exception e, int statusCode) { - ODataServerError serverError = basicServerError(e); - serverError.setStatusCode(statusCode); - serverError.setLocale(Locale.ENGLISH); + + public static ODataServerError createServerErrorObject(UriValidationException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode()); + return serverError; + } + + public static ODataServerError createServerErrorObject(UriParserSemanticException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + if(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND.equals(e.getMessageKey()) + || UriParserSemanticException.MessageKeys.FUNCTION_NOT_FOUND.equals(e.getMessageKey()) + || UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE.equals(e.getMessageKey())){ + serverError.setStatusCode(HttpStatusCode.NOT_FOUND.getStatusCode()); + }else{ + serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode()); + } + return serverError; + } + + public static ODataServerError createServerErrorObject(UriParserSyntaxException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + if(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE.equals(e.getMessageKey())){ + serverError.setStatusCode(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode()); + }else{ + serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode()); + } + return serverError; + } + + public static ODataServerError createServerErrorObject(UriParserException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode()); + return serverError; + } + + public static ODataServerError createServerErrorObject(ContentNegotiatorException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + serverError.setStatusCode(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode()); return serverError; } - public static ODataServerError createServerErrorObject(ODataTranslatedException e, int statusCode, - Locale requestedLocale) { - ODataServerError serverError = basicServerError(e); - ODataErrorMessage translatedMessage = e.getTranslatedMessage(requestedLocale); - serverError.setMessage(translatedMessage.getMessage()); - serverError.setLocale(translatedMessage.getLocale()); - serverError.setStatusCode(statusCode); + public static ODataServerError createServerErrorObject(ODataHandlerException e, Locale requestedLocale) { + ODataServerError serverError = basicTranslatedError(e, requestedLocale); + if (ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED.equals(e.getMessageKey()) + || ODataHandlerException.MessageKeys.HTTP_METHOD_NOT_IMPLEMENTED.equals(e.getMessageKey()) + || ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED.equals(e.getMessageKey())) { + serverError.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); + } else if (ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED.equals(e.getMessageKey())) { + serverError.setStatusCode(HttpStatusCode.BAD_REQUEST.getStatusCode()); + } + return serverError; } + public static ODataServerError createServerErrorObject(ODataTranslatedException e, Locale requestedLocale) { + return basicTranslatedError(e, requestedLocale); + } + public static ODataServerError createServerErrorObject(ODataApplicationException e) { ODataServerError serverError = basicServerError(e); serverError.setStatusCode(e.getStatusCode()); @@ -51,9 +96,25 @@ public class ODataExceptionHelper { serverError.setCode(e.getODataErrorCode()); return serverError; } - + + public static ODataServerError createServerErrorObject(Exception e) { + ODataServerError serverError = basicServerError(e); + serverError.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode()); + serverError.setLocale(Locale.ENGLISH); + return serverError; + } + private static ODataServerError basicServerError(Exception e) { ODataServerError serverError = new ODataServerError().setException(e).setMessage(e.getMessage()); return serverError; } + + private static ODataServerError basicTranslatedError(ODataTranslatedException e, Locale requestedLocale) { + ODataServerError serverError = basicServerError(e); + ODataErrorMessage translatedMessage = e.getTranslatedMessage(requestedLocale); + serverError.setMessage(translatedMessage.getMessage()); + serverError.setLocale(translatedMessage.getLocale()); + serverError.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode()); + return serverError; + } } 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 de4851fe8..0893d0933 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 @@ -19,7 +19,6 @@ package org.apache.olingo.server.core; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import org.apache.olingo.commons.api.edm.Edm; @@ -28,15 +27,14 @@ import org.apache.olingo.commons.api.format.ContentType; import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; -import org.apache.olingo.commons.api.http.HttpStatusCode; import org.apache.olingo.server.api.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.ODataTranslatedException; -import org.apache.olingo.server.api.processor.EntityCollectionProcessor; import org.apache.olingo.server.api.processor.DefaultProcessor; +import org.apache.olingo.server.api.processor.EntityCollectionProcessor; import org.apache.olingo.server.api.processor.EntityProcessor; import org.apache.olingo.server.api.processor.ExceptionProcessor; import org.apache.olingo.server.api.processor.MetadataProcessor; @@ -48,6 +46,8 @@ import org.apache.olingo.server.api.uri.UriResourceNavigation; import org.apache.olingo.server.api.uri.UriResourcePartTyped; 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.parser.UriParserSyntaxException; import org.apache.olingo.server.core.uri.validator.UriValidationException; import org.apache.olingo.server.core.uri.validator.UriValidator; @@ -73,30 +73,32 @@ public class ODataHandler { processInternal(request, requestedContentType, response); - } catch (final UriParserException e) { - handleException(request, response, - ODataExceptionHelper.createServerErrorObject(e, HttpStatusCode.BAD_REQUEST.getStatusCode(), null), - requestedContentType); } catch (final UriValidationException e) { - handleException(request, response, - ODataExceptionHelper.createServerErrorObject(e, HttpStatusCode.BAD_REQUEST.getStatusCode(), null), - requestedContentType); + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); + } catch (final UriParserSemanticException e) { + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); + } catch (final UriParserSyntaxException e) { + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); + } catch (final UriParserException e) { + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); } catch (ContentNegotiatorException e) { - Locale requestedLocale = null; - ODataServerError serverError = - ODataExceptionHelper.createServerErrorObject(e, HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), - requestedLocale); - handleException(request, response, serverError, requestedContentType); + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); + } catch (ODataHandlerException e) { + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); + handleException(request, response, serverError, null); } catch (ODataTranslatedException e) { - Locale requestedLocale = null; - ODataServerError serverError = - ODataExceptionHelper.createServerErrorObject(e, response.getStatusCode(), requestedLocale); + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null); handleException(request, response, serverError, requestedContentType); } catch (ODataApplicationException e) { ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e); handleException(request, response, serverError, requestedContentType); } catch (Exception e) { - ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, response.getStatusCode()); + ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e); handleException(request, response, serverError, requestedContentType); } return response; @@ -118,7 +120,7 @@ public class ODataHandler { switch (uriInfo.getKind()) { case metadata: - MetadataProcessor mp = selectProcessor(MetadataProcessor.class, response); + MetadataProcessor mp = selectProcessor(MetadataProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, mp, MetadataProcessor.class); @@ -127,10 +129,10 @@ public class ODataHandler { break; case service: if ("".equals(request.getRawODataPath())) { - RedirectProcessor rdp = selectProcessor(RedirectProcessor.class, response); + RedirectProcessor rdp = selectProcessor(RedirectProcessor.class); rdp.redirect(request, response); } else { - ServiceDocumentProcessor sdp = selectProcessor(ServiceDocumentProcessor.class, response); + ServiceDocumentProcessor sdp = selectProcessor(ServiceDocumentProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, sdp, @@ -143,7 +145,6 @@ public class ODataHandler { handleResourceDispatching(request, response, uriInfo); break; default: - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } @@ -153,7 +154,7 @@ public class ODataHandler { ContentType requestedContentType) { ExceptionProcessor exceptionProcessor; try { - exceptionProcessor = selectProcessor(ExceptionProcessor.class, response); + exceptionProcessor = selectProcessor(ExceptionProcessor.class); } catch (ODataTranslatedException e) { exceptionProcessor = new DefaultProcessor(); } @@ -173,7 +174,7 @@ public class ODataHandler { case entitySet: if (((UriResourcePartTyped) lastPathSegment).isCollection()) { if (request.getMethod().equals(HttpMethod.GET)) { - EntityCollectionProcessor cp = selectProcessor(EntityCollectionProcessor.class, response); + EntityCollectionProcessor cp = selectProcessor(EntityCollectionProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, cp, @@ -181,20 +182,18 @@ public class ODataHandler { cp.readCollection(request, response, uriInfo, requestedContentType); } else { - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } } else { if (request.getMethod().equals(HttpMethod.GET)) { - EntityProcessor ep = selectProcessor(EntityProcessor.class, response); + EntityProcessor ep = selectProcessor(EntityProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, ep, EntityProcessor.class); ep.readEntity(request, response, uriInfo, requestedContentType); } else { - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } @@ -203,7 +202,7 @@ public class ODataHandler { case navigationProperty: if (((UriResourceNavigation) lastPathSegment).isCollection()) { if (request.getMethod().equals(HttpMethod.GET)) { - EntityCollectionProcessor cp = selectProcessor(EntityCollectionProcessor.class, response); + EntityCollectionProcessor cp = selectProcessor(EntityCollectionProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, cp, @@ -211,27 +210,24 @@ public class ODataHandler { cp.readCollection(request, response, uriInfo, requestedContentType); } else { - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } } else { if (request.getMethod().equals(HttpMethod.GET)) { - EntityProcessor ep = selectProcessor(EntityProcessor.class, response); + EntityProcessor ep = selectProcessor(EntityProcessor.class); requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request, ep, EntityProcessor.class); ep.readEntity(request, response, uriInfo, requestedContentType); } else { - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } } break; default: - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED); } @@ -244,20 +240,18 @@ public class ODataHandler { if (maxVersion != null) { if (ODataServiceVersion.isBiggerThan(ODataServiceVersion.V40.toString(), maxVersion)) { - response.setStatusCode(400); throw new ODataHandlerException("ODataVersion not supported: " + maxVersion, ODataHandlerException.MessageKeys.ODATA_VERSION_NOT_SUPPORTED, maxVersion); } } } - private T selectProcessor(final Class cls, ODataResponse response) + private T selectProcessor(final Class cls) throws ODataTranslatedException { @SuppressWarnings("unchecked") T p = (T) processors.get(cls); if (p == null) { - response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); throw new ODataHandlerException("Processor: " + cls.getName() + " not registered.", ODataHandlerException.MessageKeys.PROCESSOR_NOT_IMPLEMENTED, cls.getName()); } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java index 436d54fbb..4e1f90c80 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java @@ -20,6 +20,8 @@ package org.apache.olingo.server.core; import org.apache.olingo.commons.api.ODataRuntimeException; import org.apache.olingo.commons.api.edm.Edm; +import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.format.ODataFormat; import org.apache.olingo.commons.api.http.HttpHeader; import org.apache.olingo.commons.api.http.HttpMethod; import org.apache.olingo.commons.api.http.HttpStatusCode; @@ -27,8 +29,10 @@ import org.apache.olingo.server.api.OData; import org.apache.olingo.server.api.ODataHttpHandler; 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.ODataTranslatedException; import org.apache.olingo.server.api.processor.Processor; +import org.apache.olingo.server.api.serializer.ODataSerializer; import org.apache.olingo.server.api.serializer.ODataSerializerException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,12 +40,14 @@ import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; +import java.util.Locale; import java.util.Map.Entry; public class ODataHttpHandlerImpl implements ODataHttpHandler { @@ -85,8 +91,27 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler { resp.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode()); } } - ODataExceptionHandler exceptionHandler = new ODataExceptionHandler(); - exceptionHandler.handle(resp, e); + + ODataServerError error = new ODataServerError(); + if (e instanceof ODataTranslatedException) { + error.setMessage(((ODataTranslatedException) e).getTranslatedMessage(Locale.ENGLISH).getMessage()); + } else { + error.setMessage(e.getMessage()); + } + + try { + ODataSerializer serializer = OData.newInstance().createSerializer(ODataFormat.JSON); + resp.setContent(serializer.error(error)); + } catch (final ODataSerializerException e1) { + // This should never happen but to be sure we have this catch here to prevent sending a stacktrace to a client. + String responseContent = + "{\"error\":{\"code\":null,\"message\":\"An unexpected exception occurred in the ODataHttpHandler during " + + "error processing with message: " + e.getMessage() + "\"}}"; + resp.setContent(new ByteArrayInputStream(responseContent.getBytes())); + resp.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode()); + } + // Set header + resp.setHeader(HttpHeader.CONTENT_TYPE, ContentType.APPLICATION_JSON.toContentTypeString()); return resp; } diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java index 0c4d92c46..016aeb98d 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java @@ -188,7 +188,7 @@ public class Parser { formatOption.setFormat(option.value); } else { throw new UriParserSyntaxException("Illegal value of $format option!", - UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION, + UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE, option.name, option.value); } context.contextUriInfo.setSystemQueryOption(formatOption); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java index 160cc2a5a..c23ae6860 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java @@ -358,6 +358,11 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { if (lastResourcePart == null) { if (context.contextTypes.size() == 0) { + if(checkFirst && ctx.vNS == null){ + throw wrap(new UriParserSemanticException( + "Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '" + odi + "'.", + UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND, odi)); + } throw wrap(new UriParserSemanticException("Resource part '" + odi + "' can only applied on typed " + "resource parts", UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS, odi)); @@ -396,9 +401,9 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { EdmElement property = structType.getProperty(odi); if (property == null) { throw wrap(new UriParserSemanticException("Property '" + odi + "' not found in type '" - + structType.getNamespace() + "." + structType.getName() + "'", + + structType.getNamespace() + "." + structType.getName() + "'", UriParserSemanticException.MessageKeys.PROPERTY_NOT_IN_TYPE, - structType.getFullQualifiedName().toString(), odi)); + structType.getFullQualifiedName().toString(), odi)); } if (property instanceof EdmProperty) { @@ -466,7 +471,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterEntityType) + "' behind '" + getName(lastPartWithKeys.getTypeFilterOnEntry()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterEntityType))); + getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterEntityType))); } lastPartWithKeys.setEntryTypeFilter(filterEntityType); return null; @@ -476,7 +481,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterEntityType) + "' behind '" + getName(lastPartWithKeys.getTypeFilterOnCollection()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterEntityType))); + getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterEntityType))); } lastPartWithKeys.setCollectionTypeFilter(filterEntityType); return null; @@ -488,7 +493,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterEntityType) + "' behind '" + getName(lastPartTyped.getTypeFilter()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartTyped.getTypeFilter()), getName(filterEntityType))); + getName(lastPartTyped.getTypeFilter()), getName(filterEntityType))); } lastPartTyped.setTypeFilter(filterEntityType); @@ -512,7 +517,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { throw wrap(new UriParserSemanticException( "Complex typefilter '" + getName(source.type) + "'not compatible type of previous path segment '" + getName(filterComplexType) + "'", - UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(source.type))); + UriParserSemanticException.MessageKeys.INCOMPATIBLE_TYPE_FILTER, getName(source.type))); } // is simple complex type cast @@ -540,7 +545,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterComplexType) + "' behind '" + getName(lastPartWithKeys.getTypeFilterOnEntry()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterComplexType))); + getName(lastPartWithKeys.getTypeFilterOnEntry()), getName(filterComplexType))); } lastPartWithKeys.setEntryTypeFilter(filterComplexType); return null; @@ -550,7 +555,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterComplexType) + "' behind '" + getName(lastPartWithKeys.getTypeFilterOnCollection()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterComplexType))); + getName(lastPartWithKeys.getTypeFilterOnCollection()), getName(filterComplexType))); } lastPartWithKeys.setCollectionTypeFilter(filterComplexType); return null; @@ -563,7 +568,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor { + getName(filterComplexType) + "' behind '" + getName(lastPartTyped.getTypeFilter()) + "'", UriParserSemanticException.MessageKeys.TYPE_FILTER_NOT_CHAINABLE, - getName(lastPartTyped.getTypeFilter()), getName(filterComplexType))); + getName(lastPartTyped.getTypeFilter()), getName(filterComplexType))); } lastPartTyped.setTypeFilter(filterComplexType); diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java index 48e86479d..b41fbbf71 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSemanticException.java @@ -49,7 +49,8 @@ public class UriParserSemanticException extends UriParserException { ONLY_SIMPLE_AND_COMPLEX_PROPERTIES_IN_SELECT, COMPLEX_PROPERTY_OF_ENTITY_TYPE_EXPECTED, NOT_FOR_ENTITY_TYPE, - PREVIOUS_PART_TYPED; + PREVIOUS_PART_TYPED, + /** parameter: resource_name */RESOURCE_NOT_FOUND; @Override public String getKey() { diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java index dd7323680..e1506ee53 100644 --- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java +++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParserSyntaxException.java @@ -27,7 +27,8 @@ public class UriParserSyntaxException extends UriParserException { /** parameter: query-option name */ UNKNOWN_SYSTEM_QUERY_OPTION, /** parameters: query-option name, query-option value */ WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION, SYNTAX, - SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE; + SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE, + /** parameter: query-option value */ WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE; @Override public String getKey() { diff --git a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties index 93f433f20..4695c73b2 100644 --- a/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties +++ b/lib/server-core/src/main/resources/server-core-exceptions-i18n.properties @@ -26,6 +26,7 @@ ODataHandlerException.ODATA_VERSION_NOT_SUPPORTED=OData version '%1$s' is not su UriParserSyntaxException.UNKNOWN_SYSTEM_QUERY_OPTION=The system query option '%1$s' is not defined. UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION=The system query option '%1$s' has the not-allowed value '%2$s'. +UriParserSyntaxException.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE=The system query option $value must be either json, xml, atom or a valid content-type. The value '%1$s' is neither. UriParserSyntaxException.SYNTAX=The URI is malformed. UriParserSyntaxException.SYSTEM_QUERY_OPTION_LEVELS_NOT_ALLOWED_HERE=The system query option '$levels' is not allowed here. @@ -55,6 +56,7 @@ UriParserSemanticException.ONLY_SIMPLE_AND_COMPLEX_PROPERTIES_IN_SELECT=Only sim UriParserSemanticException.COMPLEX_PROPERTY_OF_ENTITY_TYPE_EXPECTED=A complex property of an entity type is expected. UriParserSemanticException.NOT_FOR_ENTITY_TYPE=Not allowed for entity type. UriParserSemanticException.PREVIOUS_PART_TYPED=The previous part is typed. +UriParserSemanticException.RESOURCE_NOT_FOUND=Cannot find EntitySet, Singleton, ActionImport or FunctionImport with name '%1$s'. UriValidationException.UNSUPPORTED_QUERY_OPTION=The query option '%1$s' is not supported. UriValidationException.UNSUPPORTED_URI_KIND=The URI kind '%1$s' is not supported. diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerExceptionHandlingTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerExceptionHandlingTest.java new file mode 100644 index 000000000..0f40d1923 --- /dev/null +++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerExceptionHandlingTest.java @@ -0,0 +1,124 @@ +/* + * 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.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; + +import java.util.Locale; + +import org.apache.commons.io.IOUtils; +import org.apache.olingo.commons.api.ODataException; +import org.apache.olingo.commons.api.edm.Edm; +import org.apache.olingo.commons.api.edm.FullQualifiedName; +import org.apache.olingo.commons.api.format.ContentType; +import org.apache.olingo.commons.api.http.HttpMethod; +import org.apache.olingo.commons.api.http.HttpStatusCode; +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.edm.provider.EdmProvider; +import org.apache.olingo.server.api.edm.provider.EntitySet; +import org.apache.olingo.server.api.processor.MetadataProcessor; +import org.apache.olingo.server.api.uri.UriInfo; +import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; +import org.junit.Before; +import org.junit.Test; + +public class ODataHandlerExceptionHandlingTest { + private ODataHandler handler; + + @Before + public void before() { + OData odata = OData.newInstance(); + Edm edm = odata.createEdm(new EdmTechProvider()); + + handler = new ODataHandler(odata, edm); + } + + @Test + public void testUriParserExceptionResultsInRightResponseNotFound() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("NotFound"); + + ODataResponse response = handler.process(request); + assertNotNull(response); + assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), response.getStatusCode()); + } + + @Test + public void testUriParserExceptionResultsInRightResponseBadRequest() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("ESAllPrim('122')"); + + ODataResponse response = handler.process(request); + assertNotNull(response); + assertEquals(HttpStatusCode.BAD_REQUEST.getStatusCode(), response.getStatusCode()); + } + + @Test + public void testUriParserExceptionResultsInRightResponseEdmCause() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("EdmException"); + + OData odata = OData.newInstance(); + Edm edm = odata.createEdm(new EdmProvider() { + public EntitySet getEntitySet(final FullQualifiedName entityContainer, final String entitySetName) + throws ODataException { + throw new ODataException("msg"); + } + }); + + ODataHandler localHandler = new ODataHandler(odata, edm); + + ODataResponse response = localHandler.process(request); + assertNotNull(response); + assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode()); + // TODO: Check for message in case of EdmException + System.out.println(IOUtils.toString(response.getContent())); + } + + @Test + public void testWithApplicationExceptionInProcessor() throws Exception { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("$metadata"); + + MetadataProcessor metadataProcessor = mock(MetadataProcessor.class); + doThrow(new ODataApplicationException("msg", 425, Locale.ENGLISH)).when(metadataProcessor).readMetadata( + any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); + + handler.register(metadataProcessor); + + ODataResponse response = handler.process(request); + assertNotNull(response); + assertEquals(425, response.getStatusCode()); + } +} 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 3ac720852..04ed43496 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 @@ -21,35 +21,24 @@ package org.apache.olingo.server.core; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import java.util.Arrays; -import java.util.Locale; import org.apache.commons.io.IOUtils; -import org.apache.olingo.commons.api.ODataException; import org.apache.olingo.commons.api.edm.Edm; -import org.apache.olingo.commons.api.edm.FullQualifiedName; import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion; -import org.apache.olingo.commons.api.format.ContentType; 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.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.edm.provider.EdmProvider; -import org.apache.olingo.server.api.edm.provider.EntitySet; import org.apache.olingo.server.api.processor.MetadataProcessor; import org.apache.olingo.server.api.processor.ServiceDocumentProcessor; -import org.apache.olingo.server.api.uri.UriInfo; import org.apache.olingo.server.tecsvc.provider.EdmTechProvider; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; public class ODataHandlerTest { @@ -223,6 +212,19 @@ public class ODataHandlerTest { assertNotNull(response); assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), response.getStatusCode()); } + + @Test + public void testContentNegotiationNotSupported2() { + ODataRequest request = new ODataRequest(); + + request.setMethod(HttpMethod.GET); + request.setRawODataPath("$metadata"); + request.setRawQueryPath("$format=notSupported"); + + ODataResponse response = handler.process(request); + assertNotNull(response); + assertEquals(HttpStatusCode.NOT_ACCEPTABLE.getStatusCode(), response.getStatusCode()); + } @Test public void testUnregisteredProcessor() { @@ -236,73 +238,4 @@ public class ODataHandlerTest { assertEquals(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), response.getStatusCode()); } - @Test - public void testWithApplicationExceptionInProcessor() throws Exception { - ODataRequest request = new ODataRequest(); - - request.setMethod(HttpMethod.GET); - request.setRawODataPath("$metadata"); - - MetadataProcessor metadataProcessor = mock(MetadataProcessor.class); - doThrow(new ODataApplicationException("msg", 425, Locale.ENGLISH)).when(metadataProcessor).readMetadata( - any(ODataRequest.class), any(ODataResponse.class), any(UriInfo.class), any(ContentType.class)); - - handler.register(metadataProcessor); - - ODataResponse response = handler.process(request); - assertNotNull(response); - assertEquals(425, response.getStatusCode()); - } - - //TODO: Use this test - @Ignore - @Test - public void testUriParserExceptionResultsInRightResponseNotFound() throws Exception { - ODataRequest request = new ODataRequest(); - - request.setMethod(HttpMethod.GET); - request.setRawODataPath("NotFound"); - - ODataResponse response = handler.process(request); - assertNotNull(response); - assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), response.getStatusCode()); - } - - //TODO: Use this test - @Ignore - @Test - public void testUriParserExceptionResultsInRightResponseBadRequest() throws Exception { - ODataRequest request = new ODataRequest(); - - request.setMethod(HttpMethod.GET); - request.setRawODataPath("ESAllPrim()"); - - ODataResponse response = handler.process(request); - assertNotNull(response); - assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), response.getStatusCode()); - } - - @Test - public void testUriParserExceptionResultsInRightResponseEdmCause() throws Exception { - ODataRequest request = new ODataRequest(); - - request.setMethod(HttpMethod.GET); - request.setRawODataPath("EdmException"); - - OData odata = OData.newInstance(); - Edm edm = odata.createEdm(new EdmProvider() { - public EntitySet getEntitySet(final FullQualifiedName entityContainer, final String entitySetName) - throws ODataException { - throw new ODataException("msg"); - } - }); - - ODataHandler localHandler = new ODataHandler(odata, edm); - - ODataResponse response = localHandler.process(request); - assertNotNull(response); - assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode()); - // TODO: Check for message in case of EdmException - // System.out.println(IOUtils.toString(response.getContent())); - } } 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 60a0e1313..8d2c565a2 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 @@ -968,33 +968,33 @@ public class TestFullResourcePath { testUri.runEx("ETBaseTwoKeyTwoPrim/com.sap.odata.test1.ETBaseTwoKeyTwoPrim" + "/com.sap.odata.test1.ETTwoBaseTwoKeyTwoPrim") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim/com.sap.odata.test1.ETBaseTwoKeyTwoPrim(1)/com.sap.odata.test1.ETAllKey") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim(1)/com.sap.odata.test1.ETBaseTwoKeyTwoPrim('1')/com.sap.odata.test1.ETAllKey") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim(1)/com.sap.odata.test1.ETBaseTwoKeyTwoPrim" + "/com.sap.odata.test1.ETTwoBaseTwoKeyTwoPrim") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim/com.sap.odata.test1.ETBaseTwoKeyTwoPrim" + "/com.sap.odata.test1.ETTwoBaseTwoKeyTwoPrim(1)") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim/com.sap.odata.test1.ETAllKey") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ETBaseTwoKeyTwoPrim()") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); testUri.runEx("ESAllNullable(1)/CollPropertyString/$value") .isExSemantic(UriParserSemanticException.MessageKeys.ONLY_FOR_TYPED_PARTS); testUri.runEx("ETMixPrimCollComp(1)/ComplexProperty/$value") - .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_PART_ONLY_FOR_TYPED_PARTS); + .isExSemantic(UriParserSemanticException.MessageKeys.RESOURCE_NOT_FOUND); } @Test @@ -2553,15 +2553,15 @@ public class TestFullResourcePath { .isKind(UriInfoKind.resource).goPath() .isFormatText(HttpContentType.APPLICATION_ATOM_XML_ENTRY_UTF8); testUri.runEx("ESKeyNav(1)?$format=noSlash") - .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION); + .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE); testUri.runEx("ESKeyNav(1)?$format=slashAtEnd/") - .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION); + .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE); testUri.runEx("ESKeyNav(1)?$format=/startsWithSlash") - .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION); + .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE); testUri.runEx("ESKeyNav(1)?$format=two/Slashes/tooMuch") - .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION); + .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE); testUri.runEx("ESKeyNav(1)?$format=") - .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION); + .isExSyntax(UriParserSyntaxException.MessageKeys.WRONG_VALUE_FOR_SYSTEM_QUERY_OPTION_VALUE); } @Test