olingo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From chri...@apache.org
Subject olingo-odata4 git commit: [OLINGO-731] Debug interfaces part 2
Date Fri, 24 Jul 2015 07:45:38 GMT
Repository: olingo-odata4
Updated Branches:
  refs/heads/master 8f763aade -> fb65199d2


[OLINGO-731] Debug interfaces part 2


Project: http://git-wip-us.apache.org/repos/asf/olingo-odata4/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata4/commit/fb65199d
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/fb65199d
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/fb65199d

Branch: refs/heads/master
Commit: fb65199d288892d281678d068ce37c44da54be04
Parents: 8f763aa
Author: Christian Amend <christian.amend@sap.com>
Authored: Fri Jul 10 10:50:33 2015 +0200
Committer: Christian Amend <christian.amend@sap.com>
Committed: Fri Jul 24 09:29:13 2015 +0200

----------------------------------------------------------------------
 .../apache/olingo/server/api/ODataRequest.java  |  22 +-
 .../server/api/debug/DebugResponseHelper.java   |   9 +-
 .../olingo/server/api/debug/DebugSupport.java   |   5 +-
 .../server/api/debug/DefaultDebugSupport.java   |   8 +-
 .../server/api/debug/RuntimeMeasurement.java    | 106 ++++++++
 lib/server-core/pom.xml                         |  10 +-
 .../apache/olingo/server/core/ODataHandler.java |  31 ++-
 .../server/core/ODataHttpHandlerImpl.java       | 105 +++++++-
 .../apache/olingo/server/core/ODataImpl.java    |   2 +-
 .../olingo/server/core/debug/DebugInfo.java     |  50 ++++
 .../olingo/server/core/debug/DebugInfoBody.java | 150 +++++++++++
 .../server/core/debug/DebugInfoException.java   | 142 +++++++++++
 .../server/core/debug/DebugInfoRequest.java     | 112 ++++++++
 .../server/core/debug/DebugInfoResponse.java    |  87 +++++++
 .../server/core/debug/DebugInfoRuntime.java     | 186 ++++++++++++++
 .../server/core/debug/DebugInfoServer.java      |  87 +++++++
 .../olingo/server/core/debug/DebugInfoUri.java  | 231 +++++++++++++++++
 .../core/debug/DebugResponseHelperImpl.java     | 255 ++++++++++++++++++-
 lib/server-tecsvc/pom.xml                       |   1 -
 lib/server-test/pom.xml                         |   1 -
 20 files changed, 1556 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
index ea48749..ed34e96 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataRequest.java
@@ -6,9 +6,9 @@
  * 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
@@ -39,6 +39,7 @@ public class ODataRequest {
   private String rawODataPath;
   private String rawBaseUri;
   private String rawServiceResolutionUri;
+  private String protocol;
 
   /**
    * Gets the HTTP method.
@@ -203,4 +204,21 @@ public class ODataRequest {
   public void setRawServiceResolutionUri(final String rawServiceResolutionUri) {
     this.rawServiceResolutionUri = rawServiceResolutionUri;
   }
+
+  /**
+   * @return the protocol version used e.g. HTTP/1.1
+   */
+  public String getProtocol() {
+    return protocol;
+  }
+
+  /**
+   * Sets the HTTP protocol used
+   * @param protocol
+   * @see #getProtocol()
+   */
+  public void setProtocol(String protocol) {
+    this.protocol = protocol;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java
index 62a2d8a..bf6fc56 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugResponseHelper.java
@@ -18,6 +18,9 @@
  */
 package org.apache.olingo.server.api.debug;
 
+import java.util.List;
+import java.util.Map;
+
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 
@@ -31,8 +34,10 @@ public interface DebugResponseHelper {
    * @param request
    * @param applicationResponse
    * @param exception
+   * @param serverEnvironmentVaribles
+   * @param runtimeInformation
    * @return the debug response or the raw application response in case an exception occurred.
    */
-  ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception);
-
+  ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception,
+      Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java
index 3ed39a5..995ba34 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugSupport.java
@@ -18,6 +18,9 @@
  */
 package org.apache.olingo.server.api.debug;
 
+import java.util.List;
+import java.util.Map;
+
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
@@ -44,6 +47,6 @@ public interface DebugSupport {
    * @return a new debug response which will be send to the client
    */
   ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse response,
-      Exception exception);
+      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java
index fb8851d..cca537f 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DefaultDebugSupport.java
@@ -18,6 +18,9 @@
  */
 package org.apache.olingo.server.api.debug;
 
+import java.util.List;
+import java.util.Map;
+
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
@@ -36,12 +39,13 @@ public class DefaultDebugSupport implements DebugSupport {
 
   @Override
   public ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse applicationResponse,
-      Exception exception) {
+      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
     // Check if debugFormat is supported by the library
     if (DebugSupport.ODATA_DEBUG_JSON.equalsIgnoreCase(debugFormat)
         || DebugSupport.ODATA_DEBUG_HTML.equalsIgnoreCase(debugFormat)
         || DebugSupport.ODATA_DEBUG_DOWNLOAD.equalsIgnoreCase(debugFormat)) {
-      return odata.createDebugResponseHelper(debugFormat).createDebugResponse(request, applicationResponse, exception);
+      return odata.createDebugResponseHelper(debugFormat).createDebugResponse(request, applicationResponse, exception,
+          serverEnvironmentVaribles, runtimeInformation);
     } else {
       // Debug format is not supported by the library by default so in order to avoid an exception we will just give
       // back the original response from the application.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/RuntimeMeasurement.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/RuntimeMeasurement.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/RuntimeMeasurement.java
new file mode 100644
index 0000000..69e30da
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/RuntimeMeasurement.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.server.api.debug;
+
+/**
+ * <p>Runtime measurements.</p>
+ * <p>All times are in nanoseconds since some fixed but arbitrary time
+ * (perhaps in the future, so values may be negative).</p>
+ * @see System#nanoTime()
+ */
+public class RuntimeMeasurement {
+
+  private String className;
+  private String methodName;
+  private long timeStarted;
+  private long timeStopped;
+
+  /**
+   * Sets the class name.
+   * @param className the name of the class that is measured
+   */
+  public void setClassName(String className) {
+    this.className = className;
+  }
+
+  /**
+   * Gets the class name.
+   * @return the name of the class that is measured
+   */
+  public String getClassName() {
+    return className;
+  };
+
+  /**
+   * Sets the method name.
+   * @param methodName the name of the method that is measured
+   */
+  public void setMethodName(String methodName) {
+    this.methodName = methodName;
+  }
+
+  /**
+   * Gets the method name.
+   * @return the name of the method that is measured
+   */
+  public String getMethodName() {
+    return methodName;
+  }
+
+  /**
+   * Sets the start time.
+   * @param timeStarted the start time in nanoseconds
+   * @see System#nanoTime()
+   */
+  public void setTimeStarted(long timeStarted) {
+    this.timeStarted = timeStarted;
+  }
+
+  /**
+   * Gets the start time.
+   * @return the start time in nanoseconds or 0 if not set yet
+   * @see System#nanoTime()
+   */
+  public long getTimeStarted() {
+    return timeStarted;
+  }
+
+  /**
+   * Sets the stop time.
+   * @param timeStopped the stop time in nanoseconds
+   * @see System#nanoTime()
+   */
+  public void setTimeStopped(long timeStopped) {
+    this.timeStopped = timeStopped;
+  }
+
+  /**
+   * Gets the stop time.
+   * @return the stop time in nanoseconds or 0 if not set yet
+   * @see System#nanoTime()
+   */
+  public long getTimeStopped() {
+    return timeStopped;
+  }
+
+  @Override
+  public String toString() {
+    return className + "." + methodName + ": duration: " + (timeStopped - timeStarted);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-core/pom.xml b/lib/server-core/pom.xml
index 7d1758e..68c48a3 100644
--- a/lib/server-core/pom.xml
+++ b/lib/server-core/pom.xml
@@ -55,7 +55,10 @@
       <version>2.5</version>
       <scope>provided</scope>
     </dependency>
-
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
 
     <dependency>
       <groupId>junit</groupId>
@@ -69,11 +72,6 @@
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
     </dependency>
-    <dependency>
-      <groupId>commons-io</groupId>
-      <artifactId>commons-io</artifactId>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHandler.java
----------------------------------------------------------------------
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 47bef3d..1a0df8d 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
@@ -58,6 +58,7 @@ public class ODataHandler {
   private CustomETagSupport customETagSupport;
 
   private UriInfo uriInfo;
+  private Exception lastThrownException;
 
   public ODataHandler(final OData server, final ServiceMetadata serviceMetadata) {
     odata = server;
@@ -75,37 +76,37 @@ public class ODataHandler {
 
     } catch (final UriValidationException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (final UriParserSemanticException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (final UriParserSyntaxException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (final UriParserException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (ContentNegotiatorException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (SerializerException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (DeserializerException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (PreconditionException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (ODataHandlerException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (ODataApplicationException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     } catch (Exception e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
-      handleException(request, response, serverError);
+      handleException(request, response, serverError, e);
     }
     return response;
   }
@@ -124,8 +125,8 @@ public class ODataHandler {
   }
 
   public void handleException(final ODataRequest request, final ODataResponse response,
-      final ODataServerError serverError) {
-
+      final ODataServerError serverError, Exception exception) {
+    this.lastThrownException = exception;
     ErrorProcessor exceptionProcessor;
     try {
       exceptionProcessor = selectProcessor(ErrorProcessor.class);
@@ -187,4 +188,8 @@ public class ODataHandler {
   public CustomETagSupport getCustomETagSupport() {
     return customETagSupport;
   }
+
+  public Exception getLastThrownException() {
+    return lastThrownException;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
----------------------------------------------------------------------
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 566086a..2bab186 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
@@ -24,7 +24,9 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Map.Entry;
 
 import javax.servlet.http.HttpServletRequest;
@@ -41,6 +43,7 @@ import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.debug.DebugSupport;
+import org.apache.olingo.server.api.debug.RuntimeMeasurement;
 import org.apache.olingo.server.api.etag.CustomETagSupport;
 import org.apache.olingo.server.api.processor.Processor;
 import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
@@ -53,10 +56,17 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
   private static final Logger LOG = LoggerFactory.getLogger(ODataHttpHandlerImpl.class);
 
   private final ODataHandler handler;
-  private DebugSupport debugSupport;
+  private final OData odata;
   private int split = 0;
 
+  // debug stuff
+  private final List<RuntimeMeasurement> runtimeInformation = new ArrayList<RuntimeMeasurement>();
+  private DebugSupport debugSupport;
+  private String debugFormat;
+  private boolean isDebugMode = false;
+
   public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata serviceMetadata) {
+    this.odata = odata;
     handler = new ODataHandler(odata, serviceMetadata);
   }
 
@@ -65,31 +75,101 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
     Exception exception = null;
     ODataRequest odRequest = null;
     ODataResponse odResponse;
+    resolveDebugMode(request);
+    int processMethodHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "process");
+
     try {
       odRequest = new ODataRequest();
+      int requestHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "fillODataRequest");
       fillODataRequest(odRequest, request, split);
+      stopRuntimeMeasurement(requestHandel);
+      
+      int responseHandel = startRuntimeMeasurement("ODataHandler", "process");
       odResponse = handler.process(odRequest);
+      stopRuntimeMeasurement(responseHandel);
       // ALL future methods after process must not throw exceptions!
     } catch (Exception e) {
       exception = e;
       odResponse = handleException(odRequest, e);
     }
-
-    if (debugSupport != null) {
-      String debugFormat = getDebugQueryParameter(request);
-      if (debugFormat != null) {
-        // TODO: Should we be more careful here with response assignement in order to not loose the original response?
-        // TODO: How should we react to exceptions here?
-        odResponse = debugSupport.createDebugResponse(debugFormat, odRequest, odResponse, exception);
+    stopRuntimeMeasurement(processMethodHandel);
+
+    if (isDebugMode) {
+      debugSupport.init(odata);
+      // TODO: Should we be more careful here with response assignement in order to not loose the original response?
+      // TODO: How should we react to exceptions here?
+      if (exception == null) {
+        // This is to ensure that we have access to the thrown OData Exception
+        // TODO: Should we make this hack
+        exception = handler.getLastThrownException();
       }
+      Map<String, String> serverEnvironmentVaribles = createEnvironmentVariablesMap(request);
+
+      odResponse =
+          debugSupport.createDebugResponse(debugFormat, odRequest, odResponse, exception, serverEnvironmentVaribles,
+              runtimeInformation);
     }
 
     convertToHttp(response, odResponse);
   }
 
-  private String getDebugQueryParameter(HttpServletRequest request) {
-    // TODO Auto-generated method stub
-    return "";
+  private void resolveDebugMode(HttpServletRequest request) {
+    if (debugSupport != null) {
+      // Should we read the parameter from the servlet here and ignore multiple parameters?
+      debugFormat = request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER);
+      // Debug format is present and we have a debug support processor registered so we are in debug mode
+      isDebugMode = debugFormat != null;
+    }
+  }
+
+  public int startRuntimeMeasurement(final String className, final String methodName) {
+    if (isDebugMode) {
+      int handleId = runtimeInformation.size();
+
+      final RuntimeMeasurement measurement = new RuntimeMeasurement();
+      measurement.setTimeStarted(System.nanoTime());
+      measurement.setClassName(className);
+      measurement.setMethodName(methodName);
+
+      runtimeInformation.add(measurement);
+
+      return handleId;
+    } else {
+      return 0;
+    }
+  }
+
+  public void stopRuntimeMeasurement(final int handle) {
+    if (isDebugMode && handle < runtimeInformation.size()) {
+        long stopTime = System.nanoTime();
+        RuntimeMeasurement runtimeMeasurement = runtimeInformation.get(handle);
+        if (runtimeMeasurement != null) {
+          runtimeMeasurement.setTimeStopped(stopTime);
+        }
+      }
+  }
+
+  private Map<String, String> createEnvironmentVariablesMap(HttpServletRequest request) {
+    LinkedHashMap<String, String> environment = new LinkedHashMap<String, String>();
+    environment.put("authType", request.getAuthType());
+    environment.put("localAddr", request.getLocalAddr());
+    environment.put("localName", request.getLocalName());
+    environment.put("localPort", getIntAsString(request.getLocalPort()));
+    environment.put("pathInfo", request.getPathInfo());
+    environment.put("pathTranslated", request.getPathTranslated());
+    environment.put("remoteAddr", request.getRemoteAddr());
+    environment.put("remoteHost", request.getRemoteHost());
+    environment.put("remotePort", getIntAsString(request.getRemotePort()));
+    environment.put("remoteUser", request.getRemoteUser());
+    environment.put("scheme", request.getScheme());
+    environment.put("serverName", request.getServerName());
+    environment.put("serverPort", getIntAsString(request.getServerPort()));
+    environment.put("servletPath", request.getServletPath());
+    return environment;
+  }
+
+  private String getIntAsString(final int number) {
+    return number == 0 ? "unknown" : Integer.toString(number);
   }
 
   @Override
@@ -107,7 +187,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
     } else {
       serverError = ODataExceptionHelper.createServerErrorObject(e);
     }
-    handler.handleException(odRequest, resp, serverError);
+    handler.handleException(odRequest, resp, serverError, e);
     return resp;
   }
 
@@ -153,6 +233,7 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
       throws ODataLibraryException {
     try {
       odRequest.setBody(httpRequest.getInputStream());
+      odRequest.setProtocol(httpRequest.getProtocol());
       extractHeaders(odRequest, httpRequest);
       extractUri(odRequest, httpRequest, split);
       extractMethod(odRequest, httpRequest);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index dac1642..d1da556 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -145,7 +145,7 @@ public class ODataImpl extends OData {
   public DebugResponseHelper createDebugResponseHelper(String debugFormat) {
     //TODO: What should we do with invalid formats?
     //TODO: Support more debug formats
-    return new DebugResponseHelperImpl();
+    return new DebugResponseHelperImpl(debugFormat);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfo.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfo.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfo.java
new file mode 100644
index 0000000..9c5a1d4
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfo.java
@@ -0,0 +1,50 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+
+/**
+ * Debug information.
+ */
+public interface DebugInfo {
+
+  /**
+   * Gets the name of this debug information part, useful as title.
+   * @return the name
+   */
+  public String getName();
+
+  /**
+   * Appends the content of this debug information part
+   * to the given JSON stream writer.
+   * @param jsonGenerator a JSON generator
+   */
+  public void appendJson(JsonGenerator jsonGenerator) throws IOException;
+
+  /**
+   * Appends the content of this debug information part to the given writer.
+   * @param writer a {@link Writer}
+   */
+  public void appendHtml(Writer writer) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoBody.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoBody.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoBody.java
new file mode 100644
index 0000000..e266aae
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoBody.java
@@ -0,0 +1,150 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.ODataResponse;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Response body debug information.
+ */
+public class DebugInfoBody implements DebugInfo {
+
+  private static enum ResponseContent {JSON, XML, TEXT, IMAGE};
+  
+  private final ODataResponse response;
+  private final ResponseContent responseContent;
+  
+  //private final String serviceRoot;
+//  private final boolean isXml;
+//  private final boolean isJson;
+//  private final boolean isText;
+//  private final boolean isImage;
+
+  public DebugInfoBody(final ODataResponse response, final String serviceRoot) {
+    this.response = response;
+    // TODO: make header case insensitive
+    final String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE);
+    //TODO: Differentiate better
+    if (contentType != null) {
+      responseContent = ResponseContent.JSON;
+    } else {
+      responseContent = ResponseContent.TEXT;
+    }
+//    isXml = contentType.contains("xml");
+//    isJson = !isXml && contentType.startsWith(HttpContentType.APPLICATION_JSON);
+//    isText = isXml || isJson || contentType.startsWith("text/")
+//        || contentType.startsWith(HttpContentType.APPLICATION_HTTP)
+//        || contentType.startsWith(HttpContentType.MULTIPART_MIXED);
+//    isImage = !isText && contentType.startsWith("image/");
+  }
+
+  @Override
+  public String getName() {
+    return "Body";
+  }
+
+//
+  @Override
+  public void appendJson(final JsonGenerator gen) throws IOException {
+    gen.writeString(getContentString());
+  }
+
+  private String getContentString() {
+    try {
+      String contentString;
+      switch (responseContent) {
+      case IMAGE:
+        //TODO: DecodeString as base 64
+        contentString = "Currently not supported";
+        break;
+      case JSON:
+      case XML:
+      case TEXT:
+      default:
+        // TODO: Remove IOUtils from core dependency
+        contentString = IOUtils.toString(response.getContent(), "UTF-8");
+        break;
+      }
+      return contentString;
+    } catch (IOException e) {
+      return "Could not parse Body for Debug Output";
+    }
+  }
+
+//
+//  @Override
+//  public void appendHtml(final Writer writer) throws IOException {
+//    final String body = getContentString();
+//    if (isImage) {
+//      writer.append("<img src=\"data:").append(response.getContentHeader()).append(";base64,")
+//          .append(body)
+//          .append("\" />\n");
+//    } else {
+//      writer.append("<pre class=\"code").append(isXml ? " xml" : isJson ? " json" : "").append("\">\n")
+//          .append(isXml || isJson ?
+//              addLinks(ODataDebugResponseWrapper.escapeHtml(isXml ? formatXml(body) : formatJson(body)), isXml) :
+//              ODataDebugResponseWrapper.escapeHtml(body))
+//          .append("</pre>\n");
+//    }
+//  }
+//
+//  private String formatXml(final String xml) throws IOException {
+//    try {
+//      Transformer transformer = TransformerFactory.newInstance().newTransformer();
+//      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+//      transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+//      StreamResult outputTarget = new StreamResult(new StringWriter());
+//      transformer.transform(new StreamSource(new StringReader(xml)), outputTarget);
+//      return outputTarget.getWriter().toString();
+//    } catch (final TransformerException e) {
+//      return xml;
+//    }
+//  }
+//
+//  private String formatJson(final String json) {
+//    return new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create().toJson(new JsonParser().parse(json));
+//  }
+//
+//  private String addLinks(final String source, final boolean isXml) {
+//    final String debugOption = ODataDebugResponseWrapper.ODATA_DEBUG_QUERY_PARAMETER + "="
+//        + ODataDebugResponseWrapper.ODATA_DEBUG_HTML;
+//    final String urlPattern = "("
+//        + (isXml ? "(?:href|src|base)=" : "\"(?:uri|media_src|edit_media|__next)\":\\p{Space}*")
+//        + "\")(.+?)\"";
+//    return (isXml ? source.replaceAll("(xmlns(?::\\p{Alnum}+)?=\")(.+?)\"", "$1<span class=\"ns\">$2</span>\"") :
+//        source)
+//        .replaceAll(urlPattern, "$1<a href=\"" + serviceRoot + "$2?" + debugOption + "\">$2</a>\"")
+//        .replaceAll("(<a href=\"" + Pattern.quote(serviceRoot) + ')' + Pattern.quote(serviceRoot), "$1")
+//        .replaceAll("<a href=\"(.+?)\\?(.+?)\\?" + debugOption, "<a href=\"$1?$2&amp;" + debugOption)
+//        .replaceAll("&amp;amp;", "&amp;");
+//  }
+
+  @Override
+  public void appendHtml(Writer writer) throws IOException {
+    // TODO Auto-generated method stub
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoException.java
new file mode 100644
index 0000000..b19252f
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoException.java
@@ -0,0 +1,142 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import org.apache.olingo.server.api.ODataLibraryException;
+import org.apache.olingo.server.api.ODataLibraryException.ODataErrorMessage;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Exception debug information.
+ */
+public class DebugInfoException implements DebugInfo {
+
+  private final Exception exception;
+
+  public DebugInfoException(final Exception exception) {
+    this.exception = exception;
+  }
+
+  @Override
+  public String getName() {
+    return "Stacktrace";
+  }
+
+  @Override
+  public void appendJson(final JsonGenerator gen) throws IOException {
+    gen.writeStartObject();
+    gen.writeFieldName("exceptions");
+    gen.writeStartArray();
+    Throwable throwable = exception;
+    while (throwable != null) {
+      gen.writeStartObject();
+      gen.writeStringField("class", throwable.getClass().getCanonicalName());
+      gen.writeStringField("message", getMessage(throwable));
+      gen.writeFieldName("invocation");
+      appendJsonStackTraceElement(gen, throwable.getStackTrace()[0]);
+      gen.writeEndObject();
+
+      // Get next exception in the cause list
+      throwable = throwable.getCause();
+    }
+    gen.writeEndArray();
+
+    gen.writeFieldName("stacktrace");
+    gen.writeStartArray();
+    for (final StackTraceElement stackTraceElement : exception.getStackTrace()) {
+      appendJsonStackTraceElement(gen, stackTraceElement);
+    }
+    gen.writeEndArray();
+
+    gen.writeEndObject();
+  }
+
+  private String getMessage(final Throwable throwable) {
+    String message;
+    if (throwable instanceof ODataLibraryException) {
+      ODataLibraryException ex = (ODataLibraryException) throwable;
+      // We use the default locale
+      ODataErrorMessage translatedMessage = ex.getTranslatedMessage(null);
+      // We provide the best message we can
+      message = translatedMessage.getMessage() == null ? ex.getMessage() : translatedMessage.getMessage();
+    } else {
+      message = throwable.getMessage();
+    }
+    return message;
+  }
+
+  private void appendJsonStackTraceElement(final JsonGenerator gen, final StackTraceElement element)
+      throws IOException {
+    gen.writeStartObject();
+    gen.writeStringField("class", element.getClassName());
+    gen.writeStringField("method", element.getMethodName());
+    gen.writeStringField("line", Integer.toString(element.getLineNumber()));
+    gen.writeEndObject();
+  }
+
+  @Override
+  public void appendHtml(Writer writer) throws IOException {
+    // TODO Auto-generated method stub
+
+  }
+//
+//  @Override
+//  public void appendHtml(final Writer writer) throws IOException {
+//    appendException(exception, writer);
+//    writer.append("<h2>Stacktrace</h2>\n");
+//    int count = 0;
+//    for (final StackTraceElement stackTraceElement : exception.getStackTrace()) {
+//      appendStackTraceElement(stackTraceElement, ++count == 1, count == exception.getStackTrace().length, writer);
+//    }
+//  }
+//
+//  private void appendException(final Throwable throwable, final Writer writer) throws IOException {
+//    if (throwable.getCause() != null) {
+//      appendException(throwable.getCause(), writer);
+//    }
+//    final StackTraceElement details = throwable.getStackTrace()[0];
+//    writer.append("<h2>").append(throwable.getClass().getCanonicalName()).append("</h2>\n")
+//        .append("<p>")
+//        .append(ODataDebugResponseWrapper.escapeHtml(getMessageText(throwable)))
+//        .append("</p>\n");
+//    appendStackTraceElement(details, true, true, writer);
+//  }
+//
+//  private void appendStackTraceElement(final StackTraceElement stackTraceElement,
+//      final boolean isFirst, final boolean isLast, final Writer writer) throws IOException {
+//    if (isFirst) {
+//      writer.append("<table>\n<thead>\n")
+//          .append("<tr>\n<th class=\"name\">Class</th>\n")
+//          .append("<th class=\"name\">Method</th>\n")
+//          .append("<th class=\"value\">Line number in class</th>\n</tr>\n")
+//          .append("</thead>\n<tbody>\n");
+//    }
+//    writer.append("<tr>\n<td class=\"name\">").append(stackTraceElement.getClassName()).append("</td>\n")
+//        .append("<td class=\"name\">").append(stackTraceElement.getMethodName()).append("</td>\n")
+//        .append("<td class=\"value\">").append(Integer.toString(stackTraceElement.getLineNumber()))
+//        .append("</td>\n</tr>\n");
+//    if (isLast) {
+//      writer.append("</tbody>\n</table>\n");
+//    }
+//  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRequest.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRequest.java
new file mode 100644
index 0000000..e28bbb9
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRequest.java
@@ -0,0 +1,112 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.server.api.ODataRequest;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Request debug information.
+ */
+public class DebugInfoRequest implements DebugInfo {
+
+  private final String method;
+  private final String uri;
+  private final String protocol;
+  private final Map<String, String> headers;
+
+  public DebugInfoRequest(ODataRequest request) {
+    method = request.getMethod() == null ? "unkown" : request.getMethod().toString();
+    uri = request.getRawRequestUri() == null ? "unkown" : request.getRawRequestUri();
+    protocol = request.getProtocol() == null ? "unkown" : request.getProtocol();
+    // TODO: Should we really wrap the headers here or keep the original structure?
+    headers = wrapHeaders(request.getAllHeaders());
+  }
+
+  private Map<String, String> wrapHeaders(Map<String, List<String>> allHeaders) {
+    Map<String, String> localHeaders = new HashMap<String, String>();
+    for (Map.Entry<String, List<String>> entry : allHeaders.entrySet()) {
+      String value = null;
+      if (entry.getValue() != null) {
+        value = "";
+        boolean first = true;
+        for (String valuePart : entry.getValue()) {
+          if (!first) {
+            value = value + ", ";
+          }
+          value = value + valuePart;
+        }
+      }
+    }
+    return localHeaders;
+  }
+
+  @Override
+  public void appendHtml(final Writer writer) throws IOException {
+//    writer.append("<h2>Request Method</h2>\n")
+//        .append("<p>").append(method).append("</p>\n")
+//        .append("<h2>Request URI</h2>\n")
+//        .append("<p>").append(DebugResponseHelperImpl.escapeHtml(uri.toString())).append("</p>\n")
+//        .append("<h2>Request Protocol</h2>\n")
+//        .append("<p>").append(protocol).append("</p>\n");
+//    writer.append("<h2>Request Headers</h2>\n")
+//        .append("<table>\n<thead>\n")
+//        .append("<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n")
+//        .append("</thead>\n<tbody>\n");
+//    for (final String name : headers.keySet()) {
+//      for (final String value : headers.get(name)) {
+//        if (value != null) {
+//          writer.append("<tr><td class=\"name\">").append(name).append("</td>")
+//              .append("<td class=\"value\">").append(DebugResponseHelperImpl.escapeHtml(value))
+//              .append("</td></tr>\n");
+//        }
+//      }
+//    }
+//    writer.append("</tbody>\n</table>\n");
+  }
+
+  @Override
+  public String getName() {
+    return "Request";
+  }
+
+  @Override
+  public void appendJson(JsonGenerator gen) throws IOException {
+    gen.writeStartObject();
+    gen.writeStringField("method", method);
+
+    gen.writeStringField("uri", uri);
+
+    gen.writeStringField("protocol", protocol);
+
+    if (!headers.isEmpty()) {
+      gen.writeFieldName("headers");
+      DebugResponseHelperImpl.appendJsonTable(gen, headers);
+    }
+
+    gen.writeEndObject();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoResponse.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoResponse.java
new file mode 100644
index 0000000..0781d50
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoResponse.java
@@ -0,0 +1,87 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataResponse;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Response debug information.
+ */
+public class DebugInfoResponse implements DebugInfo {
+
+  private final ODataResponse response;
+  private final String serviceRoot;
+  private final HttpStatusCode status;
+  private final Map<String, String> headers;
+
+  public DebugInfoResponse(final ODataResponse applicationResponse, final String serviceRoot) {
+    this.response = applicationResponse;
+    this.serviceRoot = serviceRoot;
+    status = HttpStatusCode.fromStatusCode(response.getStatusCode());
+    headers = response.getHeaders();
+  }
+
+  @Override
+  public String getName() {
+    return "Response";
+  }
+
+  @Override
+  public void appendJson(final JsonGenerator gen) throws IOException {
+    gen.writeStartObject();
+
+    if (status != null) {
+      gen.writeFieldName("status");
+      gen.writeStartObject();
+      gen.writeStringField("code", Integer.toString(status.getStatusCode()));
+      gen.writeStringField("info", status.getInfo());
+      gen.writeEndObject();
+    }
+
+    if (headers != null && !headers.isEmpty()) {
+      gen.writeFieldName("headers");
+      DebugResponseHelperImpl.appendJsonTable(gen, headers);
+    }
+
+    gen.writeFieldName("body");
+    new DebugInfoBody(response, serviceRoot).appendJson(gen);
+
+    gen.writeEndObject();
+  }
+
+  @Override
+  public void appendHtml(final Writer writer) throws IOException {
+//    writer.append("<h2>Status Code</h2>\n")
+//        .append("<p>").append(Integer.toString(status.getStatusCode())).append(' ')
+//        .append(status.getInfo()).append("</p>\n")
+//        .append("<h2>Response Headers</h2>\n");
+//    ODataDebugResponseWrapper.appendHtmlTable(writer, headers);
+//    if (response.getContentHeader() != null && response.getEntity() != null) {
+//      writer.append("<h2>Response Body</h2>\n");
+//      new DebugInfoBody(response, serviceRoot).appendHtml(writer);
+//    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRuntime.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRuntime.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRuntime.java
new file mode 100644
index 0000000..2465ce4
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRuntime.java
@@ -0,0 +1,186 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.olingo.server.api.debug.RuntimeMeasurement;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Runtime debug information.
+ */
+public class DebugInfoRuntime implements DebugInfo {
+
+  private final RuntimeNode rootNode;
+
+  public DebugInfoRuntime(List<RuntimeMeasurement> runtimeInformation) {
+    rootNode = new RuntimeNode();
+    for (final RuntimeMeasurement runtimeMeasurement : runtimeInformation) {
+      rootNode.add(runtimeMeasurement);
+    }
+    rootNode.combineRuntimeMeasurements();
+  }
+
+  @Override
+  public String getName() {
+    return "Runtime";
+  }
+
+  @Override
+  public void appendJson(JsonGenerator gen) throws IOException {
+    appendJsonChildren(gen, rootNode);
+  }
+
+  private void appendJsonChildren(JsonGenerator gen, RuntimeNode node) throws IOException {
+    gen.writeStartArray();
+    for (RuntimeNode child : node.children) {
+      appendJsonNode(gen, child);
+    }
+    gen.writeEndArray();
+  }
+
+  private void appendJsonNode(JsonGenerator gen, RuntimeNode node) throws IOException {
+    gen.writeStartObject();
+    gen.writeStringField("class", node.className);
+    gen.writeStringField("method ", node.methodName);
+
+    if (node.timeStopped == 0) {
+      gen.writeNullField("duration");
+    } else {
+      gen.writeStringField("duration", Long.toString((node.timeStopped - node.timeStarted) / 1000));
+      gen.writeStringField("unit", "┬Ás");
+    }
+
+    if (!node.children.isEmpty()) {
+      gen.writeFieldName("children");
+      appendJsonChildren(gen, node);
+    }
+
+    gen.writeEndObject();
+  }
+
+  @Override
+  public void appendHtml(Writer writer) throws IOException {
+    // TODO Auto-generated method stub
+    //
+//  @Override
+//  public void appendHtml(final Writer writer) throws IOException {
+//    appendRuntimeNode(rootNode, "", true, writer);
+//  }
+//
+//  private void appendRuntimeNode(final RuntimeNode node, final String draw, final boolean isLast, final Writer writer)
+//      throws IOException {
+//    if (node.className != null) {
+//      writer.append("<li>")
+//          .append("<span class=\"code\">")
+//          .append("<span class=\"draw\">").append(draw)
+//          .append(isLast ? "&#x2514;" : "&#x251C;").append("&#x2500;&nbsp;</span>")
+//          .append("<span class=\"class\">").append(node.className).append("</span>.")
+//          .append("<span class=\"method\">").append(node.methodName).append("(&hellip;)")
+//          .append("</span></span>");
+//      long time = node.timeStopped == 0 ? 0 : (node.timeStopped - node.timeStarted) / 1000;
+//      writer.append("<span class=\"").append(time == 0 ? "null" : "numeric")
+//          .append("\" title=\"").append(time == 0 ? "Stop time missing" : "Gross duration")
+//          .append("\">").append(time == 0 ? "unfinished" : Long.toString(time) + "&nbsp;&micro;s")
+//          .append("</span>\n");
+//    }
+//    if (!node.children.isEmpty()) {
+//      writer.append("<ol class=\"tree\">\n");
+//      for (final RuntimeNode childNode : node.children) {
+//        appendRuntimeNode(childNode,
+//            node.className == null ? draw : draw + (isLast ? "&nbsp;" : "&#x2502;") + "&nbsp;&nbsp;",
+//            node.children.indexOf(childNode) == node.children.size() - 1,
+//            writer);
+//      }
+//      writer.append("</ol>\n");
+//    }
+//    if (node.className != null) {
+//      writer.append("</li>\n");
+//    }
+//  }
+  }
+
+  private class RuntimeNode {
+
+    protected String className;
+    protected String methodName;
+    protected long timeStarted;
+    protected long timeStopped;
+    protected List<RuntimeNode> children = new ArrayList<RuntimeNode>();
+
+    protected RuntimeNode() {
+      timeStarted = 0;
+      timeStopped = Long.MAX_VALUE;
+    }
+
+    private RuntimeNode(final RuntimeMeasurement runtimeMeasurement) {
+      className = runtimeMeasurement.getClassName();
+      methodName = runtimeMeasurement.getMethodName();
+      timeStarted = runtimeMeasurement.getTimeStarted();
+      timeStopped = runtimeMeasurement.getTimeStopped();
+    }
+
+    protected boolean add(final RuntimeMeasurement runtimeMeasurement) {
+      if (timeStarted <= runtimeMeasurement.getTimeStarted()
+          && timeStopped != 0 && timeStopped >= runtimeMeasurement.getTimeStopped()) {
+        for (RuntimeNode candidate : children) {
+          if (candidate.add(runtimeMeasurement)) {
+            return true;
+          }
+        }
+        children.add(new RuntimeNode(runtimeMeasurement));
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    /**
+     * Combines runtime measurements with identical class names and method
+     * names into one measurement, assuming that they originate from a loop
+     * or a similar construct where a summary measurement has been intended.
+     */
+    protected void combineRuntimeMeasurements() {
+      RuntimeNode preceding = null;
+      for (Iterator<RuntimeNode> iterator = children.iterator(); iterator.hasNext();) {
+        final RuntimeNode child = iterator.next();
+        if (preceding != null
+            && preceding.timeStopped != 0 && child.timeStopped != 0
+            && preceding.timeStopped <= child.timeStarted
+            && preceding.children.isEmpty() && child.children.isEmpty()
+            && preceding.methodName.equals(child.methodName)
+            && preceding.className.equals(child.className)) {
+          preceding.timeStarted = child.timeStarted - (preceding.timeStopped - preceding.timeStarted);
+          preceding.timeStopped = child.timeStopped;
+
+          iterator.remove();
+        } else {
+          preceding = child;
+          child.combineRuntimeMeasurements();
+        }
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoServer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoServer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoServer.java
new file mode 100644
index 0000000..e974d03
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoServer.java
@@ -0,0 +1,87 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.Map;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Server debug information.
+ */
+public class DebugInfoServer implements DebugInfo {
+
+  private final Map<String, String> serverEnvironmentVaribles;
+
+  public DebugInfoServer(Map<String, String> serverEnvironmentVaribles) {
+    this.serverEnvironmentVaribles = serverEnvironmentVaribles;
+  }
+
+  @Override
+  public String getName() {
+    return "Environment";
+  }
+
+  @Override
+  public void appendJson(JsonGenerator gen) throws IOException {
+    DebugResponseHelperImpl.appendJsonTable(gen, serverEnvironmentVaribles);
+  }
+
+  @Override
+  public void appendHtml(Writer writer) throws IOException {
+    // TODO Auto-generated method stub
+
+  }
+
+//  private final Map<String, String> environment;
+//
+//  public DebugInfoServer(final HttpServletRequest httpServletRequest) {
+//    environment = new TreeMap<String, String>();
+//    environment.put("authType", httpServletRequest.getAuthType());
+//    environment.put("localAddr", httpServletRequest.getLocalAddr());
+//    environment.put("localName", httpServletRequest.getLocalName());
+//    addInt("localPort", httpServletRequest.getLocalPort());
+//    environment.put("pathInfo", httpServletRequest.getPathInfo());
+//    environment.put("pathTranslated", httpServletRequest.getPathTranslated());
+//    environment.put("remoteAddr", httpServletRequest.getRemoteAddr());
+//    environment.put("remoteHost", httpServletRequest.getRemoteHost());
+//    addInt("remotePort", httpServletRequest.getRemotePort());
+//    environment.put("remoteUser", httpServletRequest.getRemoteUser());
+//    environment.put("scheme", httpServletRequest.getScheme());
+//    environment.put("serverName", httpServletRequest.getServerName());
+//    addInt("serverPort", httpServletRequest.getServerPort());
+//    environment.put("servletPath", httpServletRequest.getServletPath());
+//  }
+
+//  @Override
+//  public void appendHtml(final Writer writer) throws IOException {
+//    final Package pack = ODataDebugResponseWrapper.class.getPackage();
+//    writer.append("<h2>Library Version</h2>\n")
+//        .append("<p>").append(pack.getImplementationTitle())
+//        .append(" Version ").append(pack.getImplementationVersion()).append("</p>\n")
+//        .append("<h2>Server Environment</h2>\n");
+//    ODataDebugResponseWrapper.appendHtmlTable(writer, environment);
+//  }
+//
+//  private void addInt(final String name, final int number) {
+//    environment.put(name, number == 0 ? null : Integer.toString(number));
+//  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoUri.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoUri.java
new file mode 100644
index 0000000..2ddeb07
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoUri.java
@@ -0,0 +1,231 @@
+/*
+ * 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.debug;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+
+/**
+ * URI parser debug information.
+ */
+public class DebugInfoUri implements DebugInfo {
+
+  @Override
+  public String getName() {
+    // TODO Auto-generated method stub
+    return null;
+  }
+
+  @Override
+  public void appendJson(JsonGenerator jsonGenerator) throws IOException {
+    // TODO Auto-generated method stub
+    
+  }
+
+  @Override
+  public void appendHtml(Writer writer) throws IOException {
+    // TODO Auto-generated method stub
+    
+  }
+
+//  private final UriInfo uriInfo;
+//  private final FilterExpression filter;
+//  private final OrderByExpression orderBy;
+//  private final ExpandSelectTreeNodeImpl expandSelectTree;
+//  private final ExpressionParserException exception;
+//
+//  public DebugInfoUri(final UriInfo uriInfo, final ExpressionParserException exception) {
+//    this.uriInfo = uriInfo;
+//    filter = uriInfo == null ? null : uriInfo.getFilter();
+//    orderBy = uriInfo == null ? null : uriInfo.getOrderBy();
+//    expandSelectTree = uriInfo == null ? null : getExpandSelect();
+//    this.exception = exception;
+//  }
+//
+//  private ExpandSelectTreeNodeImpl getExpandSelect() {
+//    try {
+//      return uriInfo.getExpand().isEmpty() && uriInfo.getSelect().isEmpty() ? null :
+//          new ExpandSelectTreeCreator(uriInfo.getSelect(), uriInfo.getExpand()).create();
+//    } catch (final EdmException e) {
+//      return null;
+//    }
+//  }
+//
+//  @Override
+//  public String getName() {
+//    return "URI";
+//  }
+//
+//  @Override
+//  public void appendJson(final JsonStreamWriter jsonStreamWriter) throws IOException {
+//    jsonStreamWriter.beginObject();
+//
+//    if (exception != null && exception.getFilterTree() != null) {
+//      jsonStreamWriter.name("error")
+//          .beginObject()
+//          .namedStringValue("expression", exception.getFilterTree().getUriLiteral())
+//          .endObject();
+//      if (filter != null || orderBy != null || expandSelectTree != null) {
+//        jsonStreamWriter.separator();
+//      }
+//    }
+//
+//    if (filter != null) {
+//      String filterString;
+//      try {
+//        filterString = (String) filter.accept(new JsonVisitor());
+//      } catch (final ExceptionVisitExpression e) {
+//        filterString = null;
+//      } catch (final ODataApplicationException e) {
+//        filterString = null;
+//      }
+//      jsonStreamWriter.name("filter").unquotedValue(filterString);
+//      if (orderBy != null || expandSelectTree != null) {
+//        jsonStreamWriter.separator();
+//      }
+//    }
+//
+//    if (orderBy != null) {
+//      String orderByString;
+//      try {
+//        orderByString = (String) orderBy.accept(new JsonVisitor());
+//      } catch (final ExceptionVisitExpression e) {
+//        orderByString = null;
+//      } catch (final ODataApplicationException e) {
+//        orderByString = null;
+//      }
+//      jsonStreamWriter.name("orderby").unquotedValue(orderByString);
+//      if (expandSelectTree != null) {
+//        jsonStreamWriter.separator();
+//      }
+//    }
+//
+//    if (expandSelectTree != null) {
+//      jsonStreamWriter.name("expandSelect").unquotedValue(expandSelectTree.toJsonString());
+//    }
+//
+//    jsonStreamWriter.endObject();
+//  }
+//
+//  @Override
+//  public void appendHtml(final Writer writer) throws IOException {
+//    if (exception != null && exception.getFilterTree() != null) {
+//      writer.append("<h2>Expression Information</h2>\n")
+//          .append("<pre class=\"code\">").append(exception.getFilterTree().getUriLiteral())
+//          .append("</pre>\n");
+//      // TODO: filter error position, filter tokens, filter tree
+//    }
+//    if (filter != null) {
+//      writer.append("<h2>Filter</h2>\n")
+//          .append("<ul class=\"expr\"><li>");
+//      appendExpression(filter.getExpression(), writer);
+//      writer.append("</li></ul>\n");
+//    }
+//    if (orderBy != null) {
+//      writer.append("<h2>Orderby</h2>\n")
+//          .append(orderBy.getOrdersCount() == 1 ? "<ul" : "<ol").append(" class=\"expr\">\n");
+//      for (final OrderExpression order : orderBy.getOrders()) {
+//        writer.append("<li>");
+//        appendExpression(order.getExpression(), writer);
+//        final ExpressionKind kind = order.getExpression().getKind();
+//        if (kind == ExpressionKind.PROPERTY || kind == ExpressionKind.LITERAL) {
+//          writer.append("<br />");
+//        }
+//        writer.append("<span class=\"order\">")
+//            .append(order.getSortOrder().toString())
+//            .append("</span></li>\n");
+//      }
+//      writer.append(orderBy.getOrdersCount() == 1 ? "</ul" : "</ol").append(">\n");
+//    }
+//    if (expandSelectTree != null) {
+//      writer.append("<h2>Expand/Select</h2>\n");
+//      appendExpandSelect(expandSelectTree, writer);
+//    }
+//  }
+//
+//  private void appendExpression(final CommonExpression expression, final Writer writer) throws IOException {
+//    final ExpressionKind kind = expression.getKind();
+//    writer.append("<span class=\"kind\">")
+//        .append(kind.toString())
+//        .append("</span> <span class=\"literal\">")
+//        .append(kind == ExpressionKind.MEMBER ? ((MemberExpression) expression).getProperty().getUriLiteral() :
+//            expression.getUriLiteral())
+//        .append("</span>, type <span class=\"type\">")
+//        .append(expression.getEdmType().toString())
+//        .append("</span>");
+//    if (kind == ExpressionKind.UNARY) {
+//      writer.append("<ul class=\"expr\"><li>");
+//      appendExpression(((UnaryExpression) expression).getOperand(), writer);
+//      writer.append("</li></ul>");
+//    } else if (kind == ExpressionKind.BINARY) {
+//      writer.append("<ol class=\"expr\"><li>");
+//      appendExpression(((BinaryExpression) expression).getLeftOperand(), writer);
+//      writer.append("</li><li>");
+//      appendExpression(((BinaryExpression) expression).getRightOperand(), writer);
+//      writer.append("</li></ol>");
+//    } else if (kind == ExpressionKind.METHOD) {
+//      final MethodExpression methodExpression = (MethodExpression) expression;
+//      if (methodExpression.getParameterCount() > 0) {
+//        writer.append("<ol class=\"expr\">");
+//        for (final CommonExpression parameter : methodExpression.getParameters()) {
+//          writer.append("<li>");
+//          appendExpression(parameter, writer);
+//          writer.append("</li>");
+//        }
+//        writer.append("</ol>");
+//      }
+//    } else if (kind == ExpressionKind.MEMBER) {
+//      writer.append("<ul class=\"expr\"><li>");
+//      appendExpression(((MemberExpression) expression).getPath(), writer);
+//      writer.append("</li></ul>");
+//    }
+//  }
+//
+//  private void appendExpandSelect(final ExpandSelectTreeNode expandSelect, final Writer writer) throws IOException {
+//    writer.append("<ul class=\"expand\">\n")
+//        .append("<li>");
+//    if (expandSelect.isAll()) {
+//      writer.append("all properties");
+//    } else {
+//      for (final EdmProperty property : expandSelect.getProperties()) {
+//        try {
+//          writer.append("property <span class=\"prop\">")
+//              .append(property.getName())
+//              .append("</span><br />");
+//        } catch (final EdmException e) {}
+//      }
+//    }
+//    writer.append("</li>\n");
+//    if (!expandSelect.getLinks().isEmpty()) {
+//      for (final String name : expandSelect.getLinks().keySet()) {
+//        writer.append("<li>link <span class=\"link\">").append(name).append("</span>");
+//        final ExpandSelectTreeNode link = expandSelect.getLinks().get(name);
+//        if (link != null) {
+//          writer.append('\n');
+//          appendExpandSelect(link, writer);
+//        }
+//        writer.append("</li>\n");
+//      }
+//    }
+//    writer.append("</ul>\n");
+//  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
index ca4d7f3..6952018 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugResponseHelperImpl.java
@@ -18,16 +18,265 @@
  */
 package org.apache.olingo.server.core.debug;
 
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.debug.DebugResponseHelper;
+import org.apache.olingo.server.api.debug.DebugSupport;
+import org.apache.olingo.server.api.debug.RuntimeMeasurement;
+import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
+
+import com.fasterxml.jackson.core.JsonEncoding;
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
 
 public class DebugResponseHelperImpl implements DebugResponseHelper {
 
+  private static enum DebugFormat {
+    JSON, HTML, DOWNLOAD
+  };
+
+  private final DebugFormat requestedFormat;
+
+  public DebugResponseHelperImpl(String debugFormat) {
+    if (DebugSupport.ODATA_DEBUG_HTML.equals(debugFormat)) {
+      requestedFormat = DebugFormat.HTML;
+    } else if (DebugSupport.ODATA_DEBUG_DOWNLOAD.equals(debugFormat)) {
+      requestedFormat = DebugFormat.DOWNLOAD;
+    } else {
+      requestedFormat = DebugFormat.JSON;
+    }
+  }
+
   @Override
-  public ODataResponse
-      createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception) {
-    return applicationResponse;
+  public ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse,
+      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
+
+    try {
+      final List<DebugInfo> parts =
+          createParts(request, applicationResponse, exception, serverEnvironmentVaribles, runtimeInformation);
+      
+      ODataResponse response = new ODataResponse();
+      String contentTypeString;
+      InputStream body;
+      switch (requestedFormat) {
+      case DOWNLOAD:
+        response.setHeader("Content-Disposition", "attachment; filename=OData-Response."
+            + new Date().toString().replace(' ', '_').replace(':', '.') + ".html");
+        // Download is the same as html except for the above header
+      case HTML:
+        body = wrapInHtml(parts);
+        contentTypeString = ContentType.TEXT_HTML.toContentTypeString();
+        break;
+      case JSON:
+      default:
+        body = wrapInJson(parts);
+        contentTypeString = ContentType.APPLICATION_JSON.toContentTypeString();
+        break;
+      }
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, contentTypeString);
+      response.setContent(body);
+
+      return response;
+    } catch (IOException e) {
+      // Should not happen
+      // TODO: Check what we can do here.
+      throw new ODataRuntimeException(e);
+    }
+  }
+
+  private List<DebugInfo> createParts(ODataRequest request, ODataResponse applicationResponse, Exception exception,
+      Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
+    List<DebugInfo> parts = new ArrayList<DebugInfo>();
+
+    // request
+    parts.add(new DebugInfoRequest(request));
+
+    // response
+    // TODO: Check service URI
+    parts.add(new DebugInfoResponse(applicationResponse, request.getRawBaseUri()));
+
+    // server
+    if (serverEnvironmentVaribles != null && !serverEnvironmentVaribles.isEmpty()) {
+      parts.add(new DebugInfoServer(serverEnvironmentVaribles));
+    }
+
+//    // URI
+//    Throwable candidate = exception;
+//    while (candidate != null && !(candidate instanceof ExpressionParserException)) {
+//      candidate = candidate.getCause();
+//    }
+//    final ExpressionParserException expressionParserException = (ExpressionParserException) candidate;
+//    if (uriInfo != null
+//        && (uriInfo.getFilter() != null || uriInfo.getOrderBy() != null
+//            || !uriInfo.getExpand().isEmpty() || !uriInfo.getSelect().isEmpty())
+//        || expressionParserException != null && expressionParserException.getFilterTree() != null) {
+//      parts.add(new DebugInfoUri(uriInfo, expressionParserException));
+//    }
+//
+//    // runtime measurements
+    if (runtimeInformation != null && !runtimeInformation.isEmpty()) {
+      parts.add(new DebugInfoRuntime(runtimeInformation));
+    }
+//
+//    // exceptions
+    if (exception != null) {
+      parts.add(new DebugInfoException(exception));
+    }
+
+    return parts;
+  }
+
+  private InputStream wrapInJson(final List<DebugInfo> parts) throws IOException {
+    CircleStreamBuffer csb = new CircleStreamBuffer();
+    JsonGenerator gen = new JsonFactory().createGenerator(csb.getOutputStream(), JsonEncoding.UTF8);
+
+    gen.writeStartObject();
+    DebugInfo requestInfo = parts.get(0);
+    // TODO: Should we really translate to lower case here?
+    gen.writeFieldName(requestInfo.getName().toLowerCase(Locale.ROOT));
+    requestInfo.appendJson(gen);
+
+    DebugInfo responseInfo = parts.get(1);
+    gen.writeFieldName(responseInfo.getName().toLowerCase(Locale.ROOT));
+    responseInfo.appendJson(gen);
+
+    gen.writeFieldName("server");
+    gen.writeStartObject();
+    String version = DebugResponseHelperImpl.class.getPackage().getImplementationVersion();
+    if (version != null) {
+      gen.writeStringField("version", version);
+    } else {
+      gen.writeNullField("version");
+    }
+    for (DebugInfo part : parts.subList(2, parts.size())) {
+      gen.writeFieldName(part.getName().toLowerCase(Locale.ROOT));
+      part.appendJson(gen);
+    }
+    gen.writeEndObject();
+
+    gen.writeEndObject();
+    gen.close();
+
+    return csb.getInputStream();
+  }
+
+  private InputStream wrapInHtml(final List<DebugInfo> parts) throws IOException {
+    StringWriter writer = new StringWriter();
+//    PathInfo pathInfo = null;
+//    try {
+//      pathInfo = context.getPathInfo();
+//    } catch (final ODataException e) {}
+//
+//    writer.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n")
+//        .append("  \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n")
+//        .append("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n")
+//        .append("<head>\n")
+//        .append("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n")
+//        .append("<title>")
+//        .append(pathInfo == null ? "" :
+//            escapeHtml(pathInfo.getServiceRoot().relativize(pathInfo.getRequestUri()).getPath()))
+//        .append("</title>\n")
+//        .append("<style type=\"text/css\">\n")
+//        .append("body { font-family: Arial, sans-serif; font-size: 13px;\n")
+//        .append("       line-height: 16px; margin: 0;\n")
+//        .append("       background-color: #eeeeee; color: #333333; }\n")
+//        .append(".header { float: left; }\n")
+//        .append(".header a { line-height: 22px; padding: 10px 18px;\n")
+//        .append("            text-decoration: none; color: #333333; }\n")
+//        .append(":target, .header:nth-last-child(2) { background-color: #cccccc; }\n")
+//        .append(":target ~ .header:nth-last-child(2) { background-color: inherit; }\n")
+//        .append(".header:focus, .header:hover,\n")
+//        .append("  .header:nth-last-child(2):focus, .header:nth-last-child(2):hover\n")
+//        .append("    { background-color: #999999; }\n")
+//        .append(".section { position: absolute; top: 42px; min-width: 100%;\n")
+//        .append("           padding-top: 18px; border-top: 1px solid #dddddd; }\n")
+//        .append(".section > * { margin-left: 18px; }\n")
+//        .append(":target + .section, .section:last-child { display: block; }\n")
+//        .append(".section, :target + .section ~ .section { display: none; }\n")
+//        .append("h1 { font-size: 18px; font-weight: normal; margin: 10px 0; }\n")
+//        .append("h2 { font-size: 15px; }\n")
+//        .append("h2:not(:first-child) { margin-top: 2em; }\n")
+//        .append("table { border-collapse: collapse; border-spacing: 0;\n")
+//        .append("        margin-top: 1.5em; }\n")
+//        .append("table, thead { border-width: 1px 0; border-style: solid;\n")
+//        .append("               border-color: #dddddd; text-align: left; }\n")
+//        .append("th.name, td.name { padding: 1ex 2em 1ex 0; }\n")
+//        .append("tbody > tr:hover { background-color: #cccccc; }\n")
+//        .append(".code { font-family: \"Courier New\", monospace; }\n")
+//        .append(".code, .tree li { line-height: 15px; }\n")
+//        .append(".code a { text-decoration: underline; color: #666666; }\n")
+//        .append(".xml .ns { font-style: italic; color: #999999; }\n")
+//        .append("ul, .tree { list-style-type: none; }\n")
+//        .append("div > ul.expr, div > .expand, .tree { padding-left: 0; }\n")
+//        .append(".expr, .expand, .null, .numeric { padding-left: 1.5em; }\n")
+//        .append("</style>\n")
+//        .append("</head>\n")
+//        .append("<body>\n");
+//    char count = '0';
+//    for (final DebugInfo part : parts) {
+//      writer.append("<div class=\"header\" id=\"sec").append(++count).append("\">\n")
+//          .append("<h1><a href=\"#sec").append(count).append("\">")
+//          .append(part.getName())
+//          .append("</a></h1>\n")
+//          .append("</div>\n")
+//          .append("<div class=\"section\">\n");
+//      part.appendHtml(writer);
+//      writer.append("</div>\n");
+//    }
+//    writer.append("</body>\n")
+//        .append("</html>\n")
+//        .close();
+    byte[] bytes = writer.toString().getBytes("UTF-8");
+    return new ByteArrayInputStream(bytes);
+  }
+
+  protected static String escapeHtml(final String value) {
+    return value == null ? null : value.replace("&", "&amp;").replace("<", "&lt;").replace(">", "&gt;");
+  }
+
+  protected static void appendJsonTable(final JsonGenerator gen, final Map<String, String> entries)
+      throws IOException {
+    gen.writeStartObject();
+
+    for (Map.Entry<String, String> entry : entries.entrySet()) {
+      if (entry.getValue() != null) {
+        gen.writeStringField(entry.getKey(), entry.getValue());
+      } else {
+        gen.writeNullField(entry.getKey());
+      }
+    }
+    gen.writeEndObject();
   }
+//
+//  protected static void appendHtmlTable(final Writer writer, final Map<String, String> entries) throws IOException {
+//    writer.append("<table>\n<thead>\n")
+//        .append("<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n")
+//        .append("</thead>\n<tbody>\n");
+//    for (final String name : entries.keySet()) {
+//      final String value = entries.get(name);
+//      if (value != null) {
+//        writer.append("<tr><td class=\"name\">").append(name).append("</td>")
+//            .append("<td class=\"value\">")
+//            .append(ODataDebugResponseWrapper.escapeHtml(value))
+//            .append("</td></tr>\n");
+//      }
+//    }
+//    writer.append("</tbody>\n</table>\n");
+//  }
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-tecsvc/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/pom.xml b/lib/server-tecsvc/pom.xml
index 3903811..5bb18ce 100644
--- a/lib/server-tecsvc/pom.xml
+++ b/lib/server-tecsvc/pom.xml
@@ -160,7 +160,6 @@
     <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
-      <scope>test</scope>
     </dependency>
   </dependencies>
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/fb65199d/lib/server-test/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-test/pom.xml b/lib/server-test/pom.xml
index d715698..f698028 100644
--- a/lib/server-test/pom.xml
+++ b/lib/server-test/pom.xml
@@ -66,7 +66,6 @@
     <dependency>
       <groupId>commons-io</groupId>
       <artifactId>commons-io</artifactId>
-      <scope>test</scope>
     </dependency>
   </dependencies>
 


Mime
View raw message