This is an automated email from the ASF dual-hosted git repository.

ramyav pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/olingo-odata2.git


The following commit(s) were added to refs/heads/master by this push:
     new f7679dc  [OLINGO-1494]OData V2: Serialize error details
f7679dc is described below

commit f7679dc94491d4aa2a5146df94038565f721ef59
Author: ramya vasanth <ramya.vasa...@sap.com>
AuthorDate: Thu Nov 19 14:49:54 2020 +0530

    [OLINGO-1494]OData V2: Serialize error details
---
 .../odata2/api/processor/ODataErrorContext.java    | 67 ++++++++++++++++++++--
 .../olingo/odata2/core/ep/AtomEntityProvider.java  | 23 +++++++-
 .../core/ep/ContentTypeBasedEntityProvider.java    |  2 +
 .../olingo/odata2/core/ep/JsonEntityProvider.java  | 23 +++++++-
 .../olingo/odata2/core/ep/ProviderFacadeImpl.java  |  3 +-
 .../ep/producer/JsonErrorDocumentProducer.java     | 43 +++++++++++---
 .../core/ep/producer/XmlErrorDocumentProducer.java | 58 ++++++++++++++++---
 .../olingo/odata2/core/ep/util/FormatJson.java     |  3 +
 .../olingo/odata2/core/ep/util/FormatXml.java      |  4 ++
 .../core/ep/producer/JsonErrorProducerTest.java    | 39 +++++++++++++
 .../core/ep/producer/XmlErrorProducerTest.java     | 60 ++++++++++++++++++-
 11 files changed, 298 insertions(+), 27 deletions(-)

diff --git 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java
 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java
index 70527be..881c352 100644
--- 
a/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java
+++ 
b/odata2-lib/odata-api/src/main/java/org/apache/olingo/odata2/api/processor/ODataErrorContext.java
@@ -19,6 +19,8 @@
 package org.apache.olingo.odata2.api.processor;
 
 import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -36,16 +38,24 @@ import org.apache.olingo.odata2.api.uri.PathInfo;
  */
 public class ODataErrorContext {
 
+  // General purpose attributes
   private String contentType;
   private HttpStatusCodes httpStatus;
-  private String errorCode;
-  private String message;
-  private Locale locale;
   private Exception exception;
   private Map<String, List<String>> requestHeaders;
+  private PathInfo pathInfo;
   private URI requestUri;
+
+  // Standard OData Error Response
+  private String errorCode;
+  private Locale locale;
+  private String message;
   private String innerError;
-  private PathInfo pathInfo;
+
+  // Extended OData Error Response
+  private String severity;
+  private String target;
+  private Collection<ODataErrorContext> errorDetails = new 
ArrayList<ODataErrorContext>();
 
   /**
    * create a new context object
@@ -119,6 +129,22 @@ public class ODataErrorContext {
   }
 
   /**
+   * Return OData severity that is returned in error response.
+   * @return an application defined severity
+   */
+  public String getSeverity() {
+       return severity;
+}
+  
+  /**
+   * Set OData severity that should be returned in error response.
+   * @param severity an application defined severity
+   */
+  public void setSeverity(String severity) {
+    this.severity = severity;
+  }
+
+/**
    * Return a translated error message.
    * @return translated message
    */
@@ -209,6 +235,39 @@ public class ODataErrorContext {
   }
 
   /**
+   * Get a collection of detailed errors for a OData inner error to be 
returned in error response.
+   * @return a inner error message
+   */
+  public Collection<ODataErrorContext> getErrorDetails() {
+    return errorDetails;
+  }
+
+  /**
+   * Get a target of detailed error for a OData inner error to be returned in 
error response.
+   * @return a target
+   */
+  public String getTarget() {
+    return target;
+ }
+
+  /**
+   * Set a target for a OData detailed error to be returned in error response.
+   * @param target a target
+   */
+  public void setTarget(String target) {
+    this.target = target;
+  }
+
+/**
+   * Set a collection of detailed errors for a OData inner error to be 
returned in error response.
+   * If set, will overwrite the <code>innerError</code> element.
+   * @param errorDetails a inner error message
+   */
+  public void setErrorDetails(Collection<ODataErrorContext> errorDetails) {
+    this.errorDetails = errorDetails;
+  }
+
+  /**
    * Get {@link PathInfo} object.
    * May be <code>NULL</code> if no path info was created/set till error 
occurred (but may be over written by
    * application).
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java
index 201ffc7..4576ce5 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/AtomEntityProvider.java
@@ -103,6 +103,25 @@ public class AtomEntityProvider implements 
ContentTypeBasedEntityProvider {
   @Override
   public ODataResponse writeErrorDocument(final HttpStatusCodes status, final 
String errorCode, final String message,
       final Locale locale, final String innerError) {
+      ODataErrorContext context = new ODataErrorContext();
+      context.setHttpStatus(status);
+      context.setErrorCode(errorCode);
+      context.setMessage(message);
+      context.setLocale(locale);
+      context.setInnerError(innerError);
+
+      return writeErrorDocument(context);
+  }
+
+  /**
+   * <p>Serializes an error message according to the OData standard.</p>
+   * <p>In case an error occurs, it is logged.
+   * An exception is not thrown because this method is used in exception 
handling.</p>
+   * @param context the {@link ODataErrorContext} associated with this error
+   * @return an {@link ODataResponse} containing the serialized error message
+   */
+  @Override
+  public ODataResponse writeErrorDocument(ODataErrorContext context) {
     CircleStreamBuffer csb = new CircleStreamBuffer();
 
     try {
@@ -110,14 +129,14 @@ public class AtomEntityProvider implements 
ContentTypeBasedEntityProvider {
       XMLStreamWriter writer = 
XmlHelper.getXMLOutputFactory().createXMLStreamWriter(outStream, 
DEFAULT_CHARSET);
 
       XmlErrorDocumentProducer producer = new XmlErrorDocumentProducer();
-      producer.writeErrorDocument(writer, errorCode, message, locale, 
innerError);
+      producer.writeErrorDocument(writer, context);
 
       writer.flush();
       csb.closeWrite();
 
       ODataResponseBuilder response = 
ODataResponse.entity(csb.getInputStream())
           .header(ODataHttpHeaders.DATASERVICEVERSION, ODataServiceVersion.V10)
-          .status(status);
+          .status(context.getHttpStatus());
       return response.build();
     } catch (Exception e) {
       csb.close();
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java
index 249931d..2cd2479 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ContentTypeBasedEntityProvider.java
@@ -81,6 +81,8 @@ public interface ContentTypeBasedEntityProvider {
   ODataResponse writeErrorDocument(HttpStatusCodes status, String errorCode, 
String message, Locale locale,
       String innerError);
 
+  ODataResponse writeErrorDocument(ODataErrorContext context);
+
   ServiceDocument readServiceDocument(InputStream serviceDocument) throws 
EntityProviderException;
 
   ODataDeltaFeed readDeltaFeed(EdmEntitySet entitySet, InputStream content, 
EntityProviderReadProperties properties)
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
index fa94320..1d87012 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/JsonEntityProvider.java
@@ -85,15 +85,34 @@ public class JsonEntityProvider implements 
ContentTypeBasedEntityProvider {
   @Override
   public ODataResponse writeErrorDocument(final HttpStatusCodes status, final 
String errorCode, final String message,
       final Locale locale, final String innerError) {
+      ODataErrorContext context = new ODataErrorContext();
+      context.setHttpStatus(status);
+      context.setErrorCode(errorCode);
+      context.setMessage(message);
+      context.setLocale(locale);
+      context.setInnerError(innerError);
+
+      return writeErrorDocument(context);
+  }
+
+  /**
+   * <p>Serializes an error message according to the OData standard.</p>
+   * <p>In case an error occurs, it is logged.
+   * An exception is not thrown because this method is used in exception 
handling.</p>
+   * @param context the {@link ODataErrorContext} associated with this error
+   * @return an {@link ODataResponse} containing the serialized error message
+   */
+  @Override
+  public ODataResponse writeErrorDocument(ODataErrorContext context) {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
 
     try {
       BufferedWriter writer = new BufferedWriter(new 
OutputStreamWriter(buffer.getOutputStream(), DEFAULT_CHARSET));
-      new JsonErrorDocumentProducer().writeErrorDocument(writer, errorCode, 
message, locale, innerError);
+      new JsonErrorDocumentProducer().writeErrorDocument(writer, context);
       writer.flush();
       buffer.closeWrite();
 
-      return ODataResponse.status(status)
+      return ODataResponse.status(context.getHttpStatus())
           .entity(buffer.getInputStream())
           .header(ODataHttpHeaders.DATASERVICEVERSION, ODataServiceVersion.V10)
           .build();
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
index 9acf487..01a564d 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/ProviderFacadeImpl.java
@@ -87,8 +87,7 @@ public class ProviderFacadeImpl implements 
EntityProviderInterface {
   @Override
   public ODataResponse writeErrorDocument(final ODataErrorContext context) {
     try {
-      return 
create(context.getContentType()).writeErrorDocument(context.getHttpStatus(), 
context.getErrorCode(),
-          context.getMessage(), context.getLocale(), context.getInnerError());
+      return create(context.getContentType()).writeErrorDocument(context);
     } catch (EntityProviderException e) {
       throw new ODataRuntimeException(e);
     }
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java
index 54b5760..c838886 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorDocumentProducer.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.Writer;
 import java.util.Locale;
 
+import org.apache.olingo.odata2.api.processor.ODataErrorContext;
 import org.apache.olingo.odata2.core.ep.util.FormatJson;
 import org.apache.olingo.odata2.core.ep.util.JsonStreamWriter;
 
@@ -32,13 +33,25 @@ public class JsonErrorDocumentProducer {
 
   public void writeErrorDocument(final Writer writer, final String errorCode, 
final String message,
       final Locale locale, final String innerError) throws IOException {
-    JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
+      ODataErrorContext context = new ODataErrorContext();
+      context.setErrorCode(errorCode);
+      context.setMessage(message);
+      context.setLocale(locale);
+      context.setInnerError(innerError);
+
+      writeErrorDocument(writer, context);
+  }
 
+  public void writeErrorDocument(final Writer writer, ODataErrorContext 
context) throws IOException {
+    Locale locale = context.getLocale();
+    String innerError = context.getInnerError();
+
+    JsonStreamWriter jsonStreamWriter = new JsonStreamWriter(writer);
     jsonStreamWriter
         .beginObject()
         .name(FormatJson.ERROR)
         .beginObject()
-        .namedStringValue(FormatJson.CODE, errorCode)
+        .namedStringValue(FormatJson.CODE, context.getErrorCode())
         .separator()
         .name(FormatJson.MESSAGE)
         .beginObject()
@@ -48,12 +61,28 @@ public class JsonErrorDocumentProducer {
                 locale.getLanguage()
                     + (locale.getCountry() == null || 
locale.getCountry().isEmpty() ? "" : ("-" + locale.getCountry())))
         .separator()
-        .namedStringValue(FormatJson.VALUE, message)
+        .namedStringValue(FormatJson.VALUE, context.getMessage())
         .endObject();
-    if (innerError != null) {
-      jsonStreamWriter.separator()
-          .namedStringValue(FormatJson.INNER_ERROR, innerError);
-    }
+        if (!context.getErrorDetails().isEmpty()) {
+            int cntr = 0;
+            
jsonStreamWriter.separator().name(FormatJson.INNER_ERROR).beginObject().name(FormatJson.ERROR_DETAILS)
+                    .beginArray();
+            for (ODataErrorContext detail : context.getErrorDetails()) {
+                if (cntr > 0) {
+                    jsonStreamWriter.separator();
+                }
+                cntr++;
+                jsonStreamWriter.beginObject()
+                .namedStringValue(FormatJson.CODE, 
detail.getErrorCode()).separator()
+                .namedStringValue(FormatJson.MESSAGE, 
detail.getMessage()).separator()
+                .namedStringValue(FormatJson.TARGET, 
detail.getTarget()).separator()
+                .namedStringValue(FormatJson.SEVERITY, detail.getSeverity())
+                .endObject();
+            }
+            jsonStreamWriter.endArray().endObject();
+        } else if (innerError != null) {
+            
jsonStreamWriter.separator().namedStringValue(FormatJson.INNER_ERROR, 
innerError);
+        }
     jsonStreamWriter.endObject()
         .endObject();
   }
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
index 05ee992..e5ff2fd 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorDocumentProducer.java
@@ -18,26 +18,40 @@
  
******************************************************************************/
 package org.apache.olingo.odata2.core.ep.producer;
 
+import java.util.Collection;
 import java.util.Locale;
 
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
 
 import org.apache.olingo.odata2.api.edm.Edm;
+import org.apache.olingo.odata2.api.processor.ODataErrorContext;
 import org.apache.olingo.odata2.core.ep.util.FormatXml;
 
 public class XmlErrorDocumentProducer {
 
   public void writeErrorDocument(final XMLStreamWriter writer, final String 
errorCode, final String message,
       final Locale locale, final String innerError) throws XMLStreamException {
+      ODataErrorContext context = new ODataErrorContext();
+      context.setErrorCode(errorCode);
+      context.setMessage(message);
+      context.setLocale(locale);
+      context.setInnerError(innerError);
+
+      writeErrorDocument(writer, context);
+  }
+
+  public void writeErrorDocument(final XMLStreamWriter writer, 
ODataErrorContext context) throws XMLStreamException {
+    Locale locale = context.getLocale();
+    String errorCode = context.getErrorCode();
+    String message = context.getMessage();
+    String innerError = context.getInnerError();
+    Collection<ODataErrorContext> errorDetails = context.getErrorDetails();
+
     writer.writeStartDocument();
     writer.writeStartElement(FormatXml.M_ERROR);
     writer.writeDefaultNamespace(Edm.NAMESPACE_M_2007_08);
-    writer.writeStartElement(FormatXml.M_CODE);
-    if (errorCode != null) {
-      writer.writeCharacters(errorCode);
-    }
-    writer.writeEndElement();
+    writeSimpleElement(writer, FormatXml.M_CODE, errorCode);
     writer.writeStartElement(FormatXml.M_MESSAGE);
     if (locale != null) {
       writer.writeAttribute(Edm.PREFIX_XML, Edm.NAMESPACE_XML_1998, 
FormatXml.XML_LANG, getLocale(locale));
@@ -49,15 +63,33 @@ public class XmlErrorDocumentProducer {
     }
     writer.writeEndElement();
 
-    if (innerError != null) {
-      writer.writeStartElement(FormatXml.M_INNER_ERROR);
-      writer.writeCharacters(innerError);
-      writer.writeEndElement();
+    if (!errorDetails.isEmpty()) {
+       writeErrorDetails(writer, errorDetails);
+    } else if (innerError != null) {
+      writeSimpleElement(writer, FormatXml.M_INNER_ERROR, innerError);
     }
 
     writer.writeEndDocument();
   }
 
+  private void writeErrorDetails(final XMLStreamWriter writer, 
Collection<ODataErrorContext> errorDetails)
+          throws XMLStreamException {
+      writer.writeStartElement(FormatXml.M_INNER_ERROR);
+      writer.writeStartElement(FormatXml.M_ERROR_DETAILS);
+      for (ODataErrorContext detail : errorDetails) {
+            writer.writeStartElement(FormatXml.M_ERROR_DETAIL);
+
+            writeSimpleElement(writer, FormatXml.M_CODE, 
detail.getErrorCode());
+            writeSimpleElement(writer, FormatXml.M_MESSAGE, 
detail.getMessage());
+            writeSimpleElement(writer, FormatXml.M_TARGET, detail.getTarget());
+            writeSimpleElement(writer, FormatXml.M_SEVERITY, 
detail.getSeverity());
+
+            writer.writeEndElement();
+      }
+      writer.writeEndElement();
+      writer.writeEndElement();
+  }
+
   /**
    * Gets language and country as defined in RFC 4646 based on {@link Locale}.
    */
@@ -69,4 +101,12 @@ public class XmlErrorDocumentProducer {
     }
   }
 
+  private void writeSimpleElement(final XMLStreamWriter writer, String 
elementName, String value)
+          throws XMLStreamException {
+      writer.writeStartElement(elementName);
+      if (null != value) {
+          writer.writeCharacters(value);
+      }
+      writer.writeEndElement();
+  }
 }
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
index f1010c0..7b36ef8 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatJson.java
@@ -46,9 +46,12 @@ public class FormatJson {
   public static final String ERROR = "error";
   public static final String CODE = "code";
   public static final String MESSAGE = "message";
+  public static final String TARGET = "target";
+  public static final String SEVERITY = "severity";
   public static final String LANG = "lang";
   public static final String VALUE = "value";
   public static final String INNER_ERROR = "innererror";
+  public static final String ERROR_DETAILS = "errordetails";
   public static final String DELTA = "__delta";
   public static final String ODATA_CONTEXT = "@odata.context";
   public static final String DELTA_CONTEXT_PREFIX = "$metadata#";
diff --git 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
index 8ad0181..058093d 100644
--- 
a/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
+++ 
b/odata2-lib/odata-core/src/main/java/org/apache/olingo/odata2/core/ep/util/FormatXml.java
@@ -40,9 +40,13 @@ public class FormatXml {
   public static final String M_INLINE = "inline";
 
   public static final String M_ERROR = "error";
+  public static final String M_SEVERITY = "severity";
+  public static final String M_TARGET = "target";
   public static final String M_CODE = "code";
   public static final String M_MESSAGE = "message";
   public static final String M_INNER_ERROR = "innererror";
+  public static final String M_ERROR_DETAILS = "errordetails";
+  public static final String M_ERROR_DETAIL = "errordetail";
 
   public static final String D_ELEMENT = "element";
   public static final String D_LINKS = "links";
diff --git 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java
 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java
index 29f1e95..8feea0b 100644
--- 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java
+++ 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/JsonErrorProducerTest.java
@@ -22,6 +22,7 @@ import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 
 import java.io.InputStream;
+import java.util.Arrays;
 import java.util.Locale;
 
 import org.apache.olingo.odata2.api.ODataServiceVersion;
@@ -55,6 +56,44 @@ public class JsonErrorProducerTest {
     testSerializeJSON(null, null, null);
   }
 
+  @Test
+  public void jsonSerializationWithDetails() throws Exception {
+    String errorCode = "500";
+    String message = "Main message";
+    Locale locale = Locale.GERMAN;
+    String innerError = "Inner Error";
+
+    ODataErrorContext detailed1 = new ODataErrorContext();
+    detailed1.setErrorCode("500");
+    detailed1.setMessage("Detailed message");
+    detailed1.setSeverity("error");
+    detailed1.setTarget("element1");
+
+    ODataErrorContext detailed2 = new ODataErrorContext();
+    detailed2.setErrorCode("404");
+    detailed2.setMessage("Detailed message 2");
+    detailed2.setSeverity("warn");
+    detailed2.setTarget("element2");
+
+    ODataErrorContext ctx = new ODataErrorContext();
+    ctx.setContentType(HttpContentType.APPLICATION_JSON);
+    ctx.setErrorCode(errorCode);
+    ctx.setHttpStatus(HttpStatusCodes.INTERNAL_SERVER_ERROR);
+    ctx.setLocale(locale);
+    ctx.setMessage(message);
+    ctx.setInnerError(innerError);
+    ctx.setErrorDetails(Arrays.asList(detailed1, detailed2));
+
+    ODataResponse response = new ProviderFacadeImpl().writeErrorDocument(ctx);
+    final String jsonErrorMessage = 
StringHelper.inputStreamToString((InputStream) response.getEntity());
+    assertEquals(jsonErrorMessage, 
+        
"{\"error\":{\"code\":\"500\",\"message\":{\"lang\":\"de\",\"value\":\"Main 
message\"},"
+        + "\"innererror\":"
+        + "{\"errordetails\":["
+        + "{\"code\":\"500\",\"message\":\"Detailed 
message\",\"target\":\"element1\",\"severity\":\"error\"},"
+        + "{\"code\":\"404\",\"message\":\"Detailed message 
2\",\"target\":\"element2\",\"severity\":\"warn\"}]}}}");
+  }
+
   // helper method
   private void testSerializeJSON(final String errorCode, final String message, 
final Locale locale) throws Exception {
     ODataErrorContext ctx = new ODataErrorContext();
diff --git 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java
 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java
index 85538ce..9aa88f5 100644
--- 
a/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java
+++ 
b/odata2-lib/odata-core/src/test/java/org/apache/olingo/odata2/core/ep/producer/XmlErrorProducerTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.assertNull;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
@@ -149,6 +150,38 @@ public class XmlErrorProducerTest extends 
AbstractXmlProducerTestHelper {
   }
 
   @Test
+  public void withErrorDetails() throws Exception {
+    String errorCode = "500";
+    String message = "Main message";
+    String detailedMessage = "Detailed message";
+    String severity = "error";
+    String target = "element1";
+    Locale locale = Locale.GERMAN;
+    String innerError = "Inner Error";
+
+    ODataErrorContext detailed = new ODataErrorContext();
+    detailed.setErrorCode(errorCode);
+    detailed.setMessage(detailedMessage);
+    detailed.setSeverity(severity);
+    detailed.setTarget(target);
+
+    ODataErrorContext ctx = new ODataErrorContext();
+    ctx.setContentType(contentType);
+    ctx.setErrorCode(errorCode);
+    ctx.setHttpStatus(expectedStatus);
+    ctx.setLocale(locale);
+    ctx.setMessage(message);
+    ctx.setInnerError(innerError);
+    ctx.setErrorDetails(Collections.singletonList(detailed));
+
+    ODataResponse response = new ProviderFacadeImpl().writeErrorDocument(ctx);
+    String errorXml = verifyResponse(response);
+    System.out.println(errorXml);
+    verifyXml(errorCode, message, locale, innerError, errorXml);
+    verifyDetailsXml(errorCode, detailedMessage, severity, target, errorXml);
+  }
+
+  @Test
   public void normal() throws Exception {
     serializeError(null, "Message", null, Locale.GERMAN);
     serializeError(null, "Message", null, Locale.ENGLISH);
@@ -222,8 +255,14 @@ public class XmlErrorProducerTest extends 
AbstractXmlProducerTestHelper {
   private void
       serializeError(final String errorCode, final String message, final 
String innerError, final Locale locale)
           throws Exception {
+    ODataErrorContext context = new ODataErrorContext();
+    context.setHttpStatus(expectedStatus);
+    context.setErrorCode(errorCode);
+    context.setMessage(message);
+    context.setLocale(locale);
+    context.setInnerError(innerError);
     ODataResponse response =
-        new AtomEntityProvider().writeErrorDocument(expectedStatus, errorCode, 
message, locale, innerError);
+        new AtomEntityProvider().writeErrorDocument(context);
     String errorXml = verifyResponse(response);
     verifyXml(errorCode, message, locale, innerError, errorXml);
   }
@@ -267,4 +306,23 @@ public class XmlErrorProducerTest extends 
AbstractXmlProducerTestHelper {
       assertXpathExists("/a:error/a:innererror", errorXml);
     }
   }
+
+  private void verifyDetailsXml(final String errorCode, final String message, 
+          String severity, String target, final String errorXml) throws 
Exception {
+    assertXpathExists("/a:error/a:innererror/a:errordetails/a:errordetail", 
errorXml);
+
+    if (errorCode != null) {
+        assertXpathEvaluatesTo(errorCode, 
"/a:error/a:innererror/a:errordetails/a:errordetail/a:code", errorXml);
+    }
+    if (message != null) {
+        assertXpathEvaluatesTo(message, 
"/a:error/a:innererror/a:errordetails/a:errordetail/a:message", errorXml);
+    }
+    if (severity != null) {
+        assertXpathEvaluatesTo(severity, 
"/a:error/a:innererror/a:errordetails/a:errordetail/a:severity", errorXml);
+    }
+    if (target != null) {
+        assertXpathEvaluatesTo(target, 
"/a:error/a:innererror/a:errordetails/a:errordetail/a:target", errorXml);
+    }
+  }
+
 }

Reply via email to