You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/08/04 16:25:41 UTC

[01/18] olingo-odata4 git commit: [OLINGO-735] Replaced '*Builder.reflection*' were possible

Repository: olingo-odata4
Updated Branches:
  refs/heads/OLINGO-640 5b99eb7b6 -> db0b9d39d


[OLINGO-735] Replaced '*Builder.reflection*' were possible


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

Branch: refs/heads/OLINGO-640
Commit: 1ebbbc3698de644c097efe44472130ef248baa92
Parents: 9674aae
Author: mibo <mi...@apache.org>
Authored: Wed Jul 22 10:15:29 2015 +0200
Committer: mibo <mi...@apache.org>
Committed: Wed Jul 22 10:15:29 2015 +0200

----------------------------------------------------------------------
 .../olingo/client/api/data/ServiceDocument.java |  4 +-
 .../client/core/data/ServiceDocumentImpl.java   | 53 +++++++++++++++----
 .../core/data/ServiceDocumentItemImpl.java      | 32 ++++++++----
 .../client/core/domain/ClientPropertyImpl.java  | 39 ++++++++++----
 .../client/core/domain/ClientValuableImpl.java  | 27 ++++++----
 .../commons/api/edm/FullQualifiedName.java      | 32 +++++++++---
 .../apache/olingo/commons/api/edm/geo/SRID.java | 54 ++++++++++++++------
 7 files changed, 178 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/client-api/src/main/java/org/apache/olingo/client/api/data/ServiceDocument.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/data/ServiceDocument.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/data/ServiceDocument.java
index 47cbf67..5b6ed0d 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/data/ServiceDocument.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/data/ServiceDocument.java
@@ -18,15 +18,13 @@
  */
 package org.apache.olingo.client.api.data;
 
-import org.apache.olingo.client.api.domain.ClientServiceDocument;
-
 import java.net.URI;
 import java.util.List;
 
 /**
  * REST resource for an <tt>ODataServiceDocument</tt>.
  *
- * @see ClientServiceDocument
+ * @see org.apache.olingo.client.api.domain.ClientServiceDocument
  */
 public interface ServiceDocument {
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentImpl.java
index ec10e9d..4bf6a09 100755
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentImpl.java
@@ -22,15 +22,11 @@ import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.olingo.client.api.data.ServiceDocument;
 import org.apache.olingo.client.api.data.ServiceDocumentItem;
 import org.apache.olingo.commons.api.Constants;
 
-public class ServiceDocumentImpl implements ServiceDocument {
+public final class ServiceDocumentImpl implements ServiceDocument {
 
   private String title;
 
@@ -125,17 +121,56 @@ public class ServiceDocumentImpl implements ServiceDocument {
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ServiceDocumentImpl that = (ServiceDocumentImpl) o;
+
+    if (title != null ? !title.equals(that.title) : that.title != null) {
+      return false;
+    }
+    if (entitySets != null ? !entitySets.equals(that.entitySets) : that.entitySets != null) {
+      return false;
+    }
+    if (functionImports != null ? !functionImports.equals(that.functionImports) : that.functionImports != null) {
+      return false;
+    }
+    if (singletons != null ? !singletons.equals(that.singletons) : that.singletons != null) {
+      return false;
+    }
+    if (relatedServiceDocuments != null ?
+        !relatedServiceDocuments.equals(that.relatedServiceDocuments) : that.relatedServiceDocuments != null) {
+      return false;
+    }
+    return !(metadata != null ? !metadata.equals(that.metadata) : that.metadata != null);
+
   }
 
   @Override
   public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+    int result = title != null ? title.hashCode() : 0;
+    result = 31 * result + (entitySets != null ? entitySets.hashCode() : 0);
+    result = 31 * result + (functionImports != null ? functionImports.hashCode() : 0);
+    result = 31 * result + (singletons != null ? singletons.hashCode() : 0);
+    result = 31 * result + (relatedServiceDocuments != null ? relatedServiceDocuments.hashCode() : 0);
+    result = 31 * result + (metadata != null ? metadata.hashCode() : 0);
+    return result;
   }
 
   @Override
   public String toString() {
-    return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+    return "ServiceDocumentImpl{" +
+        "title='" + title + '\'' +
+        ", entitySets=" + entitySets +
+        ", functionImports=" + functionImports +
+        ", singletons=" + singletons +
+        ", relatedServiceDocuments=" + relatedServiceDocuments +
+        ", metadata='" + metadata + '\'' +
+        '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentItemImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentItemImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentItemImpl.java
index 3bcdaa7..fe6b59b 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentItemImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/data/ServiceDocumentItemImpl.java
@@ -18,13 +18,9 @@
  */
 package org.apache.olingo.client.core.data;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.olingo.client.api.data.ServiceDocumentItem;
 
-public class ServiceDocumentItemImpl implements ServiceDocumentItem {
+public final class ServiceDocumentItemImpl implements ServiceDocumentItem {
 
   private String name;
 
@@ -49,17 +45,35 @@ public class ServiceDocumentItemImpl implements ServiceDocumentItem {
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ServiceDocumentItemImpl that = (ServiceDocumentItemImpl) o;
+
+    if (name != null ? !name.equals(that.name) : that.name != null) {
+      return false;
+    }
+    return !(url != null ? !url.equals(that.url) : that.url != null);
+
   }
 
   @Override
   public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+    int result = name != null ? name.hashCode() : 0;
+    result = 31 * result + (url != null ? url.hashCode() : 0);
+    return result;
   }
 
   @Override
   public String toString() {
-    return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+    return "ServiceDocumentItemImpl{" +
+        "name='" + name + '\'' +
+        ", url='" + url + '\'' +
+        '}';
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
index ac1ad1d..eed965f 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
@@ -18,11 +18,6 @@
  */
 package org.apache.olingo.client.core.domain;
 
-import java.util.ArrayList;
-import java.util.List;
-
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.olingo.client.api.domain.ClientAnnotatable;
 import org.apache.olingo.client.api.domain.ClientAnnotation;
 import org.apache.olingo.client.api.domain.ClientCollectionValue;
@@ -33,7 +28,10 @@ import org.apache.olingo.client.api.domain.ClientProperty;
 import org.apache.olingo.client.api.domain.ClientValuable;
 import org.apache.olingo.client.api.domain.ClientValue;
 
-public class ClientPropertyImpl implements ClientProperty, ClientAnnotatable, ClientValuable {
+import java.util.ArrayList;
+import java.util.List;
+
+public final class ClientPropertyImpl implements ClientProperty, ClientAnnotatable, ClientValuable {
 
 
   private final List<ClientAnnotation> annotations = new ArrayList<ClientAnnotation>();
@@ -118,13 +116,36 @@ public class ClientPropertyImpl implements ClientProperty, ClientAnnotatable, Cl
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ClientPropertyImpl that = (ClientPropertyImpl) o;
+
+    if (annotations != null ? !annotations.equals(that.annotations) : that.annotations != null) {
+      return false;
+    }
+    if (name != null ? !name.equals(that.name) : that.name != null) {
+      return false;
+    }
+    if (value != null ? !value.equals(that.value) : that.value != null) {
+      return false;
+    }
+    return !(valuable != null ? !valuable.equals(that.valuable) : that.valuable != null);
+
   }
 
   @Override
   public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+    int result = annotations != null ? annotations.hashCode() : 0;
+    result = 31 * result + (name != null ? name.hashCode() : 0);
+    result = 31 * result + (value != null ? value.hashCode() : 0);
+    result = 31 * result + (valuable != null ? valuable.hashCode() : 0);
+    return result;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientValuableImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientValuableImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientValuableImpl.java
index ecae20d..4a032ce 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientValuableImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientValuableImpl.java
@@ -18,10 +18,6 @@
  */
 package org.apache.olingo.client.core.domain;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
 import org.apache.olingo.client.api.domain.ClientCollectionValue;
 import org.apache.olingo.client.api.domain.ClientComplexValue;
 import org.apache.olingo.client.api.domain.ClientEnumValue;
@@ -29,7 +25,7 @@ import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
 import org.apache.olingo.client.api.domain.ClientValuable;
 import org.apache.olingo.client.api.domain.ClientValue;
 
-public class ClientValuableImpl implements ClientValuable {
+public final class ClientValuableImpl implements ClientValuable {
 
   private final ClientValue value;
 
@@ -94,18 +90,29 @@ public class ClientValuableImpl implements ClientValuable {
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    ClientValuableImpl that = (ClientValuableImpl) o;
+
+    return !(value != null ? !value.equals(that.value) : that.value != null);
+
   }
 
   @Override
   public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+    return value != null ? value.hashCode() : 0;
   }
 
   @Override
   public String toString() {
-    return ReflectionToStringBuilder.toString(this, ToStringStyle.MULTI_LINE_STYLE);
+    return "ClientValuableImpl{" +
+        "value=" + value +
+        '}';
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/FullQualifiedName.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/FullQualifiedName.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/FullQualifiedName.java
index 7b99059..4852294 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/FullQualifiedName.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/FullQualifiedName.java
@@ -20,13 +20,10 @@ package org.apache.olingo.commons.api.edm;
 
 import java.io.Serializable;
 
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
-
 /**
  * A full qualified name of any element in the EDM consists of a name and a namespace.
  */
-public class FullQualifiedName implements Serializable {
+public final class FullQualifiedName implements Serializable {
 
   private static final long serialVersionUID = -4063629050858999076L;
 
@@ -83,13 +80,32 @@ public class FullQualifiedName implements Serializable {
   }
 
   @Override
-  public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    FullQualifiedName that = (FullQualifiedName) o;
+
+    if (namespace != null ? !namespace.equals(that.namespace) : that.namespace != null) {
+      return false;
+    }
+    if (name != null ? !name.equals(that.name) : that.name != null) {
+      return false;
+    }
+    return !(fqn != null ? !fqn.equals(that.fqn) : that.fqn != null);
+
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public int hashCode() {
+    int result = namespace != null ? namespace.hashCode() : 0;
+    result = 31 * result + (name != null ? name.hashCode() : 0);
+    result = 31 * result + (fqn != null ? fqn.hashCode() : 0);
+    return result;
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/1ebbbc36/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/SRID.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/SRID.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/SRID.java
index c22f59a..112dd2f 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/SRID.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/geo/SRID.java
@@ -18,12 +18,10 @@
  */
 package org.apache.olingo.commons.api.edm.geo;
 
-import java.io.Serializable;
-
-import org.apache.commons.lang3.builder.EqualsBuilder;
-import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension;
 
+import java.io.Serializable;
+
 /**
  * A geometry or geography property MAY define a value for the SRID attribute. The value of this attribute identifies
  * which spatial reference system is applied to values of the property on type instances.
@@ -34,7 +32,7 @@ import org.apache.olingo.commons.api.edm.geo.Geospatial.Dimension;
  * Standards Track Work Product Copyright © OASIS Open 2013. All Rights Reserved. 19 November 2013 Page 22 of 83The
  * valid values of the SRID attribute and their meanings are as defined by the European Petroleum Survey Group [EPSG].
  */
-public class SRID implements Serializable {
+public final class SRID implements Serializable {
 
   private static final String VARIABLE = "variable";
 
@@ -75,11 +73,19 @@ public class SRID implements Serializable {
   }
 
   private String getValue() {
-    return value == null
-        ? dimension == Dimension.GEOMETRY
-        ? "0"
-            : "4326"
-        : value.toString();
+    if (value == null) {
+      if (dimension == Dimension.GEOMETRY) {
+        return "0";
+      } else {
+        return "4326";
+      }
+    }
+
+    return value.toString();
+//    return value == null ? dimension == Dimension.GEOMETRY
+//        ? "0"
+//            : "4326"
+//        : value.toString();
   }
 
   private boolean isVariable() {
@@ -91,13 +97,32 @@ public class SRID implements Serializable {
   }
 
   @Override
-  public int hashCode() {
-    return HashCodeBuilder.reflectionHashCode(this);
+  public boolean equals(Object o) {
+    if (this == o) {
+      return true;
+    }
+    if (o == null || getClass() != o.getClass()) {
+      return false;
+    }
+
+    SRID srid = (SRID) o;
+
+    if (dimension != srid.dimension) {
+      return false;
+    }
+    if (value != null ? !value.equals(srid.value) : srid.value != null) {
+      return false;
+    }
+    return !(variable != null ? !variable.equals(srid.variable) : srid.variable != null);
+
   }
 
   @Override
-  public boolean equals(final Object obj) {
-    return EqualsBuilder.reflectionEquals(this, obj);
+  public int hashCode() {
+    int result = dimension != null ? dimension.hashCode() : 0;
+    result = 31 * result + (value != null ? value.hashCode() : 0);
+    result = 31 * result + (variable != null ? variable.hashCode() : 0);
+    return result;
   }
 
   @Override
@@ -106,5 +131,4 @@ public class SRID implements Serializable {
         ? VARIABLE
         : getValue();
   }
-
 }


[02/18] olingo-odata4 git commit: OLINGO-738: Adding upsertEntity feature for the server-extension framework

Posted by ch...@apache.org.
OLINGO-738: Adding upsertEntity feature for the server-extension framework


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

Branch: refs/heads/OLINGO-640
Commit: cb0f7f2d7012d9e0a46024e7e9fe21bc09704c42
Parents: 1ebbbc3
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Thu Jul 23 18:00:50 2015 -0500
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Thu Jul 23 18:00:50 2015 -0500

----------------------------------------------------------------------
 .../apache/olingo/server/core/ServiceHandler.java    | 15 +++++++++++++++
 .../server/core/legacy/ProcessorServiceHandler.java  |  7 +++++++
 .../olingo/server/core/requests/DataRequest.java     |  2 +-
 .../apache/olingo/server/example/TripPinHandler.java | 12 ++++++++++++
 4 files changed, 35 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cb0f7f2d/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
index a7753ec..a223120 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
@@ -102,6 +102,21 @@ public interface ServiceHandler extends Processor {
       EntityResponse response) throws ODataLibraryException, ODataApplicationException;
 
   /**
+   * Update or create the entity object. If based on passed in entity object's key value,  if 
+   * entity exists update the entity, else create a new entity
+   * @param request
+   * @param entity - Entity to create or update
+   * @param merge - in the case of update, true to do merge operation with current entity, 
+   * false the entity needs to be replaced
+   * @param entityETag - previous entity tag if provided by the user. "*" means allow.
+   * @param response
+   * @throws ODataLibraryException
+   * @throws ODataApplicationException
+   */
+  void upsertEntity(DataRequest request, Entity entity, boolean merge, String entityETag,
+      EntityResponse response) throws ODataLibraryException, ODataApplicationException;
+
+  /**
    * Delete the Entity
    * @param request
    * @param entityETag - entity tag to match, if provided by the user. "*" means allow

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cb0f7f2d/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
index acbc8c0..b65f19c 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
@@ -430,4 +430,11 @@ public class ProcessorServiceHandler implements ServiceHandler {
     throw new ODataHandlerException("not implemented",
         ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
   }
+
+  @Override
+  public void upsertEntity(DataRequest request, Entity entity, boolean merge, String entityETag, 
+      EntityResponse response) throws ODataLibraryException, ODataApplicationException {
+    throw new ODataHandlerException("not implemented",
+        ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cb0f7f2d/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 7f2273c..2966d86 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -317,7 +317,7 @@ public class DataRequest extends ServiceRequest {
               getContextURL(odata), false, response, getReturnRepresentation());
           handler.createEntity(DataRequest.this, getEntityFromClient(), entityResponse);
         } else {
-          handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
+          handler.upsertEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
               entityResponse);
         }
       } else if (isPOST()) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/cb0f7f2d/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
index 6ca0fcd..db06558 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
@@ -544,4 +544,16 @@ public class TripPinHandler implements ServiceHandler {
   public void crossJoin(DataRequest dataRequest, List<String> entitySetNames, ODataResponse response) {
     response.setStatusCode(200);
   }
+
+  @Override
+  public void upsertEntity(DataRequest request, Entity entity, boolean merge, String entityETag, 
+      EntityResponse response) throws ODataLibraryException, ODataApplicationException {
+    EdmEntitySet edmEntitySet = request.getEntitySet();
+    Entity currentEntity = this.dataModel.getEntity(edmEntitySet.getName(), request.getKeyPredicates());
+    if(currentEntity == null) {
+      createEntity(request, entity, response);
+    } else {
+      updateEntity(request, entity, merge, entityETag, response);
+    }
+  }
 }


[11/18] olingo-odata4 git commit: [OLINGO-731] Added tests

Posted by ch...@apache.org.
[OLINGO-731] Added tests


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

Branch: refs/heads/OLINGO-640
Commit: 57a11aff6b1658e66424290423a4cadb104661f5
Parents: b146a40
Author: Christian Amend <ch...@sap.com>
Authored: Tue Jul 28 15:35:50 2015 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Jul 28 15:47:23 2015 +0200

----------------------------------------------------------------------
 .../apache/olingo/server/core/ODataHandler.java |  16 +-
 .../core/debug/DebugResponseHelperImpl.java     |  15 +-
 .../olingo/server/core/debug/DebugTabBody.java  |  19 ++-
 .../server/core/debug/DebugTabRequest.java      |  99 +++++++-----
 .../server/core/debug/DebugTabResponse.java     |  20 ++-
 .../server/core/debug/DebugTabServer.java       |  10 +-
 .../server/core/debug/ServerCoreDebugger.java   |   7 +-
 .../serializer/BatchResponseSerializer.java     |   1 -
 .../server/core/debug/AbstractDebugTabTest.java |  58 +++++++
 .../server/core/debug/DebugTabBodyTest.java     |  37 +++++
 .../server/core/debug/DebugTabRequestTest.java  | 155 +++++++++++++++++++
 .../server/core/debug/DebugTabResponseTest.java |  79 ++++++++++
 .../server/core/debug/DebugTabServerTest.java   |  84 ++++++++++
 .../core/debug/ServerCoreDebuggerTest.java      | 121 +++++++++++++++
 14 files changed, 651 insertions(+), 70 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/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 1d1b270..bfbc5ac 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
@@ -74,10 +74,9 @@ public class ODataHandler {
 
   public ODataResponse process(final ODataRequest request) {
     ODataResponse response = new ODataResponse();
+    int measurementHandel = debugger.startRuntimeMeasurement("ODataHandler", "processInternal");
     try {
-
       processInternal(request, response);
-
     } catch (final UriValidationException e) {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e, null);
       handleException(request, response, serverError, e);
@@ -112,6 +111,7 @@ public class ODataHandler {
       ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
       handleException(request, response, serverError, e);
     }
+    debugger.stopRuntimeMeasurement(measurementHandel);
     return response;
   }
 
@@ -119,13 +119,19 @@ public class ODataHandler {
       throws ODataApplicationException, ODataLibraryException {
     validateODataVersion(request, response);
 
+    int measurementUriParser = debugger.startRuntimeMeasurement("UriParser", "parseUri");
     uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(), null,
         serviceMetadata.getEdm());
+    debugger.stopRuntimeMeasurement(measurementUriParser);
 
+    int measurementUriValidator = debugger.startRuntimeMeasurement("UriValidator", "validate");
     final HttpMethod method = request.getMethod();
     new UriValidator().validate(uriInfo, method);
+    debugger.stopRuntimeMeasurement(measurementUriValidator);
 
+    int measurementDispatcher = debugger.startRuntimeMeasurement("Dispatcher", "dispatch");
     new ODataDispatcher(method, uriInfo, this).dispatch(request, response);
+    debugger.stopRuntimeMeasurement(measurementDispatcher);
   }
 
   public void handleException(final ODataRequest request, final ODataResponse response,
@@ -146,7 +152,9 @@ public class ODataHandler {
     } catch (final ContentNegotiatorException e) {
       requestedContentType = ContentType.JSON;
     }
+    int measurementHandle = debugger.startRuntimeMeasurement("ErrorProcessor", "processError");
     exceptionProcessor.processError(request, response, serverError, requestedContentType);
+    debugger.stopRuntimeMeasurement(measurementHandle);
   }
 
   private void validateODataVersion(final ODataRequest request, final ODataResponse response)
@@ -196,8 +204,8 @@ public class ODataHandler {
   public Exception getLastThrownException() {
     return lastThrownException;
   }
-  
-  public UriInfo getUriInfo(){
+
+  public UriInfo getUriInfo() {
     return uriInfo;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/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 d99dd4c..94ab544 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
@@ -76,7 +76,7 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
             + new Date().toString().replace(' ', '_').replace(':', '.') + ".html");
         // Download is the same as html except for the above header
       case HTML:
-        String title = debugInfo.getRequest() == null ? 
+        String title = debugInfo.getRequest() == null ?
             "V4 Service" : "V4 Service: " + debugInfo.getRequest().getRawODataPath();
         body = wrapInHtml(parts, title);
         contentTypeString = ContentType.TEXT_HTML.toContentTypeString();
@@ -164,7 +164,7 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
 
     gen.writeEndObject();
     gen.close();
-    csb.close();
+    csb.closeWrite();
 
     return csb.getInputStream();
   }
@@ -258,14 +258,15 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
         .append("</thead>\n<tbody>\n");
     for (final String name : entries.keySet()) {
       final String value = entries.get(name);
+      writer.append("<tr><td class=\"name\">").append(name).append("</td>")
+      .append("<td class=\"value\">");
       if (value != null) {
-        writer.append("<tr><td class=\"name\">").append(name).append("</td>")
-            .append("<td class=\"value\">")
-            .append(escapeHtml(value))
-            .append("</td></tr>\n");
+        writer.append(escapeHtml(value));
+      }else{
+        writer.append("null");
       }
+      writer.append("</td></tr>\n");
     }
     writer.append("</tbody>\n</table>\n");
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
index 43e9ba6..5608d58 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
@@ -50,11 +50,15 @@ public class DebugTabBody implements DebugTab {
 
   public DebugTabBody(final ODataResponse response, final String serviceRoot) {
     this.response = response;
-    this.serviceRoot = serviceRoot;
-    final String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE);
-    // TODO: Differentiate better
-    if (contentType != null) {
-      responseContent = ResponseContent.JSON;
+    this.serviceRoot = serviceRoot == null ? "/" : serviceRoot;
+    if (response != null) {
+      final String contentType = response.getHeaders().get(HttpHeader.CONTENT_TYPE);
+      // TODO: Differentiate better
+      if (contentType != null) {
+        responseContent = ResponseContent.JSON;
+      } else {
+        responseContent = ResponseContent.TEXT;
+      }
     } else {
       responseContent = ResponseContent.TEXT;
     }
@@ -74,7 +78,7 @@ public class DebugTabBody implements DebugTab {
 //
   @Override
   public void appendJson(final JsonGenerator gen) throws IOException {
-    if (response.getContent() == null) {
+    if (response == null || response.getContent() == null) {
       gen.writeNull();
     } else {
       gen.writeString(getContentString());
@@ -106,7 +110,8 @@ public class DebugTabBody implements DebugTab {
   @Override
   public void appendHtml(final Writer writer) throws IOException {
 
-    final String body = response.getContent() == null ? "ODataLibrary: null body." : getContentString();
+    final String body =
+        response == null || response.getContent() == null ? "ODataLibrary: No body." : getContentString();
     switch (responseContent) {
     case XML:
       writer.append("<pre class=\"code").append("xml").append("\">\n");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
index 8eba537..be38f68 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
@@ -20,7 +20,7 @@ package org.apache.olingo.server.core.debug;
 
 import java.io.IOException;
 import java.io.Writer;
-import java.util.LinkedHashMap;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
@@ -36,33 +36,20 @@ public class DebugTabRequest implements DebugTab {
   private final String method;
   private final String uri;
   private final String protocol;
-  private final Map<String, String> headers;
+  private final Map<String, List<String>> headers;
 
   public DebugTabRequest(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 LinkedHashMap<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;
-        }
-      }
-      localHeaders.put(entry.getKey(), value);
+    if (request != null) {
+      method = request.getMethod() == null ? "unkown" : request.getMethod().toString();
+      uri = request.getRawRequestUri() == null ? "unkown" : request.getRawRequestUri();
+      protocol = request.getProtocol() == null ? "unkown" : request.getProtocol();
+      headers = request.getAllHeaders();
+    } else {
+      method = "unkown";
+      uri = "unkown";
+      protocol = "unkown";
+      headers = Collections.emptyMap();
     }
-    return localHeaders;
   }
 
   @Override
@@ -70,25 +57,26 @@ public class DebugTabRequest implements DebugTab {
     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("<p>").append(DebugResponseHelperImpl.escapeHtml(uri)).append("</p>\n")
         .append("<h2>Request Protocol</h2>\n")
-        .append("<p>").append(protocol).append("</p>\n");
+        .append("<p>").append(DebugResponseHelperImpl.escapeHtml(protocol)).append("</p>\n");
     writer.append("<h2>Request Headers</h2>\n");
-    DebugResponseHelperImpl.appendHtmlTable(writer, headers);
-
-//        .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");
+
+    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 Map.Entry<String, List<String>> entry : headers.entrySet()) {
+      List<String> headersList = entry.getValue();
+      if (headersList != null && !headersList.isEmpty()) {
+        for (String headerValue : headersList) {
+          writer.append("<tr><td class=\"name\">").append(entry.getKey()).append("</td>")
+              .append("<td class=\"value\">")
+              .append(DebugResponseHelperImpl.escapeHtml(headerValue))
+              .append("</td></tr>\n");
+        }
+      }
+    }
+    writer.append("</tbody>\n</table>\n");
   }
 
   @Override
@@ -107,7 +95,32 @@ public class DebugTabRequest implements DebugTab {
 
     if (!headers.isEmpty()) {
       gen.writeFieldName("headers");
-      DebugResponseHelperImpl.appendJsonTable(gen, headers);
+
+      gen.writeStartObject();
+
+      for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
+        List<String> headersList = entry.getValue();
+        if (headersList != null && !headersList.isEmpty()) {
+          if (headersList.size() == 1) {
+            gen.writeStringField(entry.getKey(), headersList.get(0));
+          } else {
+            gen.writeFieldName(entry.getKey());
+            gen.writeStartArray();
+            for (String headerValue : headersList) {
+              if (headerValue != null) {
+                gen.writeString(headerValue);
+              } else {
+                gen.writeNull();
+              }
+            }
+            gen.writeEndArray();
+          }
+        } else {
+          gen.writeNullField(entry.getKey());
+        }
+      }
+
+      gen.writeEndObject();
     }
 
     gen.writeEndObject();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
index 5cb153c..528cf61 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
@@ -20,6 +20,7 @@ package org.apache.olingo.server.core.debug;
 
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Collections;
 import java.util.Map;
 
 import org.apache.olingo.commons.api.http.HttpStatusCode;
@@ -39,9 +40,14 @@ public class DebugTabResponse implements DebugTab {
 
   public DebugTabResponse(final ODataResponse applicationResponse, final String serviceRoot) {
     this.response = applicationResponse;
-    this.serviceRoot = serviceRoot;
-    status = HttpStatusCode.fromStatusCode(response.getStatusCode());
-    headers = response.getHeaders();
+    if (response != null) {
+      status = HttpStatusCode.fromStatusCode(response.getStatusCode());
+      headers = response.getHeaders();
+    } else {
+      status = HttpStatusCode.INTERNAL_SERVER_ERROR;
+      headers = Collections.emptyMap();
+    }
+    this.serviceRoot = serviceRoot == null ? "/" : serviceRoot;
   }
 
   @Override
@@ -67,7 +73,11 @@ public class DebugTabResponse implements DebugTab {
     }
 
     gen.writeFieldName("body");
-    new DebugTabBody(response, serviceRoot).appendJson(gen);
+    if (response != null && response.getContent() != null) {
+      new DebugTabBody(response, serviceRoot).appendJson(gen);
+    } else {
+      gen.writeNull();
+    }
 
     gen.writeEndObject();
   }
@@ -80,7 +90,7 @@ public class DebugTabResponse implements DebugTab {
         .append("<h2>Response Headers</h2>\n");
     DebugResponseHelperImpl.appendHtmlTable(writer, headers);
     writer.append("<h2>Response Body</h2>\n");
-    if (response.getContent() != null) {
+    if (response != null && response.getContent() != null) {
       new DebugTabBody(response, serviceRoot).appendHtml(writer);
     } else {
       writer.append("<p>ODataLibrary: no response body</p>");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
index 4eb95ba..2faae3e 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
@@ -42,7 +42,11 @@ public class DebugTabServer implements DebugTab {
 
   @Override
   public void appendJson(JsonGenerator gen) throws IOException {
-    DebugResponseHelperImpl.appendJsonTable(gen, serverEnvironmentVaribles);
+    if (serverEnvironmentVaribles != null && !serverEnvironmentVaribles.isEmpty()) {
+      DebugResponseHelperImpl.appendJsonTable(gen, serverEnvironmentVaribles);
+    } else {
+      gen.writeNull();
+    }
   }
 
   @Override
@@ -52,6 +56,8 @@ public class DebugTabServer implements DebugTab {
         .append("<p>").append(pack.getImplementationTitle())
         .append(" Version ").append(pack.getImplementationVersion()).append("</p>\n")
         .append("<h2>Server Environment</h2>\n");
-    DebugResponseHelperImpl.appendHtmlTable(writer, serverEnvironmentVaribles);
+    if (serverEnvironmentVaribles != null && !serverEnvironmentVaribles.isEmpty()) {
+      DebugResponseHelperImpl.appendHtmlTable(writer, serverEnvironmentVaribles);
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
index fcf611d..8bdbe39 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
@@ -64,6 +64,11 @@ public class ServerCoreDebugger {
   public ODataResponse createDebugResponse(final HttpServletRequest request, final Exception exception,
       final ODataRequest odRequest, final ODataResponse odResponse, UriInfo uriInfo,
       Map<String, String> serverEnvironmentVaribles) {
+    //Failsafe so we do not generate unauthorized debug messages
+    if(!isDebugMode){
+      return odResponse;
+    }
+    
     try {
       DebugInformation debugInfo =
           createDebugInformation(request, exception, odRequest, odResponse, uriInfo, serverEnvironmentVaribles);
@@ -80,7 +85,7 @@ public class ServerCoreDebugger {
     odResponse.setHeader(HttpHeader.CONTENT_TYPE, ContentType.TEXT_PLAIN.toContentTypeString());
     InputStream content = new ByteArrayInputStream("ODataLibrary: Could not assemble debug response.".getBytes());
     odResponse.setContent(content);
-    return null;
+    return odResponse;
   }
 
   private DebugInformation createDebugInformation(final HttpServletRequest request, final Exception exception,

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java
index 377c5e1..c907b8f 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/BatchResponseSerializer.java
@@ -22,7 +22,6 @@ import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.nio.ByteBuffer;
 import java.nio.channels.Channels;
 import java.nio.channels.ReadableByteChannel;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java
new file mode 100644
index 0000000..43b1aaa
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/AbstractDebugTabTest.java
@@ -0,0 +1,58 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+
+import org.apache.commons.io.IOUtils;
+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 abstract class AbstractDebugTabTest {
+
+  protected String createHtml(DebugTab tab) throws Exception {
+    StringWriter writer = new StringWriter();
+    tab.appendHtml(writer);
+    writer.flush();
+    byte[] bytes = writer.toString().getBytes("UTF-8");
+    return IOUtils.toString(new ByteArrayInputStream(bytes));
+  }
+
+  protected String createJson(DebugTab requestTab) throws IOException {
+    CircleStreamBuffer csb = new CircleStreamBuffer();
+    JsonGenerator gen = new JsonFactory().createGenerator(csb.getOutputStream(), JsonEncoding.UTF8);
+    requestTab.appendJson(gen);
+    gen.flush();
+    gen.close();
+    csb.closeWrite();
+    return IOUtils.toString(csb.getInputStream());
+  }
+  
+  protected void print(DebugTab tab) throws Exception{
+    System.out.println(createJson(tab));
+    System.out.println("---------------------------------------------------------");
+    System.out.println(createHtml(tab));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java
new file mode 100644
index 0000000..7d3a58e
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabBodyTest.java
@@ -0,0 +1,37 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class DebugTabBodyTest extends AbstractDebugTabTest {
+
+  @Test
+  public void nullResponseMustNotLeadToException() throws Exception {
+    DebugTabBody tab = new DebugTabBody(null, null);
+
+    String expectedHtml = "<pre class=\"code\">\n"
+        + "ODataLibrary: No body.</pre>\n";
+
+    assertEquals("null", createJson(tab));
+    assertEquals(expectedHtml, createHtml(tab));
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRequestTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRequestTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRequestTest.java
new file mode 100644
index 0000000..3689301
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabRequestTest.java
@@ -0,0 +1,155 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.server.api.ODataRequest;
+import org.junit.Test;
+
+public class DebugTabRequestTest extends AbstractDebugTabTest {
+
+  @Test
+  public void initialRequestMustNotleadToException() throws Exception {
+    String expectedJson = "{\"method\":\"unkown\",\"uri\":\"unkown\",\"protocol\":\"unkown\"}";
+    String expectedHtml = "<h2>Request Method</h2>\n"
+        + "<p>unkown</p>\n"
+        + "<h2>Request URI</h2>\n"
+        + "<p>unkown</p>\n"
+        + "<h2>Request Protocol</h2>\n"
+        + "<p>unkown</p>\n"
+        + "<h2>Request Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "</tbody>\n"
+        + "</table>\n";
+
+    DebugTabRequest requestTab = new DebugTabRequest(null);
+    assertEquals(expectedJson, createJson(requestTab));
+    assertEquals(expectedHtml, createHtml(requestTab));
+
+    requestTab = new DebugTabRequest(new ODataRequest());
+    assertEquals(expectedJson, createJson(requestTab));
+    assertEquals(expectedHtml, createHtml(requestTab));
+  }
+
+  @Test
+  public void onlyProtocolNotSet() throws Exception {
+    String expectedJson = "{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"unkown\"}";
+    String expectedHtml = "<h2>Request Method</h2>\n"
+        + "<p>GET</p>\n"
+        + "<h2>Request URI</h2>\n"
+        + "<p>def&amp;</p>\n"
+        + "<h2>Request Protocol</h2>\n"
+        + "<p>unkown</p>\n"
+        + "<h2>Request Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "</tbody>\n"
+        + "</table>\n";
+
+    ODataRequest oDataRequest = new ODataRequest();
+    oDataRequest.setMethod(HttpMethod.GET);
+    oDataRequest.setRawRequestUri("def&");
+
+    DebugTabRequest requestTab = new DebugTabRequest(oDataRequest);
+    assertEquals(expectedJson, createJson(requestTab));
+    assertEquals(expectedHtml, createHtml(requestTab));
+  }
+
+  @Test
+  public void singleHeaderValue() throws Exception {
+    String expectedJson =
+        "{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"def&\",\"headers\":{\"HEADERNAME\":\"Value1\"}}";
+    String expectedHtml = "<h2>Request Method</h2>\n"
+        + "<p>GET</p>\n"
+        + "<h2>Request URI</h2>\n"
+        + "<p>def&amp;</p>\n"
+        + "<h2>Request Protocol</h2>\n"
+        + "<p>def&amp;</p>\n"
+        + "<h2>Request Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value1</td></tr>\n"
+        + "</tbody>\n"
+        + "</table>\n";
+
+    ODataRequest oDataRequest = new ODataRequest();
+    oDataRequest.setMethod(HttpMethod.GET);
+    oDataRequest.setRawRequestUri("def&");
+    oDataRequest.setProtocol("def&");
+    List<String> headerValues = new ArrayList<String>();
+    headerValues.add("Value1");
+    oDataRequest.addHeader("HeaderName", headerValues);
+
+    DebugTabRequest requestTab = new DebugTabRequest(oDataRequest);
+    System.out.println(createHtml(requestTab));
+    assertEquals(expectedJson, createJson(requestTab));
+    assertEquals(expectedHtml, createHtml(requestTab));
+  }
+
+  @Test
+  public void multiHeaderValueResultsInMap() throws Exception {
+    String expectedJson = "{\"method\":\"GET\",\"uri\":\"def&\",\"protocol\":\"def&\","
+        + "\"headers\":{\"HEADERNAME\":[\"Value1\",\"Value2\"]}}";
+    String expectedHtml = "<h2>Request Method</h2>\n"
+        + "<p>GET</p>\n"
+        + "<h2>Request URI</h2>\n"
+        + "<p>def&amp;</p>\n"
+        + "<h2>Request Protocol</h2>\n"
+        + "<p>def&amp;</p>\n"
+        + "<h2>Request Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value1</td></tr>\n"
+        + "<tr><td class=\"name\">HEADERNAME</td><td class=\"value\">Value2</td></tr>\n"
+        + "</tbody>\n"
+        + "</table>\n";
+
+    ODataRequest oDataRequest = new ODataRequest();
+    oDataRequest.setMethod(HttpMethod.GET);
+    oDataRequest.setRawRequestUri("def&");
+    oDataRequest.setProtocol("def&");
+    List<String> headerValues = new ArrayList<String>();
+    headerValues.add("Value1");
+    headerValues.add("Value2");
+    oDataRequest.addHeader("HeaderName", headerValues);
+
+    DebugTabRequest requestTab = new DebugTabRequest(oDataRequest);
+    assertEquals(expectedJson, createJson(requestTab));
+    assertEquals(expectedHtml, createHtml(requestTab));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabResponseTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabResponseTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabResponseTest.java
new file mode 100644
index 0000000..af55a40
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabResponseTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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 static org.junit.Assert.assertEquals;
+
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataResponse;
+import org.junit.Test;
+
+public class DebugTabResponseTest extends AbstractDebugTabTest {
+
+  @Test
+  public void nullResponseMustNotLeadToException() throws Exception {
+    DebugTabResponse tab = new DebugTabResponse(null, null);
+
+    String expectedJson = "{\"status\":{\"code\":\"500\",\"info\":\"Internal Server Error\"},\"body\":null}";
+    String expectedHtml = "<h2>Status Code</h2>\n"
+        + "<p>500 Internal Server Error</p>\n"
+        + "<h2>Response Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "</tbody>\n"
+        + "</table>\n"
+        + "<h2>Response Body</h2>\n"
+        + "<p>ODataLibrary: no response body</p>";
+
+    assertEquals(expectedJson, createJson(tab));
+    assertEquals(expectedHtml, createHtml(tab));
+  }
+
+  @Test
+  public void withInformationNoBody() throws Exception {
+    ODataResponse response = new ODataResponse();
+    response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+    response.setHeader("headername", "headervalue");
+    response.setHeader("headername2", "headervalue2");
+    DebugTabResponse tab = new DebugTabResponse(response, null);
+
+    String expectedJson = "{\"status\":{\"code\":\"204\",\"info\":\"No Content\"},"
+        + "\"headers\":{\"headername\":\"headervalue\",\"headername2\":\"headervalue2\"},\"body\":null}";
+    String expectedHtml = "<h2>Status Code</h2>\n"
+        + "<p>204 No Content</p>\n"
+        + "<h2>Response Headers</h2>\n"
+        + "<table>\n"
+        + "<thead>\n"
+        + "<tr><th class=\"name\">Name</th><th class=\"value\">Value</th></tr>\n"
+        + "</thead>\n"
+        + "<tbody>\n"
+        + "<tr><td class=\"name\">headername</td><td class=\"value\">headervalue</td></tr>\n"
+        + "<tr><td class=\"name\">headername2</td><td class=\"value\">headervalue2</td></tr>\n"
+        + "</tbody>\n"
+        + "</table>\n"
+        + "<h2>Response Body</h2>\n"
+        + "<p>ODataLibrary: no response body</p>";
+    assertEquals(expectedJson, createJson(tab));
+    assertEquals(expectedHtml, createHtml(tab));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabServerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabServerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabServerTest.java
new file mode 100644
index 0000000..dc4748d
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/DebugTabServerTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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 static org.junit.Assert.*;
+
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+public class DebugTabServerTest extends AbstractDebugTabTest {
+
+  @Test
+  public void nullServerInformationMustNotleadToException() throws Exception {
+    DebugTabServer serverTab = new DebugTabServer(null);
+
+    assertEquals("null", createJson(serverTab));
+    String html = createHtml(serverTab);
+    assertTrue(html.startsWith("<h2>Library Version</h2>"));
+    assertTrue(html.endsWith("<h2>Server Environment</h2>\n"));
+  }
+
+  @Test
+  public void initialServerInformationMustNotleadToException() throws Exception {
+    Map<String, String> env = Collections.emptyMap();
+    DebugTabServer serverTab = new DebugTabServer(env);
+
+    assertEquals("null", createJson(serverTab));
+    String html = createHtml(serverTab);
+    assertTrue(html.startsWith("<h2>Library Version</h2>"));
+    assertTrue(html.endsWith("<h2>Server Environment</h2>\n"));
+  }
+
+  @Test
+  public void twoParametersNoNull() throws Exception {
+    Map<String, String> env = new LinkedHashMap<String, String>();
+    env.put("key1", "value1");
+    env.put("key2", "value2");
+    DebugTabServer serverTab = new DebugTabServer(env);
+
+    String expectedJson = "{\"key1\":\"value1\",\"key2\":\"value2\"}";
+
+    assertEquals(expectedJson, createJson(serverTab));
+    String html = createHtml(serverTab);
+    assertTrue(html.contains("<tr><td class=\"name\">key1</td><td class=\"value\">value1</td></tr>"));
+    assertTrue(html.contains("<tr><td class=\"name\">key2</td><td class=\"value\">value2</td></tr>"));
+    assertTrue(html.endsWith("</table>\n"));
+  }
+  
+  @Test
+  public void twoParametersWithNull() throws Exception {
+    Map<String, String> env = new LinkedHashMap<String, String>();
+    env.put("key1", null);
+    env.put("key2", null);
+    DebugTabServer serverTab = new DebugTabServer(env);
+
+    String expectedJson = "{\"key1\":null,\"key2\":null}";
+
+    assertEquals(expectedJson, createJson(serverTab));
+    String html = createHtml(serverTab);
+    assertTrue(html.contains("<tr><td class=\"name\">key1</td><td class=\"value\">null</td></tr>"));
+    assertTrue(html.contains("<tr><td class=\"name\">key2</td><td class=\"value\">null</td></tr>"));
+    assertTrue(html.endsWith("</table>\n"));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/57a11aff/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java
new file mode 100644
index 0000000..32ec195
--- /dev/null
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/debug/ServerCoreDebuggerTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.ODataRuntimeException;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.debug.DebugInformation;
+import org.apache.olingo.server.api.debug.DebugSupport;
+import org.junit.Before;
+import org.junit.Test;
+
+public class ServerCoreDebuggerTest {
+
+  private ServerCoreDebugger debugger;
+
+  @Before
+  public void setupDebugger() {
+    debugger = new ServerCoreDebugger(OData.newInstance());
+    debugger.setDebugSupportProcessor(new LocalDebugProcessor());
+  }
+
+  @Test
+  public void standardIsDebugModeIsFlase() {
+    assertFalse(debugger.isDebugMode());
+  }
+
+  @Test
+  public void resolveDebugModeNoDebugSupportProcessor() {
+    HttpServletRequest request = mock(HttpServletRequest.class);
+    when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_JSON);
+
+    ServerCoreDebugger localDebugger = new ServerCoreDebugger(OData.newInstance());
+    localDebugger.resolveDebugMode(request);
+    assertFalse(debugger.isDebugMode());
+  }
+
+  @Test
+  public void resolveDebugModeNullParameter() {
+    HttpServletRequest request = mock(HttpServletRequest.class);
+    when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(null);
+    debugger.resolveDebugMode(request);
+    assertFalse(debugger.isDebugMode());
+  }
+
+  @Test
+  public void resolveDebugModeJsonNotAuthorized() {
+    HttpServletRequest request = mock(HttpServletRequest.class);
+    when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_JSON);
+
+    DebugSupport debugSupportMock = mock(DebugSupport.class);
+    when(debugSupportMock.isUserAuthorized()).thenReturn(false);
+
+    ServerCoreDebugger localDebugger = new ServerCoreDebugger(OData.newInstance());
+    localDebugger.setDebugSupportProcessor(debugSupportMock);
+
+    localDebugger.resolveDebugMode(request);
+    assertFalse(debugger.isDebugMode());
+  }
+
+  @Test
+  public void testFailResponse() throws IOException {
+    HttpServletRequest request = mock(HttpServletRequest.class);
+    when(request.getParameter(DebugSupport.ODATA_DEBUG_QUERY_PARAMETER)).thenReturn(DebugSupport.ODATA_DEBUG_JSON);
+    debugger.resolveDebugMode(request);
+    ODataResponse debugResponse = debugger.createDebugResponse(null, null, null, null, null, null);
+    assertEquals(500, debugResponse.getStatusCode());
+    assertEquals("ODataLibrary: Could not assemble debug response.", IOUtils.toString(debugResponse.getContent()));
+  }
+
+  @Test
+  public void noDebugModeCreateDebugResponseCallMustDoNothing() {
+    ODataResponse odResponse = new ODataResponse();
+    ODataResponse debugResponse = debugger.createDebugResponse(null, null, null, odResponse, null, null);
+
+    assertTrue(odResponse == debugResponse);
+  }
+
+  public class LocalDebugProcessor implements DebugSupport {
+
+    @Override
+    public void init(OData odata) {}
+
+    @Override
+    public boolean isUserAuthorized() {
+      return true;
+    }
+
+    @Override
+    public ODataResponse createDebugResponse(String debugFormat, DebugInformation debugInfo) {
+      throw new ODataRuntimeException("Test");
+    }
+  }
+}


[04/18] olingo-odata4 git commit: [OLINGO-731] Debug interfaces part 2

Posted by ch...@apache.org.
[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/OLINGO-640
Commit: fb65199d288892d281678d068ce37c44da54be04
Parents: 8f763aa
Author: Christian Amend <ch...@sap.com>
Authored: Fri Jul 10 10:50:33 2015 +0200
Committer: Christian Amend <ch...@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>
 


[12/18] olingo-odata4 git commit: [OLINGO-659] Minor code refactoring

Posted by ch...@apache.org.
[OLINGO-659] Minor code refactoring


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

Branch: refs/heads/OLINGO-640
Commit: 305f54dcf27dabca5fdeefe01fb4cc9e7fd67d56
Parents: 57a11af
Author: Michael Bolz <mi...@sap.com>
Authored: Tue Jul 28 20:25:52 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Wed Jul 29 20:40:30 2015 +0200

----------------------------------------------------------------------
 .../json/ODataJsonDeserializer.java             | 275 +++++++++++--------
 .../json/ODataJsonDeserializerEntityTest.java   |  50 ++++
 2 files changed, 203 insertions(+), 122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/305f54dc/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
index 84beb61..9c6798d 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializer.java
@@ -63,7 +63,6 @@ import org.apache.olingo.server.core.deserializer.helper.ExpandTreeBuilderImpl;
 import com.fasterxml.jackson.core.JsonFactory;
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.JsonNode;
@@ -202,9 +201,8 @@ public class ODataJsonDeserializer implements ODataDeserializer {
       throws DeserializerException {
     try {
       ObjectNode tree = parseJsonTree(stream);
-      Map<String, Parameter> parameters = new LinkedHashMap<String, Parameter>();
       if (tree != null) {
-        consumeParameters(edmAction, tree, parameters);
+        Map<String, Parameter> parameters = consumeParameters(edmAction, tree);
 
         final List<String> toRemove = new ArrayList<String>();
         Iterator<Entry<String, JsonNode>> fieldsIterator = tree.fields();
@@ -222,8 +220,9 @@ public class ODataJsonDeserializer implements ODataDeserializer {
         // remove here to avoid iterator issues.
         tree.remove(toRemove);
         assertJsonNodeIsEmpty(tree);
-      }
       return DeserializerResultImpl.with().actionParameters(parameters).build();
+      }
+      return DeserializerResultImpl.with().build();
 
     } catch (final JsonParseException e) {
       throw new DeserializerException("An JsonParseException occurred", e,
@@ -237,58 +236,35 @@ public class ODataJsonDeserializer implements ODataDeserializer {
     }
   }
 
-  private ObjectNode parseJsonTree(final InputStream stream)
-      throws IOException, JsonParseException, JsonProcessingException {
+  private ObjectNode parseJsonTree(final InputStream stream) throws IOException {
     ObjectMapper objectMapper = new ObjectMapper();
     objectMapper.configure(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY, true);
     JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
-    ObjectNode tree = parser.getCodec().readTree(parser);
-    return tree;
+    return parser.getCodec().readTree(parser);
   }
 
-  private void consumeParameters(final EdmAction edmAction, final ObjectNode node,
-      final Map<String, Parameter> parameters)
+  private  Map<String, Parameter> consumeParameters(final EdmAction edmAction, final ObjectNode node)
       throws DeserializerException {
     List<String> parameterNames = edmAction.getParameterNames();
     if (edmAction.isBound()) {
       // The binding parameter must not occur in the payload.
       parameterNames = parameterNames.subList(1, parameterNames.size());
     }
+    Map<String, Parameter> parameters = new LinkedHashMap<String, Parameter>();
     for (final String paramName : parameterNames) {
       final EdmParameter edmParameter = edmAction.getParameter(paramName);
-      Parameter parameter = new Parameter();
-      parameter.setName(paramName);
-      JsonNode jsonNode = node.get(paramName);
 
       switch (edmParameter.getType().getKind()) {
       case PRIMITIVE:
       case DEFINITION:
       case ENUM:
-        if (jsonNode == null || jsonNode.isNull()) {
-          if (!edmParameter.isNullable()) {
-            throw new DeserializerException("Non-nullable parameter not present or null",
-                DeserializerException.MessageKeys.INVALID_NULL_PARAMETER, paramName);
-          }
-          if (edmParameter.isCollection()) {
-            throw new DeserializerException("Collection must not be null for parameter: " + paramName,
-                DeserializerException.MessageKeys.INVALID_NULL_PARAMETER, paramName);
-          }
-          parameter.setValue(ValueType.PRIMITIVE, null);
-          parameters.put(paramName, parameter);
-          node.remove(paramName);
-        } else {
-          Property consumePropertyNode =
-              consumePropertyNode(edmParameter.getName(), edmParameter.getType(), edmParameter.isCollection(),
-                  edmParameter.isNullable(), edmParameter.getMaxLength(), edmParameter.getPrecision(), edmParameter
-                      .getScale(), true, edmParameter.getMapping(), jsonNode);
-          parameter.setValue(consumePropertyNode.getValueType(), consumePropertyNode.getValue());
-          parameters.put(paramName, parameter);
-          node.remove(paramName);
-        }
+        Parameter parameter = createParameter(node.get(paramName), paramName, edmParameter);
+        parameters.put(paramName, parameter);
+        node.remove(paramName);
         break;
       case COMPLEX:
       case ENTITY:
-        throw new DeserializerException("Entity an complex parameters currently not Implemented",
+        throw new DeserializerException("Entity and complex parameters currently not Implemented",
             DeserializerException.MessageKeys.NOT_IMPLEMENTED);
       default:
         throw new DeserializerException("Invalid type kind " + edmParameter.getType().getKind().toString()
@@ -296,6 +272,31 @@ public class ODataJsonDeserializer implements ODataDeserializer {
             paramName);
       }
     }
+    return parameters;
+  }
+
+  private Parameter createParameter(JsonNode node, String paramName, EdmParameter edmParameter) throws
+      DeserializerException {
+    Parameter parameter = new Parameter();
+    parameter.setName(paramName);
+    if (node == null || node.isNull()) {
+      if (!edmParameter.isNullable()) {
+        throw new DeserializerException("Non-nullable parameter not present or null",
+            MessageKeys.INVALID_NULL_PARAMETER, paramName);
+      }
+      if (edmParameter.isCollection()) {
+        throw new DeserializerException("Collection must not be null for parameter: " + paramName,
+            MessageKeys.INVALID_NULL_PARAMETER, paramName);
+      }
+      parameter.setValue(ValueType.PRIMITIVE, null);
+    } else {
+      Property consumePropertyNode =
+          consumePropertyNode(edmParameter.getName(), edmParameter.getType(), edmParameter.isCollection(),
+              edmParameter.isNullable(), edmParameter.getMaxLength(), edmParameter.getPrecision(), edmParameter
+                  .getScale(), true, edmParameter.getMapping(), node);
+      parameter.setValue(consumePropertyNode.getValueType(), consumePropertyNode.getValue());
+    }
+    return parameter;
   }
 
   /**
@@ -342,9 +343,8 @@ public class ODataJsonDeserializer implements ODataDeserializer {
               DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, propertyName);
         }
         Property property = consumePropertyNode(edmProperty.getName(), edmProperty.getType(),
-            edmProperty.isCollection(),
-            edmProperty.isNullable(), edmProperty.getMaxLength(), edmProperty.getPrecision(), edmProperty.getScale(),
-            edmProperty.isUnicode(), edmProperty.getMapping(),
+            edmProperty.isCollection(), edmProperty.isNullable(), edmProperty.getMaxLength(),
+            edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(), edmProperty.getMapping(),
             jsonNode);
         entity.addProperty(property);
         node.remove(propertyName);
@@ -360,41 +360,59 @@ public class ODataJsonDeserializer implements ODataDeserializer {
       JsonNode jsonNode = node.get(navigationPropertyName);
       if (jsonNode != null) {
         EdmNavigationProperty edmNavigationProperty = edmEntityType.getNavigationProperty(navigationPropertyName);
-        boolean isNullable = edmNavigationProperty.isNullable();
-        if ((jsonNode.isNull() && !isNullable) || (jsonNode.isNull() && edmNavigationProperty.isCollection())) {
-          throw new DeserializerException("Property: " + navigationPropertyName + " must not be null.",
-              DeserializerException.MessageKeys.INVALID_NULL_PROPERTY, navigationPropertyName);
-        }
+        checkNotNullOrValidNull(jsonNode, edmNavigationProperty);
 
-        Link link = new Link();
-        link.setTitle(navigationPropertyName);
-        final ExpandTreeBuilder childExpandBuilder = (expandBuilder != null) ?
-            expandBuilder.expand(edmNavigationProperty) : null;
-        if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
-          link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
-          EntityCollection inlineEntitySet = new EntityCollection();
-          inlineEntitySet.getEntities().addAll(consumeEntitySetArray(edmNavigationProperty.getType(), jsonNode,
-              childExpandBuilder));
-          link.setInlineEntitySet(inlineEntitySet);
-        } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || jsonNode.isNull())
-            && !edmNavigationProperty.isCollection()) {
-          link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
-          if (!jsonNode.isNull()) {
-            Entity inlineEntity = consumeEntityNode(edmNavigationProperty.getType(), (ObjectNode) jsonNode,
-                childExpandBuilder);
-            link.setInlineEntity(inlineEntity);
-          }
-        } else {
-          throw new DeserializerException("Invalid value: " + jsonNode.getNodeType()
-              + " for expanded navigation property: " + navigationPropertyName,
-              DeserializerException.MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, navigationPropertyName);
-        }
+        Link link = createLink(expandBuilder, navigationPropertyName, jsonNode, edmNavigationProperty);
         entity.getNavigationLinks().add(link);
         node.remove(navigationPropertyName);
       }
     }
   }
 
+  /**
+   * Check if jsonNode is not null or if null but nullable or collection navigationProperty
+   *
+   * @param jsonNode related json node
+   * @param edmNavigationProperty related navigation property
+   * @throws DeserializerException if jsonNode is not null or if null but nullable or collection navigationProperty
+   */
+  private void checkNotNullOrValidNull(JsonNode jsonNode,
+      EdmNavigationProperty edmNavigationProperty) throws DeserializerException {
+    boolean isNullable = edmNavigationProperty.isNullable();
+    if ((jsonNode.isNull() && !isNullable) || (jsonNode.isNull() && edmNavigationProperty.isCollection())) {
+      throw new DeserializerException("Property: " + edmNavigationProperty.getName() + " must not be null.",
+          MessageKeys.INVALID_NULL_PROPERTY, edmNavigationProperty.getName());
+    }
+  }
+
+  private Link createLink(ExpandTreeBuilder expandBuilder, String navigationPropertyName, JsonNode jsonNode,
+      EdmNavigationProperty edmNavigationProperty) throws DeserializerException {
+    Link link = new Link();
+    link.setTitle(navigationPropertyName);
+    final ExpandTreeBuilder childExpandBuilder = (expandBuilder != null) ?
+        expandBuilder.expand(edmNavigationProperty) : null;
+    if (jsonNode.isArray() && edmNavigationProperty.isCollection()) {
+      link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
+      EntityCollection inlineEntitySet = new EntityCollection();
+      inlineEntitySet.getEntities().addAll(
+          consumeEntitySetArray(edmNavigationProperty.getType(), jsonNode, childExpandBuilder));
+      link.setInlineEntitySet(inlineEntitySet);
+    } else if (!jsonNode.isArray() && (!jsonNode.isValueNode() || jsonNode.isNull())
+        && !edmNavigationProperty.isCollection()) {
+      link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+      if (!jsonNode.isNull()) {
+        Entity inlineEntity = consumeEntityNode(edmNavigationProperty.getType(), (ObjectNode) jsonNode,
+            childExpandBuilder);
+        link.setInlineEntity(inlineEntity);
+      }
+    } else {
+      throw new DeserializerException("Invalid value: " + jsonNode.getNodeType()
+          + " for expanded navigation property: " + navigationPropertyName,
+          MessageKeys.INVALID_VALUE_FOR_NAVIGATION_PROPERTY, navigationPropertyName);
+    }
+    return link;
+  }
+
   private Link consumeBindingLink(final String key, final JsonNode jsonNode, final EdmEntityType edmEntityType)
       throws DeserializerException {
     String[] splitKey = key.split("@");
@@ -450,11 +468,11 @@ public class ODataJsonDeserializer implements ODataDeserializer {
     property.setName(name);
     property.setType(type.getFullQualifiedName().getFullQualifiedNameAsString());
     if (isCollection) {
-      consumePropertyCollectionNode(name, type, isNullable, maxLength, precision, scale, isUnicode, mapping,
-          jsonNode, property);
+      consumePropertyCollectionNode(name, type, isNullable, maxLength, precision, scale, isUnicode, mapping, jsonNode,
+          property);
     } else {
-      consumePropertySingleNode(name, type, isNullable, maxLength, precision, scale, isUnicode, mapping,
-          jsonNode, property);
+      consumePropertySingleNode(name, type, isNullable, maxLength, precision, scale, isUnicode, mapping, jsonNode,
+          property);
     }
     return property;
   }
@@ -695,7 +713,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
 
   /**
    * This method either returns the primitive types default class or the manually mapped class if present.
-   * @param edmMapping
+   * @param mapping
    * @param edmPrimitiveType
    * @return the java class to be used during deserialization
    */
@@ -736,7 +754,8 @@ public class ODataJsonDeserializer implements ODataDeserializer {
 
   private void checkJsonTypeBasedOnPrimitiveType(final String propertyName, final String edmPrimitiveTypeName,
       final JsonNode jsonNode)
-      throws DeserializerException {
+        throws DeserializerException {
+
     EdmPrimitiveTypeKind primKind;
     try {
       primKind = EdmPrimitiveTypeKind.valueOf(edmPrimitiveTypeName);
@@ -744,60 +763,72 @@ public class ODataJsonDeserializer implements ODataDeserializer {
       throw new DeserializerException("Unknown Primitive Type: " + edmPrimitiveTypeName, e,
           DeserializerException.MessageKeys.UNKNOWN_PRIMITIVE_TYPE, edmPrimitiveTypeName, propertyName);
     }
-    switch (primKind) {
-    // Booleans
-    case Boolean:
-      if (!jsonNode.isBoolean()) {
-        throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
-            + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName);
+
+    boolean valid = matchTextualCase(jsonNode, primKind);
+    valid |= matchNumberCase(jsonNode, primKind);
+    valid |= matchBooleanCase(jsonNode, primKind);
+    valid |= matchIEEENumberCase(jsonNode, primKind);
+
+    if(!valid) {
+      throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
+          + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName);
+    }
+  }
+
+  private boolean matchIEEENumberCase(JsonNode node, EdmPrimitiveTypeKind primKind) {
+      switch (primKind) {
+      case Int64:
+      case Decimal:
+        // Numbers (either numbers or string)
+        if (isIEEE754Compatible) {
+          return node.isTextual();
+        } else {
+          return node.isNumber();
+        }
       }
-      break;
-    // Numbers (must be numbers)
-    case Int16:
-    case Int32:
-    case Byte:
-    case SByte:
-    case Single:
-    case Double:
-      if (!jsonNode.isNumber()) {
-        throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
-            + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName);
+    return false;
+  }
+
+  private boolean matchBooleanCase(JsonNode node, EdmPrimitiveTypeKind primKind) {
+    if(node.isBoolean()) {
+      switch (primKind) {
+      case Boolean:
+        return true;
       }
-      break;
-    case Int64:
-    case Decimal:
-      // Numbers (eighter numers or string)
-      if (isIEEE754Compatible) {
-        if (!jsonNode.isTextual()) {
-          throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
-              + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY,
-              propertyName);
-        }
-      } else {
-        if (!jsonNode.isNumber()) {
-          throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
-              + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY,
-              propertyName);
-        }
+    }
+    return false;
+  }
+
+  private boolean matchNumberCase(JsonNode node, EdmPrimitiveTypeKind primKind) {
+    if(node.isNumber()) {
+      switch (primKind) {
+      // Numbers (must be numbers)
+      case Int16:
+      case Int32:
+      case Byte:
+      case SByte:
+      case Single:
+      case Double:
+        return true;
       }
-      break;
-    // Strings
-    case String:
-    case Binary:
-    case Date:
-    case DateTimeOffset:
-    case Duration:
-    case Guid:
-    case TimeOfDay:
-      if (!jsonNode.isTextual()) {
-        throw new DeserializerException("Invalid json type: " + jsonNode.getNodeType() + " for edm " + primKind
-            + " property: " + propertyName, DeserializerException.MessageKeys.INVALID_VALUE_FOR_PROPERTY, propertyName);
+    }
+    return false;
+  }
+
+  private boolean matchTextualCase(JsonNode node, EdmPrimitiveTypeKind primKind) {
+    if(node.isTextual()) {
+      switch (primKind) {
+      case String:
+      case Binary:
+      case Date:
+      case DateTimeOffset:
+      case Duration:
+      case Guid:
+      case TimeOfDay:
+        return true;
       }
-      break;
-    default:
-      throw new DeserializerException("Unsupported Edm Primitive Type: " + primKind,
-          DeserializerException.MessageKeys.NOT_IMPLEMENTED);
     }
+    return false;
   }
 
   @Override
@@ -809,7 +840,7 @@ public class ODataJsonDeserializer implements ODataDeserializer {
       JsonParser parser = new JsonFactory(objectMapper).createParser(stream);
       final ObjectNode tree = parser.getCodec().readTree(parser);
 
-      Property property = null;
+      final Property property;
       JsonNode jsonNode = tree.get(Constants.VALUE);
       if (jsonNode != null) {
         property = consumePropertyNode(edmProperty.getName(), edmProperty.getType(),

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/305f54dc/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
index 4a03b03..5388b40 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/deserializer/json/ODataJsonDeserializerEntityTest.java
@@ -1520,6 +1520,56 @@ public class ODataJsonDeserializerEntityTest extends AbstractODataDeserializerTe
     deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity();
   }
 
+  @Test(expected = DeserializerException.class)
+  public void ieee754CompatibleAsNumber() throws Exception {
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON_IEEE754Compatible);
+    String entityString =
+        "{\"PropertyInt16\":32767," +
+            "\"PropertyString\":\"First Resource - positive values\"," +
+            "\"PropertyBoolean\":null," +
+            "\"PropertyByte\":255," +
+            "\"PropertySByte\":127," +
+            "\"PropertyInt32\":2147483647," +
+            "\"PropertyInt64\":123," +
+            "\"PropertySingle\":1.79E20," +
+            "\"PropertyDouble\":-1.79E19," +
+            "\"PropertyDecimal\":\"null\"," +
+            "\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
+            "\"PropertyDate\":null," +
+            "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," +
+            "\"PropertyDuration\":\"PT6S\"," +
+            "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
+            "\"PropertyTimeOfDay\":\"03:26:05\"}";
+
+    final InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity();
+  }
+
+  @Test(expected = DeserializerException.class)
+  public void ieee754NotCompatibleAsString() throws Exception {
+    ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON);
+    String entityString =
+        "{\"PropertyInt16\":32767," +
+            "\"PropertyString\":\"First Resource - positive values\"," +
+            "\"PropertyBoolean\":null," +
+            "\"PropertyByte\":255," +
+            "\"PropertySByte\":127," +
+            "\"PropertyInt32\":2147483647," +
+            "\"PropertyInt64\":\"123\"," +
+            "\"PropertySingle\":1.79E20," +
+            "\"PropertyDouble\":-1.79E19," +
+            "\"PropertyDecimal\":\"null\"," +
+            "\"PropertyBinary\":\"ASNFZ4mrze8=\"," +
+            "\"PropertyDate\":null," +
+            "\"PropertyDateTimeOffset\":\"2012-12-03T07:16:23Z\"," +
+            "\"PropertyDuration\":\"PT6S\"," +
+            "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\"," +
+            "\"PropertyTimeOfDay\":\"03:26:05\"}";
+
+    final InputStream stream = new ByteArrayInputStream(entityString.getBytes());
+    deserializer.entity(stream, edm.getEntityType(new FullQualifiedName("Namespace1_Alias", "ETAllPrim"))).getEntity();
+  }
+
   private void checkPropertyJsonType(final String entityString) throws DeserializerException {
     InputStream stream = new ByteArrayInputStream(entityString.getBytes());
     ODataDeserializer deserializer = OData.newInstance().createDeserializer(CONTENT_TYPE_JSON);


[08/18] olingo-odata4 git commit: [OLINGO-713] Added tutorial project for system query options - expand/select

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
deleted file mode 100755
index c21d352..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.util;
-
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.EntityCollection;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
-import org.apache.olingo.commons.api.edm.EdmProperty;
-import org.apache.olingo.commons.api.edm.EdmType;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.uri.UriInfoResource;
-import org.apache.olingo.server.api.uri.UriParameter;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-
-public class Util {
-  
-  public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
-                                  List<UriParameter> keyParams) throws ODataApplicationException {
-
-    List<Entity> entityList = entitySet.getEntities();
-
-    // loop over all entities in order to find that one that matches all keys in request
-    // e.g. contacts(ContactID=1, CompanyID=1)
-    for (Entity entity: entityList) {
-      boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
-      if (foundEntity) {
-        return entity;
-      }
-    }
-
-    return null;
-  }
-
-  public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity entity, List<UriParameter> keyParams)
-          throws ODataApplicationException {
-
-    // loop over all keys
-    for (final UriParameter key : keyParams) {
-      // key
-      String keyName = key.getName();
-      String keyText = key.getText();
-
-      // Edm: we need this info for the comparison below
-      EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName);
-      Boolean isNullable = edmKeyProperty.isNullable();
-      Integer maxLength = edmKeyProperty.getMaxLength();
-      Integer precision = edmKeyProperty.getPrecision();
-      Boolean isUnicode = edmKeyProperty.isUnicode();
-      Integer scale = edmKeyProperty.getScale();
-      // get the EdmType in order to compare
-      EdmType edmType = edmKeyProperty.getType();
-      EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
-
-      // Runtime data: the value of the current entity
-      // don't need to check for null, this is done in olingo library
-      Object valueObject = entity.getProperty(keyName).getValue();
-
-      // now need to compare the valueObject with the keyText String
-      // this is done using the type.valueToString
-      String valueAsString;
-      try {
-        valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode);
-      } catch (EdmPrimitiveTypeException e) {
-        throw new ODataApplicationException("Failed to retrieve String value", HttpStatusCode.INTERNAL_SERVER_ERROR
-                .getStatusCode(), Locale.ENGLISH, e);
-      }
-
-      if (valueAsString == null) {
-        return false;
-      }
-
-      boolean matches = valueAsString.equals(keyText);
-      if (!matches) {
-        // if any of the key properties is not found in the entity, we don't need to search further
-        return false;
-      }
-    }
-
-    return true;
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
deleted file mode 100755
index fe5cdbb..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.web;
-
-import java.io.IOException;
-import java.lang.Override;import java.lang.RuntimeException;import java.util.ArrayList;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-import myservice.mynamespace.data.Storage;
-import myservice.mynamespace.service.DemoEdmProvider;
-import myservice.mynamespace.service.DemoEntityCollectionProcessor;
-import myservice.mynamespace.service.DemoEntityProcessor;
-import myservice.mynamespace.service.DemoPrimitiveProcessor;
-
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataHttpHandler;
-import org.apache.olingo.server.api.ServiceMetadata;
-import org.apache.olingo.server.api.edmx.EdmxReference;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DemoServlet extends HttpServlet {
-
-  private static final long serialVersionUID = 1L;
-  private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
-
-
-  @Override
-  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-    try {
-      HttpSession session = req.getSession(true);
-      Storage storage = (Storage) session.getAttribute(Storage.class.getName());
-      if (storage == null) {
-        storage = new Storage();
-        session.setAttribute(Storage.class.getName(), storage);
-      }
-
-      // create odata handler and configure it with EdmProvider and Processor
-      OData odata = OData.newInstance();
-      ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
-      ODataHttpHandler handler = odata.createHandler(edm);
-      handler.register(new DemoEntityCollectionProcessor(storage));
-      handler.register(new DemoEntityProcessor(storage));
-      handler.register(new DemoPrimitiveProcessor(storage));
-
-      // let the handler do the work
-      handler.process(req, resp);
-    } catch (RuntimeException e) {
-      LOG.error("Server Error occurred in ExampleServlet", e);
-      throw new ServletException(e);
-    }
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml b/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
deleted file mode 100755
index 21de52a..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  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.
--->
-<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
-    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
-				 id="WebApp_ID" version="2.5">
-
-	<!-- Register the HttpServlet implementation -->
-	<servlet>
-	  <servlet-name>DemoServlet</servlet-name>
-	  <servlet-class>myservice.mynamespace.web.DemoServlet</servlet-class>
-	  <load-on-startup>1</load-on-startup>
-	</servlet>
-	
-	<!-- 
-		Our OData service can be invoked at 
-		http://localhost:8080/DemoService/DemoService.svc
-	-->
-	<servlet-mapping>
-	  <servlet-name>DemoServlet</servlet-name>
-	  <url-pattern>/DemoService.svc/*</url-pattern>
-	</servlet-mapping>
-</web-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp b/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
deleted file mode 100755
index 7ffb4ba..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-
-Licensed to the Apache Software Foundation (ASF) under one
-or more contributor license agreements.  See the NOTICE file
-distributed with this work for additional information
-regarding copyright ownership.  The ASF licenses this file
-to you under the Apache License, Version 2.0 (the
-"License"); you may not use this file except in compliance
-with the License.  You may obtain a copy of the License at
-
-http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing,
-software distributed under the License is distributed on an
-"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-KIND, either express or implied.  See the License for the
-specific language governing permissions and limitations
-under the License.
-
--->
-<html>
-<body>
-<h2>Hello World!</h2>
-<a href="DemoService.svc/">OData Olingo V4 Demo Service</a>
-</body>
-</html>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/pom.xml b/samples/tutorials/p6_queryoptions-es/pom.xml
new file mode 100755
index 0000000..bb095ad
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/pom.xml
@@ -0,0 +1,80 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>my.group.id</groupId>
+  <artifactId>DemoService-QueryOptions-ES</artifactId>
+  <packaging>war</packaging>
+  <version>0.0.1</version>
+
+	<name>${project.artifactId}-Webapp</name>
+
+	<build>
+		<finalName>DemoService</finalName>
+	</build>
+  
+	<properties>
+		<javax.version>2.5</javax.version>
+		<odata.version>4.0.0-beta-03</odata.version>
+		<slf4j.version>1.7.7</slf4j.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>${javax.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-core</artifactId>
+			<version>${odata.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-core</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>${slf4j.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/data/Storage.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/data/Storage.java
new file mode 100755
index 0000000..2034fe6
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/data/Storage.java
@@ -0,0 +1,252 @@
+/*
+ * 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 myservice.mynamespace.data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.util.Util;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.server.api.uri.UriParameter;
+
+public class Storage {
+
+  // represent our database
+  private List<Entity> productList;
+  private List<Entity> categoryList;
+
+  public Storage() {
+
+    productList = new ArrayList<Entity>();
+    categoryList = new ArrayList<Entity>();
+
+    // creating some sample data
+    initProductSampleData();
+    initCategorySampleData();
+  }
+
+  /* PUBLIC FACADE */
+
+  public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet) {
+    EntityCollection entitySet = null;
+
+    if (edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)) {
+      entitySet = getProducts();
+    } else if (edmEntitySet.getName().equals(DemoEdmProvider.ES_CATEGORIES_NAME)) {
+      entitySet = getCategories();
+    }
+
+    return entitySet;
+  }
+
+  public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams) {
+    Entity entity = null;
+
+    EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+
+    if (edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)) {
+      entity = getProduct(edmEntityType, keyParams);
+    } else if (edmEntityType.getName().equals(DemoEdmProvider.ET_CATEGORY_NAME)) {
+      entity = getCategory(edmEntityType, keyParams);
+    }
+
+    return entity;
+  }
+
+  // Navigation
+
+  public Entity getRelatedEntity(Entity entity, EdmEntityType relatedEntityType) {
+    EntityCollection collection = getRelatedEntityCollection(entity, relatedEntityType);
+    if (collection.getEntities().isEmpty()) {
+      return null;
+    }
+    return collection.getEntities().get(0);
+  }
+
+  public Entity getRelatedEntity(Entity entity, EdmEntityType relatedEntityType, List<UriParameter> keyPredicates) {
+
+    EntityCollection relatedEntities = getRelatedEntityCollection(entity, relatedEntityType);
+    return Util.findEntity(relatedEntityType, relatedEntities, keyPredicates);
+  }
+
+  public EntityCollection getRelatedEntityCollection(Entity sourceEntity, EdmEntityType targetEntityType) {
+    EntityCollection navigationTargetEntityCollection = new EntityCollection();
+
+    FullQualifiedName relatedEntityFqn = targetEntityType.getFullQualifiedName();
+    String sourceEntityFqn = sourceEntity.getType();
+
+    if (sourceEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString())
+        && relatedEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN)) {
+      // relation Products->Category (result all categories)
+      int productID = (Integer) sourceEntity.getProperty("ID").getValue();
+      if (productID == 1 || productID == 2) {
+        navigationTargetEntityCollection.getEntities().add(categoryList.get(0));
+      } else if (productID == 3 || productID == 4) {
+        navigationTargetEntityCollection.getEntities().add(categoryList.get(1));
+      } else if (productID == 5 || productID == 6) {
+        navigationTargetEntityCollection.getEntities().add(categoryList.get(2));
+      }
+    } else if (sourceEntityFqn.equals(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString())
+        && relatedEntityFqn.equals(DemoEdmProvider.ET_PRODUCT_FQN)) {
+      // relation Category->Products (result all products)
+      int categoryID = (Integer) sourceEntity.getProperty("ID").getValue();
+      if (categoryID == 1) {
+        // the first 2 products are notebooks
+        navigationTargetEntityCollection.getEntities().addAll(productList.subList(0, 2));
+      } else if (categoryID == 2) {
+        // the next 2 products are organizers
+        navigationTargetEntityCollection.getEntities().addAll(productList.subList(2, 4));
+      } else if (categoryID == 3) {
+        // the first 2 products are monitors
+        navigationTargetEntityCollection.getEntities().addAll(productList.subList(4, 6));
+      }
+    }
+
+    if (navigationTargetEntityCollection.getEntities().isEmpty()) {
+      return null;
+    }
+
+    return navigationTargetEntityCollection;
+  }
+
+  /* INTERNAL */
+
+  private EntityCollection getProducts() {
+    EntityCollection retEntitySet = new EntityCollection();
+
+    for (Entity productEntity : this.productList) {
+      retEntitySet.getEntities().add(productEntity);
+    }
+
+    return retEntitySet;
+  }
+
+  private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams) {
+
+    // the list of entities at runtime
+    EntityCollection entityCollection = getProducts();
+
+    /* generic approach to find the requested entity */
+    return Util.findEntity(edmEntityType, entityCollection, keyParams);
+  }
+
+  private EntityCollection getCategories() {
+    EntityCollection entitySet = new EntityCollection();
+
+    for (Entity categoryEntity : this.categoryList) {
+      entitySet.getEntities().add(categoryEntity);
+    }
+
+    return entitySet;
+  }
+
+  private Entity getCategory(EdmEntityType edmEntityType, List<UriParameter> keyParams) {
+
+    // the list of entities at runtime
+    EntityCollection entitySet = getCategories();
+
+    /* generic approach to find the requested entity */
+    return Util.findEntity(edmEntityType, entitySet, keyParams);
+  }
+
+  /* HELPER */
+
+  private void initProductSampleData() {
+
+    Entity entity = new Entity();
+
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Professional 17"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "Notebook Professional, 2.8GHz - 15 XGA - 8GB DDR3 RAM - 500GB"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 4));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Comfort Easy"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "32 GB Digital Assitant with high-resolution color screen"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 5));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 6));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Flat Basic"));
+    entity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+        "Optimum Hi-Resolution max. 1600 x 1200 @ 85Hz, Dot Pitch: 0.24mm"));
+    entity.setType(DemoEdmProvider.ET_PRODUCT_FQN.getFullQualifiedNameAsString());
+    productList.add(entity);
+  }
+
+  private void initCategorySampleData() {
+
+    Entity entity = new Entity();
+
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebooks"));
+    entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
+    categoryList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Organizers"));
+    entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
+    categoryList.add(entity);
+
+    entity = new Entity();
+    entity.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3));
+    entity.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Monitors"));
+    entity.setType(DemoEdmProvider.ET_CATEGORY_FQN.getFullQualifiedNameAsString());
+    categoryList.add(entity);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
new file mode 100755
index 0000000..7b1fef8
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
@@ -0,0 +1,211 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.olingo.commons.api.ODataException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlNavigationProperty;
+import org.apache.olingo.commons.api.edm.provider.CsdlNavigationPropertyBinding;
+import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
+import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
+import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
+
+public class DemoEdmProvider extends CsdlAbstractEdmProvider {
+
+  // Service Namespace
+  public static final String NAMESPACE = "OData.Demo";
+
+  // EDM Container
+  public static final String CONTAINER_NAME = "Container";
+  public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
+
+  // Entity Types Names
+  public static final String ET_PRODUCT_NAME = "Product";
+  public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);
+
+  public static final String ET_CATEGORY_NAME = "Category";
+  public static final FullQualifiedName ET_CATEGORY_FQN = new FullQualifiedName(NAMESPACE, ET_CATEGORY_NAME);
+
+  // Entity Set Names
+  public static final String ES_PRODUCTS_NAME = "Products";
+  public static final String ES_CATEGORIES_NAME = "Categories";
+
+  @Override
+  public CsdlEntityType getEntityType(FullQualifiedName entityTypeName) throws ODataException {
+
+    // this method is called for each EntityType that are configured in the Schema
+    CsdlEntityType entityType = null;
+
+    if (entityTypeName.equals(ET_PRODUCT_FQN)) {
+      // create EntityType properties
+      CsdlProperty id = new CsdlProperty().setName("ID")
+          .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
+      CsdlProperty name = new CsdlProperty().setName("Name")
+          .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
+      CsdlProperty description = new CsdlProperty().setName("Description")
+          .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
+
+      // create PropertyRef for Key element
+      CsdlPropertyRef propertyRef = new CsdlPropertyRef();
+      propertyRef.setName("ID");
+
+      // navigation property: many-to-one, null not allowed (product must have a category)
+      CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Category")
+          .setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products");
+      List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
+      navPropList.add(navProp);
+
+      // configure EntityType
+      entityType = new CsdlEntityType();
+      entityType.setName(ET_PRODUCT_NAME);
+      entityType.setProperties(Arrays.asList(id, name, description));
+      entityType.setKey(Arrays.asList(propertyRef));
+      entityType.setNavigationProperties(navPropList);
+
+    } else if (entityTypeName.equals(ET_CATEGORY_FQN)) {
+      // create EntityType properties
+      CsdlProperty id = new CsdlProperty().setName("ID")
+          .setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
+      CsdlProperty name = new CsdlProperty().setName("Name")
+          .setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
+
+      // create PropertyRef for Key element
+      CsdlPropertyRef propertyRef = new CsdlPropertyRef();
+      propertyRef.setName("ID");
+
+      // navigation property: one-to-many
+      CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Products")
+          .setType(ET_PRODUCT_FQN).setCollection(true).setPartner("Category");
+      List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
+      navPropList.add(navProp);
+
+      // configure EntityType
+      entityType = new CsdlEntityType();
+      entityType.setName(ET_CATEGORY_NAME);
+      entityType.setProperties(Arrays.asList(id, name));
+      entityType.setKey(Arrays.asList(propertyRef));
+      entityType.setNavigationProperties(navPropList);
+    }
+
+    return entityType;
+
+  }
+
+  @Override
+  public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer, String entitySetName) throws ODataException {
+
+    CsdlEntitySet entitySet = null;
+
+    if (entityContainer.equals(CONTAINER)) {
+
+      if (entitySetName.equals(ES_PRODUCTS_NAME)) {
+
+        entitySet = new CsdlEntitySet();
+        entitySet.setName(ES_PRODUCTS_NAME);
+        entitySet.setType(ET_PRODUCT_FQN);
+
+        // navigation
+        CsdlNavigationPropertyBinding navPropBinding = new CsdlNavigationPropertyBinding();
+        navPropBinding.setTarget("Categories"); // the target entity set, where the navigation property points to
+        navPropBinding.setPath("Category"); // the path from entity type to navigation property
+        List<CsdlNavigationPropertyBinding> navPropBindingList = new ArrayList<CsdlNavigationPropertyBinding>();
+        navPropBindingList.add(navPropBinding);
+        entitySet.setNavigationPropertyBindings(navPropBindingList);
+
+      } else if (entitySetName.equals(ES_CATEGORIES_NAME)) {
+
+        entitySet = new CsdlEntitySet();
+        entitySet.setName(ES_CATEGORIES_NAME);
+        entitySet.setType(ET_CATEGORY_FQN);
+
+        // navigation
+        CsdlNavigationPropertyBinding navPropBinding = new CsdlNavigationPropertyBinding();
+        navPropBinding.setTarget("Products"); // the target entity set, where the navigation property points to
+        navPropBinding.setPath("Products"); // the path from entity type to navigation property
+        List<CsdlNavigationPropertyBinding> navPropBindingList = new ArrayList<CsdlNavigationPropertyBinding>();
+        navPropBindingList.add(navPropBinding);
+        entitySet.setNavigationPropertyBindings(navPropBindingList);
+      }
+    }
+
+    return entitySet;
+  }
+
+  @Override
+  public CsdlEntityContainerInfo getEntityContainerInfo(FullQualifiedName entityContainerName) throws ODataException {
+
+    // This method is invoked when displaying the service document at
+    // e.g. http://localhost:8080/DemoService/DemoService.svc
+    if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
+      CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
+      entityContainerInfo.setContainerName(CONTAINER);
+      return entityContainerInfo;
+    }
+
+    return null;
+  }
+
+  @Override
+  public List<CsdlSchema> getSchemas() throws ODataException {
+    // create Schema
+    CsdlSchema schema = new CsdlSchema();
+    schema.setNamespace(NAMESPACE);
+
+    // add EntityTypes
+    List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
+    entityTypes.add(getEntityType(ET_PRODUCT_FQN));
+    entityTypes.add(getEntityType(ET_CATEGORY_FQN));
+    schema.setEntityTypes(entityTypes);
+
+    // add EntityContainer
+    schema.setEntityContainer(getEntityContainer());
+
+    // finally
+    List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
+    schemas.add(schema);
+
+    return schemas;
+  }
+
+  @Override
+  public CsdlEntityContainer getEntityContainer() throws ODataException {
+
+    // create EntitySets
+    List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
+    entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
+    entitySets.add(getEntitySet(CONTAINER, ES_CATEGORIES_NAME));
+
+    // create EntityContainer
+    CsdlEntityContainer entityContainer = new CsdlEntityContainer();
+    entityContainer.setName(CONTAINER_NAME);
+    entityContainer.setEntitySets(entitySets);
+
+    return entityContainer;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
new file mode 100755
index 0000000..60f8cd2
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
@@ -0,0 +1,160 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.util.List;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+
+public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
+
+  private OData odata;
+  private ServiceMetadata srvMetadata;
+  // our database-mock
+  private Storage storage;
+
+  public DemoEntityCollectionProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.srvMetadata = serviceMetadata;
+  }
+
+  /*
+   * This method is invoked when a collection of entities has to be read. In
+   * our example, this can be either a "normal" read operation, or a
+   * navigation:
+   * 
+   * Example for "normal" read entity set operation:
+   * http://localhost:8080/DemoService/DemoService.svc/Categories
+   * 
+   * Example for navigation
+   * http://localhost:8080/DemoService/DemoService.svc/Categories(3)/Products
+   */
+  public void readEntityCollection(ODataRequest request,
+      ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
+      throws ODataApplicationException, SerializerException {
+
+    // 1st retrieve the requested EdmEntitySet from the uriInfo
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    // in our example, the first segment is the EntitySet
+    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+    // 2nd: fetch the data from backend for this requested EntitySetName
+    EntityCollection entityCollection = storage.readEntitySetData(edmEntitySet);
+
+    // 3rd: apply system query options
+    SelectOption selectOption = uriInfo.getSelectOption();
+    ExpandOption expandOption = uriInfo.getExpandOption();
+
+    // handle $expand
+    // in our example: http://localhost:8080/DemoService/DemoService.svc/Categories/$expand=Products
+    // or http://localhost:8080/DemoService/DemoService.svc/Products?$expand=Category
+    if (expandOption != null) {
+
+      // retrieve the EdmNavigationProperty from the expand expression
+      // Note: in our example, we have only one NavigationProperty, so we can directly access it
+      ExpandItem expandItem = expandOption.getExpandItems().get(0);
+      // can be 'Category' or 'Products'
+      UriResource uriResource = expandItem.getResourcePath().getUriResourceParts().get(0);
+      // we don't need to handle error cases, as it is done in the Olingo library
+      if (uriResource instanceof UriResourceNavigation) {
+        EdmNavigationProperty edmNavigationProperty = ((UriResourceNavigation) uriResource).getProperty();
+        String navPropName = edmNavigationProperty.getName();
+        EdmEntityType expandEdmEntityType = edmNavigationProperty.getType();
+
+        List<Entity> entityList = entityCollection.getEntities();
+        for (Entity entity : entityList) {
+          Link link = new Link();
+          link.setTitle(navPropName);
+          link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);
+
+          if (edmNavigationProperty.isCollection()) { // in case of Categories/$expand=Products
+            // fetch the data for the $expand (to-many navigation) from backend
+            EntityCollection expandEntityCollection = storage.getRelatedEntityCollection(entity, expandEdmEntityType);
+            link.setInlineEntitySet(expandEntityCollection);
+          } else { // in case of Products?$expand=Category
+            // fetch the data for the $expand (to-one navigation) from backend
+            // here we get the data for the expand
+            Entity expandEntity = storage.getRelatedEntity(entity, expandEdmEntityType);
+            link.setInlineEntity(expandEntity);
+          }
+
+          // set the link - containing the expanded data - to the current entity
+          entity.getNavigationLinks().add(link);
+        }
+      }
+    }
+
+    // 4th: serialize
+    EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+    // we need the property names of the $select, in order to build the context URL
+    String selectList = odata.createUriHelper().buildContextURLSelectList(edmEntityType, expandOption, selectOption);
+    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).selectList(selectList).build();
+
+    // adding the selectOption to the serializerOpts will actually tell the lib to do the job
+    EntityCollectionSerializerOptions opts = EntityCollectionSerializerOptions.with()
+        .contextURL(contextUrl)
+        .select(selectOption)
+        .expand(expandOption)
+        .build();
+
+    ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(responseFormat));
+    SerializerResult serializerResult = serializer.entityCollection(srvMetadata, edmEntityType, entityCollection, opts);
+
+    // 5th: configure the response object: set the body, headers and status code
+    response.setContent(serializerResult.getContent());
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
new file mode 100755
index 0000000..f9bcb2b
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
@@ -0,0 +1,235 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.ContextURL.Suffix;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Link;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
+import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
+import org.apache.olingo.server.api.uri.queryoption.SelectOption;
+
+public class DemoEntityProcessor implements EntityProcessor {
+
+  private OData odata;
+  private ServiceMetadata srvMetadata;
+  private Storage storage;
+
+  public DemoEntityProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.srvMetadata = serviceMetadata;
+  }
+
+
+//  /**
+//   * DUMMY example implementation
+//   * */
+//  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
+//      throws ODataApplicationException, SerializerException {
+//
+//		// 1. Analyze the URI
+//	  	EdmEntitySet edmEntitySet  = ((UriResourceEntitySet)uriInfo.getUriResourceParts().get(0)).getEntitySet();
+//	  	// get the system query option $expand
+//		ExpandOption expandOption = uriInfo.getExpandOption();
+//
+//		// 2. get the data. 
+//		
+//		// Note: this is FAKE implementation
+//		// used for following request: 
+//		// http://localhost:8080/DemoService/DemoService.svc/Products(1)?$expand=Category
+//		
+//		// create hard-coded product entity and set a hard-coded category as inlineEntity for the expand
+//	    Entity fakeProductEntity = new Entity().addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 11))
+//	    					.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Gamer Mouse"));
+//	    fakeProductEntity.addProperty(new Property(null, "Description", ValueType.PRIMITIVE, "High end gaming mouse"));
+//	    
+//	    // create hard-coded category entity (the target of the $expand) 
+//	    Entity fakeCategoryEntity = new Entity().addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 22))
+//	    					.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Mice"));
+//
+//	    // create navigation link from product to category
+//        Link fakeLink = new Link();
+//        fakeLink.setTitle("Category");  // hard-code the name of the navigation property as declared in EdmProvider
+//        fakeLink.setInlineEntity(fakeCategoryEntity); // the entity which will be expanded
+//        
+//        //add the link to the product entity
+//        fakeProductEntity.getNavigationLinks().add(fakeLink);
+//        
+//        // END FAKE
+//
+//        
+//		// 3. serialize
+//		ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).suffix(ContextURL.Suffix.ENTITY).build();
+//		// $expand info is added to the serializer options
+//		EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).expand(expandOption).build();  
+//		ODataSerializer serializer = this.odata.createSerializer(ODataFormat.fromContentType(responseFormat));
+//		SerializerResult serializerResult = serializer.entity(srvMetadata, edmEntitySet.getEntityType(), fakeProductEntity, options);
+//
+//		//4. configure the response object
+//		response.setContent(serializerResult.getContent());
+//		response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+//		response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+//  }
+
+  
+  
+  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
+	      throws ODataApplicationException, SerializerException {
+
+			// 1. retrieve the Entity Type
+			List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+			// Note: only in our example we can assume that the first segment is the EntitySet
+			UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+			EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+			// 2. retrieve the data from backend
+			List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+			Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+
+			// 3. apply system query options
+			
+			// handle $select
+			SelectOption selectOption = uriInfo.getSelectOption();
+			// in our example, we don't have performance issues, so we can rely upon the handling in the Olingo lib
+			// nothing else to be done
+			
+			// handle $expand
+			ExpandOption expandOption = uriInfo.getExpandOption();
+			// in our example: http://localhost:8080/DemoService/DemoService.svc/Categories(1)/$expand=Products
+			// or http://localhost:8080/DemoService/DemoService.svc/Products(1)?$expand=Category
+			if(expandOption != null){
+
+				// retrieve the EdmNavigationProperty from the expand expression
+				// Note: in our example, we have only one NavigationProperty, so we can directly access it
+				ExpandItem expandItem = expandOption.getExpandItems().get(0);
+				// can be 'Category' or 'Products', no path supported
+				UriResource uriResource = expandItem.getResourcePath().getUriResourceParts().get(0);
+				// we don't need to handle error cases, as it is done in the Olingo library
+				if(uriResource instanceof UriResourceNavigation){
+					EdmNavigationProperty edmNavigationProperty = ((UriResourceNavigation)uriResource).getProperty();
+					EdmEntityType expandEdmEntityType = edmNavigationProperty.getType();
+					String navPropName = edmNavigationProperty.getName();
+					
+					// build the inline data
+					Link link = new Link();
+					link.setTitle(navPropName);
+					link.setType(Constants.ENTITY_NAVIGATION_LINK_TYPE);  
+					
+					if(edmNavigationProperty.isCollection()){ // in case of Categories(1)/$expand=Products
+						// fetch the data for the $expand (to-many navigation) from backend
+						// here we get the data for the expand
+						EntityCollection expandEntityCollection = storage.getRelatedEntityCollection(entity, expandEdmEntityType);
+						link.setInlineEntitySet(expandEntityCollection);
+					}else{  // in case of Products(1)?$expand=Category
+						// fetch the data for the $expand (to-one navigation) from backend
+						// here we get the data for the expand
+						Entity expandEntity = storage.getRelatedEntity(entity, expandEdmEntityType);
+						link.setInlineEntity(expandEntity);
+					}
+					
+					// set the link - containing the expanded data - to the current entity 
+					entity.getNavigationLinks().add(link);
+				}
+			}
+			
+			
+			
+			// 4. serialize
+			EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+			// we need the property names of the $select, in order to build the context URL
+			String selectList = odata.createUriHelper().buildContextURLSelectList(edmEntityType, expandOption, selectOption);
+			ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet)
+                                                .selectList(selectList)
+                                                .suffix(Suffix.ENTITY).build();
+		 	
+			// make sure that $expand and $select are considered by the serializer
+			// adding the selectOption to the serializerOpts will actually tell the lib to do the job
+			EntitySerializerOptions opts = EntitySerializerOptions.with()
+					.contextURL(contextUrl)
+					.select(selectOption)
+					.expand(expandOption)
+					.build();
+
+			ODataSerializer serializer = this.odata.createSerializer(ODataFormat.fromContentType(responseFormat));
+			SerializerResult serializerResult = serializer.entity(srvMetadata, edmEntityType, entity, opts);
+
+			//5. configure the response object
+			response.setContent(serializerResult.getContent());
+			response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+			response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+	  }
+
+  
+  
+  /*
+   * These processor methods are not handled in this tutorial
+   */
+
+  public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+      ContentType requestFormat, ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+      ContentType requestFormat, ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+      throws ODataApplicationException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
new file mode 100755
index 0000000..c32c5c2
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.PrimitiveProcessor;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+
+public class DemoPrimitiveProcessor implements PrimitiveProcessor {
+
+  private OData odata;
+  private Storage storage;
+
+  public DemoPrimitiveProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+
+  }
+
+  /*
+   * In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name
+   * and the response:
+   * {
+   * 
+   * @odata.context: "$metadata#Products/Name",
+   * value: "Notebook Basic 15"
+   * }
+   */
+  public void readPrimitive(ODataRequest request, ODataResponse response,
+      UriInfo uriInfo, ContentType responseFormat)
+      throws ODataApplicationException, SerializerException {
+
+    // 1. Retrieve info from URI
+    // 1.1. retrieve the info about the requested entity set
+    List<UriResource> resourceParts = uriInfo.getUriResourceParts();
+    // Note: only in our example we can rely that the first segment is the EntitySet
+    UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
+    EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
+    // the key for the entity
+    List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();
+
+    // 1.2. retrieve the requested (Edm) property
+    // the last segment is the Property
+    UriResourceProperty uriProperty = (UriResourceProperty) resourceParts.get(resourceParts.size() - 1);
+    EdmProperty edmProperty = uriProperty.getProperty();
+    String edmPropertyName = edmProperty.getName();
+    // in our example, we know we have only primitive types in our model
+    EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();
+
+    // 2. retrieve data from backend
+    // 2.1. retrieve the entity data, for which the property has to be read
+    Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+    if (entity == null) { // Bad request
+      throw new ODataApplicationException("Entity not found",
+          HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+    }
+
+    // 2.2. retrieve the property data from the entity
+    Property property = entity.getProperty(edmPropertyName);
+    if (property == null) {
+      throw new ODataApplicationException("Property not found",
+          HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+    }
+
+    // 3. serialize
+    Object value = property.getValue();
+    if (value != null) {
+      // 3.1. configure the serializer
+      ODataFormat format = ODataFormat.fromContentType(responseFormat);
+      ODataSerializer serializer = odata.createSerializer(format);
+
+      ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
+      PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
+      // 3.2. serialize
+      SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options);
+      InputStream propertyStream = serializerResult.getContent();
+
+      // 4. configure the response object
+      response.setContent(propertyStream);
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+    } else {
+      // in case there's no value for the property, we can skip the serialization
+      response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+    }
+  }
+
+  /*
+   * These processor methods are not handled in this tutorial
+   */
+
+  public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
+      ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+      throws ODataApplicationException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/util/Util.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/util/Util.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/util/Util.java
new file mode 100755
index 0000000..f16360f
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/util/Util.java
@@ -0,0 +1,149 @@
+/*
+ * 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 myservice.mynamespace.util;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmBindingTarget;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriParameter;
+
+public class Util {
+
+  public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
+      List<UriParameter> keyParams) {
+
+    List<Entity> entityList = entitySet.getEntities();
+
+    // loop over all entities in order to find that one that matches
+    // all keys in request e.g. contacts(ContactID=1, CompanyID=1)
+    for (Entity entity : entityList) {
+      boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
+      if (foundEntity) {
+        return entity;
+      }
+    }
+
+    return null;
+  }
+
+  public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity rt_entity,
+      List<UriParameter> keyParams) {
+
+    // loop over all keys
+    for (final UriParameter key : keyParams) {
+      // key
+      String keyName = key.getName();
+      String keyText = key.getText();
+
+      // note: below line doesn't consider: keyProp can be part of a complexType in V4
+      // in such case, it would be required to access it via getKeyPropertyRef()
+      // but since this isn't the case in our model, we ignore it in our implementation
+      EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName);
+      // Edm: we need this info for the comparison below
+      Boolean isNullable = edmKeyProperty.isNullable();
+      Integer maxLength = edmKeyProperty.getMaxLength();
+      Integer precision = edmKeyProperty.getPrecision();
+      Boolean isUnicode = edmKeyProperty.isUnicode();
+      Integer scale = edmKeyProperty.getScale();
+      // get the EdmType in order to compare
+      EdmType edmType = edmKeyProperty.getType();
+      // if(EdmType instanceof EdmPrimitiveType) // do we need this?
+      EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
+
+      // Runtime data: the value of the current entity
+      // don't need to check for null, this is done in FWK
+      Object valueObject = rt_entity.getProperty(keyName).getValue();
+      // TODO if the property is a complex type
+
+      // now need to compare the valueObject with the keyText String
+      // this is done using the type.valueToString
+      String valueAsString = null;
+      try {
+        valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable,
+            maxLength, precision, scale, isUnicode);
+      } catch (EdmPrimitiveTypeException e) {
+        return false; // TODO proper Exception handling
+      }
+
+      if (valueAsString == null) {
+        return false;
+      }
+
+      boolean matches = valueAsString.equals(keyText);
+      // if any of the key properties is not found in the entity, we don't need to search further
+      if (!matches) {
+        return false;
+      }
+      // if the given key value is found in the current entity, continue with the next key
+    }
+
+    return true;
+  }
+
+  /**
+   * Example:
+   * For the following navigation: DemoService.svc/Categories(1)/Products
+   * we need the EdmEntitySet for the navigation property "Products"
+   *
+   * This is defined as follows in the metadata:
+   * <code>
+   * 
+   * <EntitySet Name="Categories" EntityType="OData.Demo.Category">
+   * <NavigationPropertyBinding Path="Products" Target="Products"/>
+   * </EntitySet>
+   * </code>
+   * The "Target" attribute specifies the target EntitySet
+   * Therefore we need the startEntitySet "Categories" in order to retrieve the target EntitySet "Products"
+   */
+  public static EdmEntitySet getNavigationTargetEntitySet(EdmEntitySet startEntitySet,
+      EdmNavigationProperty edmNavigationProperty)
+      throws ODataApplicationException {
+
+    EdmEntitySet navigationTargetEntitySet = null;
+
+    String navPropName = edmNavigationProperty.getName();
+    EdmBindingTarget edmBindingTarget = startEntitySet.getRelatedBindingTarget(navPropName);
+    if (edmBindingTarget == null) {
+      throw new ODataApplicationException("Not supported.",
+          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    }
+
+    if (edmBindingTarget instanceof EdmEntitySet) {
+      navigationTargetEntitySet = (EdmEntitySet) edmBindingTarget;
+    } else {
+      throw new ODataApplicationException("Not supported.",
+          HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+    }
+
+    return navigationTargetEntitySet;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/web/DemoServlet.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/web/DemoServlet.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/web/DemoServlet.java
new file mode 100755
index 0000000..5c828e5
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/web/DemoServlet.java
@@ -0,0 +1,75 @@
+/*
+ * 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 myservice.mynamespace.web;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import myservice.mynamespace.data.Storage;
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.service.DemoEntityCollectionProcessor;
+import myservice.mynamespace.service.DemoEntityProcessor;
+import myservice.mynamespace.service.DemoPrimitiveProcessor;
+
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataHttpHandler;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DemoServlet extends HttpServlet {
+
+  private static final long serialVersionUID = 1L;
+  private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
+
+  @Override
+  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+    try {
+      HttpSession session = req.getSession(true);
+      Storage storage = (Storage) session.getAttribute(Storage.class.getName());
+      if (storage == null) {
+        storage = new Storage();
+        session.setAttribute(Storage.class.getName(), storage);
+      }
+
+      // create odata handler and configure it with EdmProvider and Processor
+      OData odata = OData.newInstance();
+      ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
+      ODataHttpHandler handler = odata.createHandler(edm);
+      handler.register(new DemoEntityCollectionProcessor(storage));
+      handler.register(new DemoEntityProcessor(storage));
+      handler.register(new DemoPrimitiveProcessor(storage));
+
+      // let the handler do the work
+      handler.process(req, resp);
+    } catch (RuntimeException e) {
+      LOG.error("Server Error occurred in DemoServlet", e);
+      throw new ServletException(e);
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/webapp/WEB-INF/web.xml b/samples/tutorials/p6_queryoptions-es/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..bc216cb
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
+
+	<servlet>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <servlet-class> myservice.mynamespace.web.DemoServlet</servlet-class>
+	  <load-on-startup>1</load-on-startup>
+	</servlet>
+	
+	<servlet-mapping>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <url-pattern>/DemoService.svc/*</url-pattern>
+	</servlet-mapping>
+</web-app>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp b/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
new file mode 100755
index 0000000..cee3a31
--- /dev/null
+++ b/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
@@ -0,0 +1,43 @@
+<!--
+
+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.
+
+-->
+<html>
+<body>
+<h2>Hello World!</h2>
+<a href="DemoService.svc/">OData Olingo V4 Demo Service - Expand and Select</a>
+<h3>Sample Links</h3>
+<ul>
+    <li>
+        <a href="DemoService.svc/Products(1)/?$expand=Category">Expand - /Products(1)/?$expand=Category</a>
+    </li>
+    <li>
+        <a href="DemoService.svc/Products/?$expand=Category">Expand - /Products/?$expand=Category</a>
+    </li>
+    <li>
+        <a href="DemoService.svc/Categories(1)/?$expand=Products">Expand - /Categories(1)/?$expand=Products</a>
+    </li>
+    <li>
+        <a href="DemoService.svc/Categories/?$expand=Products">Expand - /DemoService.svc/Categories/?$expand=Products</a>
+    </li>
+</ul>
+
+
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/pom.xml b/samples/tutorials/pom.xml
index 111e200..cfa48a4 100644
--- a/samples/tutorials/pom.xml
+++ b/samples/tutorials/pom.xml
@@ -39,7 +39,8 @@
     <module>p2_readep</module>
     <module>p3_write</module>
     <module>p4_navigation</module>
-    <module>p5_queryoptions</module>
+    <module>p5_queryoptions-tis</module>
+    <module>p6_queryoptions-es</module>
   </modules>
 
   <build>


[15/18] olingo-odata4 git commit: [OLINGO-708] Enabled async support for batch case in TecSvc

Posted by ch...@apache.org.
[OLINGO-708] Enabled async support for batch case in TecSvc


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

Branch: refs/heads/OLINGO-640
Commit: 955823383d8755cace6872e2f9f6b72db22c885d
Parents: 5e481b2
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Aug 3 19:21:38 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Aug 3 19:22:34 2015 +0200

----------------------------------------------------------------------
 .../fit/tecsvc/client/AsyncSupportITCase.java   | 104 ++++++++
 .../fit/tecsvc/http/BasicAsyncITCase.java       | 238 +++++++++++++++++++
 fit/src/test/resources/basicBatchPost.batch     |  33 +++
 .../processor/TechnicalBatchProcessor.java      |  17 ++
 4 files changed, 392 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/95582338/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
index ad8fcbc..b99317d 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/AsyncSupportITCase.java
@@ -19,9 +19,15 @@
 package org.apache.olingo.fit.tecsvc.client;
 
 import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.client.api.communication.ODataClientErrorException;
+import org.apache.olingo.client.api.communication.request.AsyncBatchRequestWrapper;
+import org.apache.olingo.client.api.communication.request.ODataBatchableRequest;
 import org.apache.olingo.client.api.communication.request.ODataRequest;
+import org.apache.olingo.client.api.communication.request.batch.ODataBatchRequest;
 import org.apache.olingo.client.api.communication.request.cud.ODataEntityCreateRequest;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntityRequest;
 import org.apache.olingo.client.api.communication.response.AsyncResponseWrapper;
+import org.apache.olingo.client.api.communication.response.ODataBatchResponse;
 import org.apache.olingo.client.api.communication.response.ODataEntityCreateResponse;
 import org.apache.olingo.client.api.communication.response.ODataResponse;
 import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
@@ -29,6 +35,7 @@ import org.apache.olingo.client.api.domain.ClientEntity;
 import org.apache.olingo.client.api.domain.ClientEntitySet;
 import org.apache.olingo.client.api.domain.ClientObjectFactory;
 import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.client.api.uri.URIBuilder;
 import org.apache.olingo.client.core.ODataClientFactory;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityCollection;
@@ -40,9 +47,11 @@ import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.fit.AbstractBaseTestITCase;
 import org.apache.olingo.fit.tecsvc.TecSvcConst;
 import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.net.URI;
+import java.net.URISyntaxException;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
@@ -198,6 +207,101 @@ public final class AsyncSupportITCase extends AbstractBaseTestITCase {
     assertNull(property2.getPrimitiveValue());
   }
 
+  @Test
+  @Ignore("mibo: Does currently not work as expected -> issue in ODataClient?")
+  public void getBatchRequest() throws Exception {
+    ODataClient client = getClient();
+    final ODataBatchRequest request = client.getBatchRequestFactory().getBatchRequest(SERVICE_URI);
+
+//    final BatchManager payload = request.payloadManager();
+
+    // create new request
+//    ODataEntityRequest<ClientEntity> getRequest = appendGetRequest(client, payload, "ESAllPrim", 32767, false);
+//    payload.addRequest(getRequest);
+
+    //
+    request.addCustomHeader(HttpHeader.PREFER,
+        "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=1");
+    ODataBatchableRequest getRequest = appendGetRequest(client, "ESAllPrim", 32767, false);
+    AsyncBatchRequestWrapper asyncRequest =
+        client.getAsyncRequestFactory().getAsyncBatchRequestWrapper(request);
+    asyncRequest.addRetrieve(getRequest);
+    AsyncResponseWrapper<ODataBatchResponse> asyncResponse = asyncRequest.execute();
+
+//    Future<ODataBatchResponse> test = payload.getAsyncResponse();
+//    ODataBatchResponse res = payload.getResponse();
+//
+//    while(!test.isDone()) {
+//      System.out.println("Wait...");
+//      TimeUnit.SECONDS.sleep(1);
+//    }
+
+//    // Fetch result
+//    final ODataBatchResponse response = asyncResponse.getODataResponse();
+
+    waitTillDone(asyncResponse, 3);
+//    assertEquals(HttpStatusCode.ACCEPTED.getStatusCode(), response.getStatusCode());
+//    assertEquals("Accepted", response.getStatusMessage());
+
+    ODataResponse firstResponse = asyncResponse.getODataResponse();
+    assertEquals(200, firstResponse.getStatusCode());
+    assertEquals(2, firstResponse.getHeaderNames().size());
+    assertEquals("4.0", firstResponse.getHeader("OData-Version").iterator().next());
+
+    ResWrap<Entity> firWrap = getClient().getDeserializer(ContentType.APPLICATION_JSON)
+        .toEntity(firstResponse.getRawResponse());
+    Entity entity = firWrap.getPayload();
+    assertEquals(32767, entity.getProperty("PropertyInt16").asPrimitive());
+    assertEquals("First Resource - positive values", entity.getProperty("PropertyString").asPrimitive());
+  }
+
+
+  /**
+   * Test delete with async prefer header but without async support from TecSvc.
+   */
+  @Test
+  public void deleteEntity() throws Exception {
+    ODataClient client = getClient();
+    URI uri = client.newURIBuilder(SERVICE_URI)
+        .appendEntitySetSegment(ES_ALL_PRIM)
+        .appendKeySegment(32767).build();
+
+    // asyncDeleteRequest async request
+    ODataRequest deleteRequest = getClient().getCUDRequestFactory().getDeleteRequest(uri)
+        .addCustomHeader(HttpHeader.PREFER, "respond-async; " + TechnicalAsyncService.TEC_ASYNC_SLEEP + "=5");
+    AsyncResponseWrapper<ODataResponse> asyncDeleteRequest =
+        client.getAsyncRequestFactory().getAsyncRequestWrapper(deleteRequest).execute();
+
+    waitTillDone(asyncDeleteRequest, 5);
+
+    ODataResponse response = asyncDeleteRequest.getODataResponse();
+    assertEquals(HttpStatusCode.NO_CONTENT.getStatusCode(), response.getStatusCode());
+
+    // Check that the deleted entity is really gone.
+    // This check has to be in the same session in order to access the same data provider.
+    ODataEntityRequest<ClientEntity> entityRequest = client.getRetrieveRequestFactory().getEntityRequest(uri);
+    entityRequest.addCustomHeader(HttpHeader.COOKIE, response.getHeader(HttpHeader.SET_COOKIE).iterator().next());
+    try {
+      entityRequest.execute();
+      fail("Expected exception not thrown!");
+    } catch (final ODataClientErrorException e) {
+      assertEquals(HttpStatusCode.NOT_FOUND.getStatusCode(), e.getStatusLine().getStatusCode());
+    }
+  }
+
+  private ODataEntityRequest<ClientEntity> appendGetRequest(final ODataClient client, final String segment,
+                                                            final Object key, final boolean isRelative)
+      throws URISyntaxException {
+
+    final URIBuilder targetURI = client.newURIBuilder(SERVICE_URI);
+    targetURI.appendEntitySetSegment(segment).appendKeySegment(key);
+    final URI uri = (isRelative) ? new URI(SERVICE_URI).relativize(targetURI.build()) : targetURI.build();
+
+    ODataEntityRequest<ClientEntity> queryReq = client.getRetrieveRequestFactory().getEntityRequest(uri);
+    queryReq.setFormat(ContentType.JSON);
+    return queryReq;
+  }
+
   private void checkEntityAvailableWith(ClientEntitySet entitySet, String property, Object value) {
     List<ClientEntity> entities = entitySet.getEntities();
     for (ClientEntity entity : entities) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/95582338/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicAsyncITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicAsyncITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicAsyncITCase.java
new file mode 100644
index 0000000..c4a6779
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicAsyncITCase.java
@@ -0,0 +1,238 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.fit.tecsvc.http;
+
+import org.apache.olingo.client.api.ODataClient;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpMethod;
+import org.apache.olingo.fit.AbstractBaseTestITCase;
+import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.apache.olingo.fit.util.StringHelper;
+import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Pattern;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * Test support of asynchronous batch within the TecSvc without using the OData client library (only
+ * use java.net.* components for plain http communication).
+ */
+public class BasicAsyncITCase extends AbstractBaseTestITCase {
+
+  private static final String SERVICE_URI = TecSvcConst.BASE_URI + "/";
+
+  private static final String HEADER_CONTENT_TRANSFER_ENCODING_BINARY = "Content-Transfer-Encoding: binary";
+  private static final String HEADER_CONTENT_TYPE_HTTP =
+      HttpHeader.CONTENT_TYPE + ": " + ContentType.APPLICATION_HTTP.toContentTypeString();
+  private static final String DEFAULT_BATCH_BOUNDARY = "batch_123";
+  private static final String ACCEPT_HEADER_VALUE = ContentType.APPLICATION_JSON.toContentTypeString();
+
+  private static final String CRLF = "\r\n";
+  private static final String DEFAULT_ENCODING = "utf-8";
+
+  /**
+   * Works
+   */
+  @Test
+  public void batchAsync() throws Exception {
+    final String content = getDefaultRequest("ESAllPrim(32767)");
+    final HttpURLConnection connection = postBatch(StringHelper.encapsulate(content), DEFAULT_BATCH_BOUNDARY, 1);
+    StringHelper.Stream response = StringHelper.toStream(connection.getInputStream());
+
+    assertEquals(0, response.byteLength());
+
+    Map<String, List<String>> headerFields = connection.getHeaderFields();
+    assertEquals("HTTP/1.1 202 Accepted", headerFields.get(null).get(0));
+    assertTrue(Pattern.matches("http:\\/\\/localhost:9080\\/odata-server-tecsvc\\/status\\/\\d*",
+        headerFields.get("Location").get(0)));
+    assertEquals("respond-async", headerFields.get("Preference-Applied").get(0));
+
+    // get async response (still pending)
+    String respondUri = headerFields.get("Location").get(0);
+    HttpURLConnection statusRequest = getRequest(new URL(respondUri), Collections.<String, String>emptyMap());
+    StringHelper.Stream statusBody = StringHelper.toStream(statusRequest.getInputStream());
+    Map<String, List<String>> statusHeaderFields = statusRequest.getHeaderFields();
+    assertEquals("HTTP/1.1 202 Accepted", statusHeaderFields.get(null).get(0));
+    assertEquals(0, statusBody.byteLength());
+
+    // get async response (now finished)
+    TimeUnit.SECONDS.sleep(2);
+    HttpURLConnection result = getRequest(new URL(respondUri), Collections.<String, String>emptyMap());
+    StringHelper.Stream resultBody = StringHelper.toStream(result.getInputStream());
+    Map<String, List<String>> resultHeaderFields = result.getHeaderFields();
+    String resBody = resultBody.asString();
+
+    assertEquals("HTTP/1.1 200 OK", resultHeaderFields.get(null).get(0));
+    assertEquals(1013, resultBody.byteLength());
+    contains(resBody,
+        "HTTP/1.1 200 OK",
+        "OData-Version: 4.0",
+        "Content-Length: 605",
+        "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"",
+        "\"PropertyInt16\":32767",
+        "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\",",
+        "--batch_", "--");
+  }
+
+  /**
+   * Test with changeset
+   */
+  @Test
+  public void asyncChangesetViaPost() throws Exception {
+    InputStream content = Thread.currentThread().getContextClassLoader().getResourceAsStream("basicBatchPost.batch");
+    final HttpURLConnection connection = postBatch(content, "batch_8194-cf13-1f56", 1);
+    StringHelper.Stream response = StringHelper.toStream(connection.getInputStream());
+    assertEquals(0, response.byteLength());
+
+    Map<String, List<String>> headerFields = connection.getHeaderFields();
+    assertEquals("HTTP/1.1 202 Accepted", headerFields.get(null).get(0));
+    // because of generated status id it is only checked that the location starts correct and contains a number
+    assertTrue(Pattern.matches("http:\\/\\/localhost:9080\\/odata-server-tecsvc\\/status\\/\\d*",
+        headerFields.get("Location").get(0)));
+    assertEquals("respond-async", headerFields.get("Preference-Applied").get(0));
+
+    // get async response (still pending)
+    String respondUri = headerFields.get("Location").get(0);
+    HttpURLConnection statusRequest = getRequest(new URL(respondUri), Collections.<String, String>emptyMap());
+    StringHelper.Stream statusBody = StringHelper.toStream(statusRequest.getInputStream());
+    Map<String, List<String>> statusHeaderFields = statusRequest.getHeaderFields();
+    assertEquals("HTTP/1.1 202 Accepted", statusHeaderFields.get(null).get(0));
+    assertEquals(0, statusBody.byteLength());
+
+    // get async response (now finished)
+    TimeUnit.SECONDS.sleep(2);
+    HttpURLConnection result = getRequest(new URL(respondUri), Collections.<String, String>emptyMap());
+    StringHelper.Stream resultBody = StringHelper.toStream(result.getInputStream());
+    Map<String, List<String>> resultHeaderFields = result.getHeaderFields();
+    String resBody = resultBody.asString();
+    assertEquals("HTTP/1.1 200 OK", resultHeaderFields.get(null).get(0));
+    assertEquals(2324, resultBody.byteLength());
+    contains(resBody,
+        "HTTP/1.1 200 OK",
+        "OData-Version: 4.0",
+        "Content-Length: 605",
+        "\"@odata.context\":\"$metadata#ESAllPrim/$entity\"",
+        "\"PropertyInt16\":32767",
+        "\"PropertyGuid\":\"01234567-89ab-cdef-0123-456789abcdef\",",
+        "--batch_", "--");
+  }
+
+  /**
+   * Validates that the content contains all given values in same order as the parameters are given.
+   * If the content does not contain a value or not in the given order <code>Assert.fail()</code> is called.
+   *
+   * @param content content which is checked
+   * @param values values which must be in content (and in correct order)
+   */
+  private void contains(String content, String... values) {
+    int index = 0;
+    for (String value : values) {
+      int currentIndex = content.indexOf(value, index);
+      if(currentIndex == -1) {
+        if(content.contains(value)) {
+          int foundIndex = content.indexOf(value);
+          fail("Expected value '" + value + "' was found but not were expected " +
+              "(started to search from position '" + index + "' but found first occurrence at index '" +
+              foundIndex + "').");
+        } else {
+          fail("Expected value '" + value + "' was not found");
+        }
+      }
+      index = currentIndex;
+    }
+  }
+
+  private String getDefaultRequest(final String uri) {
+    return "--" + DEFAULT_BATCH_BOUNDARY + CRLF
+        + HEADER_CONTENT_TRANSFER_ENCODING_BINARY + CRLF
+        + HEADER_CONTENT_TYPE_HTTP + CRLF
+        + CRLF
+        + "GET " + uri + " HTTP/1.1" + CRLF
+        + CRLF
+        + CRLF
+        + "--" + DEFAULT_BATCH_BOUNDARY + "--";
+  }
+
+  private HttpURLConnection postRequest(final URL url, final String content, final Map<String, String> headers)
+      throws IOException {
+    final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.POST.toString());
+    //
+    for (Map.Entry<String, String> header : headers.entrySet()) {
+      connection.setRequestProperty(header.getKey(), header.getValue());
+    }
+    //
+    connection.setDoOutput(true);
+    final OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
+    writer.append(content);
+    writer.close();
+    connection.connect();
+    return connection;
+  }
+
+  private HttpURLConnection getRequest(URL url, Map<String, String> headers) throws IOException {
+    final HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+    connection.setRequestMethod(HttpMethod.GET.toString());
+    //
+    for (Map.Entry<String, String> header : headers.entrySet()) {
+      connection.setRequestProperty(header.getKey(), header.getValue());
+    }
+    //
+    connection.connect();
+    return connection;
+  }
+
+  private HttpURLConnection postBatch(final InputStream content, String batchBoundary, int sleepTime)
+      throws IOException {
+
+    Map<String, String> headers = new HashMap<String, String>();
+    String contentTypeValue = ContentType.create(
+        ContentType.MULTIPART_MIXED, "boundary", batchBoundary).toContentTypeString();
+    headers.put(HttpHeader.CONTENT_TYPE, contentTypeValue);
+    headers.put(HttpHeader.ACCEPT, ACCEPT_HEADER_VALUE);
+    if(sleepTime >= 0) {
+      headers.put(HttpHeader.PREFER, "respond-async; " +
+          TechnicalAsyncService.TEC_ASYNC_SLEEP + "=" + String.valueOf(sleepTime));
+    }
+
+    StringHelper.Stream s = StringHelper.toStream(content);
+    final URL url = new URL(SERVICE_URI + "$batch");
+    return postRequest(url, s.asString(DEFAULT_ENCODING), headers);
+  }
+
+  @Override
+  protected ODataClient getClient() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/95582338/fit/src/test/resources/basicBatchPost.batch
----------------------------------------------------------------------
diff --git a/fit/src/test/resources/basicBatchPost.batch b/fit/src/test/resources/basicBatchPost.batch
new file mode 100644
index 0000000..ad5f617
--- /dev/null
+++ b/fit/src/test/resources/basicBatchPost.batch
@@ -0,0 +1,33 @@
+--batch_8194-cf13-1f56
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+GET ESAllPrim(32767) HTTP/1.1
+Accept: application/json
+
+
+--batch_8194-cf13-1f56
+Content-Type: multipart/mixed; boundary=changeset_f980-1cb6-94dd
+
+--changeset_f980-1cb6-94dd
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+Content-ID: changeRequest1
+
+PUT ESAllPrim(32767) HTTP/1.1
+Accept: application/json
+Content-Type: application/json
+
+{"PropertyString":"MODIFIED"}
+
+--changeset_f980-1cb6-94dd--
+
+--batch_8194-cf13-1f56
+Content-Type: application/http
+Content-Transfer-Encoding: binary
+
+GET ESAllPrim(32767)/PropertyString HTTP/1.1
+Accept: application/json
+
+
+--batch_8194-cf13-1f56--

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/95582338/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java
index a2c7629..6821c8f 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalBatchProcessor.java
@@ -36,6 +36,8 @@ import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
 import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
 import org.apache.olingo.server.api.prefer.PreferencesApplied;
 import org.apache.olingo.server.api.processor.BatchProcessor;
+import org.apache.olingo.server.tecsvc.async.AsyncProcessor;
+import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 
 public class TechnicalBatchProcessor extends TechnicalProcessor implements BatchProcessor {
@@ -47,6 +49,21 @@ public class TechnicalBatchProcessor extends TechnicalProcessor implements Batch
   @Override
   public void processBatch(final BatchFacade facade, final ODataRequest request, final ODataResponse response)
       throws ODataApplicationException, ODataLibraryException {
+    // only the first batch call (process batch) must be handled in a separate way for async support
+    // because a changeset has to be wrapped within a process batch call
+    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
+      TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
+      BatchProcessor processor = new TechnicalBatchProcessor(dataProvider);
+      processor.init(odata, serviceMetadata);
+      AsyncProcessor<BatchProcessor> asyncProcessor = asyncService.register(processor, BatchProcessor.class);
+      asyncProcessor.prepareFor().processBatch(facade, request, response);
+      String location = asyncProcessor.processAsync();
+      TechnicalAsyncService.acceptedResponse(response, location);
+      //
+      return;
+    }
+
+
     final boolean continueOnError =
         odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasContinueOnError();
 


[05/18] olingo-odata4 git commit: [OLINGO-713] Added tutorial project for system query options

Posted by ch...@apache.org.
[OLINGO-713] Added tutorial project for system query options


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

Branch: refs/heads/OLINGO-640
Commit: 010d94f7f762f49db1668d8a008bc639e9df783e
Parents: fb65199
Author: Michael Bolz <mi...@sap.com>
Authored: Fri Jul 24 15:50:56 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Jul 24 15:50:56 2015 +0200

----------------------------------------------------------------------
 samples/tutorials/p5_queryoptions/pom.xml       |  79 ++++++++++
 .../myservice/mynamespace/data/Storage.java     | 130 ++++++++++++++++
 .../mynamespace/service/DemoEdmProvider.java    | 154 +++++++++++++++++++
 .../service/DemoEntityCollectionProcessor.java  | 142 +++++++++++++++++
 .../service/DemoEntityProcessor.java            | 118 ++++++++++++++
 .../service/DemoPrimitiveProcessor.java         | 150 ++++++++++++++++++
 .../java/myservice/mynamespace/util/Util.java   | 105 +++++++++++++
 .../myservice/mynamespace/web/DemoServlet.java  |  76 +++++++++
 .../src/main/webapp/WEB-INF/web.xml             |  40 +++++
 .../p5_queryoptions/src/main/webapp/index.jsp   |  26 ++++
 samples/tutorials/pom.xml                       |   1 +
 11 files changed, 1021 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/pom.xml b/samples/tutorials/p5_queryoptions/pom.xml
new file mode 100755
index 0000000..117f59d
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>my.group.id</groupId>
+	<artifactId>DemoService-QueryOptions</artifactId>
+	<packaging>war</packaging>
+	<version>0.0.1</version>
+
+	<name>${project.artifactId}-Webapp</name>
+
+	<build>
+		<finalName>DemoService</finalName>
+	</build>
+
+	<properties>
+		<javax.version>2.5</javax.version>
+		<odata.version>4.0.0-beta-03</odata.version>
+		<slf4j.version>1.7.7</slf4j.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>${javax.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-core</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-core</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>${slf4j.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
new file mode 100755
index 0000000..2aa9fac
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
@@ -0,0 +1,130 @@
+/*
+ * 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 myservice.mynamespace.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.util.Util;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriParameter;
+
+public class Storage {
+
+	private List<Entity> productList;
+
+	public Storage() {
+		productList = new ArrayList<Entity>();
+		initSampleData();
+	}
+
+	/* PUBLIC FACADE */
+
+	public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet)throws ODataApplicationException{
+
+		// actually, this is only required if we have more than one Entity Sets
+		if(edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)){
+			return getProducts();
+		}
+
+		return null;
+	}
+
+	public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
+					throws ODataApplicationException{
+
+		EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+
+		// actually, this is only required if we have more than one Entity Type
+		if(edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)){
+			return getProduct(edmEntityType, keyParams);
+		}
+
+		return null;
+	}
+
+
+
+	/*  INTERNAL */
+
+	private EntityCollection getProducts(){
+		EntityCollection retEntitySet = new EntityCollection();
+
+		for(Entity productEntity : this.productList){
+			   retEntitySet.getEntities().add(productEntity);
+		}
+
+		return retEntitySet;
+	}
+
+
+	private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
+					throws ODataApplicationException{
+
+		// the list of entities at runtime
+		EntityCollection entitySet = getProducts();
+		
+		/*  generic approach  to find the requested entity */
+		Entity requestedEntity = Util.findEntity(edmEntityType, entitySet, keyParams);
+		
+		if(requestedEntity == null){
+			// this variable is null if our data doesn't contain an entity for the requested key
+			// Throw suitable exception
+			throw new ODataApplicationException("Entity for requested key doesn't exist",
+          HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+		}
+
+		return requestedEntity;
+	}
+
+	/* HELPER */
+
+	private void initSampleData(){
+
+		// add some sample product entities
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")));
+
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")));
+
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
new file mode 100755
index 0000000..3c28a21
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
@@ -0,0 +1,154 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.olingo.commons.api.ODataException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
+import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
+import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
+
+public class DemoEdmProvider extends CsdlAbstractEdmProvider {
+
+  // Service Namespace
+  public static final String NAMESPACE = "OData.Demo";
+
+  // EDM Container
+  public static final String CONTAINER_NAME = "Container";
+  public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
+
+  // Entity Types Names
+  public static final String ET_PRODUCT_NAME = "Product";
+  public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);
+
+  // Entity Set Names
+  public static final String ES_PRODUCTS_NAME = "Products";
+
+  @Override
+  public CsdlEntityType getEntityType(FullQualifiedName entityTypeName)
+      throws ODataException {
+    // this method is called for one of the EntityTypes that are configured in the Schema
+    if (ET_PRODUCT_FQN.equals(entityTypeName)) {
+
+      // create EntityType properties
+      CsdlProperty id = new CsdlProperty().setName("ID").setType(
+          EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
+      CsdlProperty name = new CsdlProperty().setName("Name").setType(
+          EdmPrimitiveTypeKind.String.getFullQualifiedName());
+      CsdlProperty description = new CsdlProperty().setName("Description").setType(
+          EdmPrimitiveTypeKind.String.getFullQualifiedName());
+
+      // create PropertyRef for Key element
+      CsdlPropertyRef propertyRef = new CsdlPropertyRef();
+      propertyRef.setName("ID");
+
+      // configure EntityType
+      CsdlEntityType entityType = new CsdlEntityType();
+      entityType.setName(ET_PRODUCT_NAME);
+      entityType.setProperties(Arrays.asList(id, name, description));
+      entityType.setKey(Collections.singletonList(propertyRef));
+
+      return entityType;
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer,
+      String entitySetName) throws ODataException {
+    if (entityContainer.equals(CONTAINER)) {
+      if (entitySetName.equals(ES_PRODUCTS_NAME)) {
+        CsdlEntitySet entitySet = new CsdlEntitySet();
+        entitySet.setName(ES_PRODUCTS_NAME);
+        entitySet.setType(ET_PRODUCT_FQN);
+
+        return entitySet;
+      }
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public CsdlEntityContainerInfo getEntityContainerInfo(
+      FullQualifiedName entityContainerName) throws ODataException {
+    // This method is invoked when displaying the service document at
+    // e.g. http://localhost:8080/DemoService/DemoService.svc
+    if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
+      CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
+      entityContainerInfo.setContainerName(CONTAINER);
+      return entityContainerInfo;
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public List<CsdlSchema> getSchemas() throws ODataException {
+    // create Schema
+    CsdlSchema schema = new CsdlSchema();
+    schema.setNamespace(NAMESPACE);
+
+    // add EntityTypes
+    List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
+    entityTypes.add(getEntityType(ET_PRODUCT_FQN));
+    schema.setEntityTypes(entityTypes);
+
+    // add EntityContainer
+    schema.setEntityContainer(getEntityContainer());
+
+    // finally
+    List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
+    schemas.add(schema);
+
+    return schemas;
+
+  }
+
+  @Override
+  public CsdlEntityContainer getEntityContainer() throws ODataException {
+    // create EntitySets
+    List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
+    entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
+
+    // create EntityContainer
+    CsdlEntityContainer entityContainer = new CsdlEntityContainer();
+    entityContainer.setName(CONTAINER_NAME);
+    entityContainer.setEntitySets(entitySets);
+
+    return entityContainer;
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
new file mode 100755
index 0000000..fc58c23
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipOption;
+import org.apache.olingo.server.api.uri.queryoption.TopOption;
+
+public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
+
+  private OData odata;
+  private ServiceMetadata serviceMetadata;
+  private Storage storage;
+
+  public DemoEntityCollectionProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+  }
+
+  public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+      ContentType responseFormat) throws ODataApplicationException, SerializerException {
+
+    // 1st retrieve the requested EntitySet from the uriInfo (representation of the parsed URI)
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    // in our example, the first segment is the EntitySet
+    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+    // 2nd: fetch the data from backend for this requested EntitySetName and deliver as EntitySet
+    EntityCollection entityCollection = storage.readEntitySetData(edmEntitySet);
+
+    // 3rd: apply System Query Options
+    // modify the result set according to the query options, specified by the end user
+    List<Entity> entityList = entityCollection.getEntities();
+    EntityCollection returnEntityCollection = new EntityCollection();
+
+    // handle $count: always return the original number of entities, without considering $top and $skip
+    CountOption countOption = uriInfo.getCountOption();
+    if (countOption != null) {
+      boolean isCount = countOption.getValue();
+      if (isCount) {
+        returnEntityCollection.setCount(entityList.size());
+      }
+    }
+
+    // handle $skip
+    SkipOption skipOption = uriInfo.getSkipOption();
+    if (skipOption != null) {
+      int skipNumber = skipOption.getValue();
+      if (skipNumber >= 0 && skipNumber <= entityList.size()) {
+        entityList = entityList.subList(skipNumber, entityList.size());
+      } else {
+        throw new ODataApplicationException("Invalid value for $skip", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+            Locale.ROOT);
+      }
+    }
+
+    // handle $top
+    TopOption topOption = uriInfo.getTopOption();
+    if (topOption != null) {
+      int topNumber = topOption.getValue();
+      if (topNumber >= 0 && topNumber <= entityList.size()) {
+        entityList = entityList.subList(0, topNumber);
+      } else {
+        throw new ODataApplicationException("Invalid value for $top", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+            Locale.ROOT);
+      }
+    }
+
+    // after applying the system query options, create the EntityCollection based on the reduced list
+    for (Entity entity : entityList) {
+      returnEntityCollection.getEntities().add(entity);
+    }
+
+    // 4th: create a serializer based on the requested format (json)
+    ODataFormat format = ODataFormat.fromContentType(responseFormat);
+    ODataSerializer serializer = odata.createSerializer(format);
+
+    // and serialize the content: transform from the EntitySet object to InputStream
+    EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
+
+    EntityCollectionSerializerOptions opts =
+        EntityCollectionSerializerOptions.with().contextURL(contextUrl).count(countOption).build();
+    SerializerResult serializerResult =
+        serializer.entityCollection(serviceMetadata, edmEntityType, returnEntityCollection, opts);
+    InputStream serializedContent = serializerResult.getContent();
+
+    // 5th: configure the response object: set the body, headers and status code
+    response.setContent(serializedContent);
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
new file mode 100755
index 0000000..81453a0
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
@@ -0,0 +1,118 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+
+public class DemoEntityProcessor implements EntityProcessor {
+
+  private OData odata;
+  private ServiceMetadata serviceMetadata;
+  private Storage storage;
+
+  public DemoEntityProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+  }
+
+  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
+      throws ODataApplicationException, SerializerException {
+
+    // 1. retrieve the Entity Type
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    // Note: only in our example we can assume that the first segment is the EntitySet
+    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+    // 2. retrieve the data from backend
+    List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+    Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+
+    // 3. serialize
+    EdmEntityType entityType = edmEntitySet.getEntityType();
+
+    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    // expand and select currently not supported
+    EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();
+
+    ODataFormat oDataFormat = ODataFormat.fromContentType(responseFormat);
+    ODataSerializer serializer = this.odata.createSerializer(oDataFormat);
+    SerializerResult serializerResult = serializer.entity(serviceMetadata, entityType, entity, options);
+    InputStream entityStream = serializerResult.getContent();
+
+    // 4. configure the response object
+    response.setContent(entityStream);
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+  }
+
+  /*
+   * These processor methods are not handled in this tutorial
+   */
+
+  public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
+      ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
+      ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+      throws ODataApplicationException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
new file mode 100755
index 0000000..64f7949
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.PrimitiveProcessor;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+
+public class DemoPrimitiveProcessor implements PrimitiveProcessor {
+
+	private OData odata;
+	private Storage storage;
+
+	public DemoPrimitiveProcessor(Storage storage) {
+		this.storage = storage;
+	}
+
+	public void init(OData odata, ServiceMetadata serviceMetadata) {
+		this.odata = odata;
+
+	}
+
+	/*
+	 * In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name
+	 * and the response:
+	 * {
+	 *	  @odata.context: "$metadata#Products/Name",
+	 *	  value: "Notebook Basic 15"
+	 * }
+	 * */
+	public void readPrimitive(ODataRequest request, ODataResponse response,
+								UriInfo uriInfo, ContentType responseFormat)
+								throws ODataApplicationException, SerializerException {
+
+		// 1. Retrieve info from URI
+		// 1.1. retrieve the info about the requested entity set
+		List<UriResource> resourceParts = uriInfo.getUriResourceParts();
+		// Note: only in our example we can rely that the first segment is the EntitySet
+		UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
+		EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
+		// the key for the entity
+		List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();
+
+		// 1.2. retrieve the requested (Edm) property
+		// the last segment is the Property
+		UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1);
+		EdmProperty edmProperty = uriProperty.getProperty();
+		String edmPropertyName = edmProperty.getName();
+		// in our example, we know we have only primitive types in our model
+		EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();
+
+
+		// 2. retrieve data from backend
+		// 2.1. retrieve the entity data, for which the property has to be read
+		Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+		if (entity == null) { // Bad request
+			throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+		}
+
+		// 2.2. retrieve the property data from the entity
+		Property property = entity.getProperty(edmPropertyName);
+		if (property == null) {
+			throw new ODataApplicationException("Property not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+		}
+
+		// 3. serialize
+		Object value = property.getValue();
+		if (value != null) {
+			// 3.1. configure the serializer
+			ODataFormat format = ODataFormat.fromContentType(responseFormat);
+			ODataSerializer serializer = odata.createSerializer(format);
+
+			ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
+			PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
+			// 3.2. serialize
+			SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options);
+			InputStream propertyStream = serializerResult.getContent();
+
+			//4. configure the response object
+			response.setContent(propertyStream);
+			response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+			response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+		} else {
+			// in case there's no value for the property, we can skip the serialization
+			response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+		}
+	}
+
+
+
+	/*
+	 * These processor methods are not handled in this tutorial
+	 * */
+
+	public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+                              ContentType requestFormat, ContentType responseFormat)
+								throws ODataApplicationException, DeserializerException, SerializerException {
+		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+	}
+
+	public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+          throws ODataApplicationException {
+		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+	}
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
new file mode 100755
index 0000000..c21d352
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/util/Util.java
@@ -0,0 +1,105 @@
+/*
+ * 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 myservice.mynamespace.util;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+
+public class Util {
+  
+  public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
+                                  List<UriParameter> keyParams) throws ODataApplicationException {
+
+    List<Entity> entityList = entitySet.getEntities();
+
+    // loop over all entities in order to find that one that matches all keys in request
+    // e.g. contacts(ContactID=1, CompanyID=1)
+    for (Entity entity: entityList) {
+      boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
+      if (foundEntity) {
+        return entity;
+      }
+    }
+
+    return null;
+  }
+
+  public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity entity, List<UriParameter> keyParams)
+          throws ODataApplicationException {
+
+    // loop over all keys
+    for (final UriParameter key : keyParams) {
+      // key
+      String keyName = key.getName();
+      String keyText = key.getText();
+
+      // Edm: we need this info for the comparison below
+      EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName);
+      Boolean isNullable = edmKeyProperty.isNullable();
+      Integer maxLength = edmKeyProperty.getMaxLength();
+      Integer precision = edmKeyProperty.getPrecision();
+      Boolean isUnicode = edmKeyProperty.isUnicode();
+      Integer scale = edmKeyProperty.getScale();
+      // get the EdmType in order to compare
+      EdmType edmType = edmKeyProperty.getType();
+      EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
+
+      // Runtime data: the value of the current entity
+      // don't need to check for null, this is done in olingo library
+      Object valueObject = entity.getProperty(keyName).getValue();
+
+      // now need to compare the valueObject with the keyText String
+      // this is done using the type.valueToString
+      String valueAsString;
+      try {
+        valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode);
+      } catch (EdmPrimitiveTypeException e) {
+        throw new ODataApplicationException("Failed to retrieve String value", HttpStatusCode.INTERNAL_SERVER_ERROR
+                .getStatusCode(), Locale.ENGLISH, e);
+      }
+
+      if (valueAsString == null) {
+        return false;
+      }
+
+      boolean matches = valueAsString.equals(keyText);
+      if (!matches) {
+        // if any of the key properties is not found in the entity, we don't need to search further
+        return false;
+      }
+    }
+
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
new file mode 100755
index 0000000..fe5cdbb
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/web/DemoServlet.java
@@ -0,0 +1,76 @@
+/*
+ * 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 myservice.mynamespace.web;
+
+import java.io.IOException;
+import java.lang.Override;import java.lang.RuntimeException;import java.util.ArrayList;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import myservice.mynamespace.data.Storage;
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.service.DemoEntityCollectionProcessor;
+import myservice.mynamespace.service.DemoEntityProcessor;
+import myservice.mynamespace.service.DemoPrimitiveProcessor;
+
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataHttpHandler;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DemoServlet extends HttpServlet {
+
+  private static final long serialVersionUID = 1L;
+  private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
+
+
+  @Override
+  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+    try {
+      HttpSession session = req.getSession(true);
+      Storage storage = (Storage) session.getAttribute(Storage.class.getName());
+      if (storage == null) {
+        storage = new Storage();
+        session.setAttribute(Storage.class.getName(), storage);
+      }
+
+      // create odata handler and configure it with EdmProvider and Processor
+      OData odata = OData.newInstance();
+      ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
+      ODataHttpHandler handler = odata.createHandler(edm);
+      handler.register(new DemoEntityCollectionProcessor(storage));
+      handler.register(new DemoEntityProcessor(storage));
+      handler.register(new DemoPrimitiveProcessor(storage));
+
+      // let the handler do the work
+      handler.process(req, resp);
+    } catch (RuntimeException e) {
+      LOG.error("Server Error occurred in ExampleServlet", e);
+      throw new ServletException(e);
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml b/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..21de52a
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+				 id="WebApp_ID" version="2.5">
+
+	<!-- Register the HttpServlet implementation -->
+	<servlet>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <servlet-class>myservice.mynamespace.web.DemoServlet</servlet-class>
+	  <load-on-startup>1</load-on-startup>
+	</servlet>
+	
+	<!-- 
+		Our OData service can be invoked at 
+		http://localhost:8080/DemoService/DemoService.svc
+	-->
+	<servlet-mapping>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <url-pattern>/DemoService.svc/*</url-pattern>
+	</servlet-mapping>
+</web-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp b/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
new file mode 100755
index 0000000..7ffb4ba
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions/src/main/webapp/index.jsp
@@ -0,0 +1,26 @@
+<!--
+
+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.
+
+-->
+<html>
+<body>
+<h2>Hello World!</h2>
+<a href="DemoService.svc/">OData Olingo V4 Demo Service</a>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/010d94f7/samples/tutorials/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/pom.xml b/samples/tutorials/pom.xml
index 915fbb5..111e200 100644
--- a/samples/tutorials/pom.xml
+++ b/samples/tutorials/pom.xml
@@ -39,6 +39,7 @@
     <module>p2_readep</module>
     <module>p3_write</module>
     <module>p4_navigation</module>
+    <module>p5_queryoptions</module>
   </modules>
 
   <build>


[06/18] olingo-odata4 git commit: [OLINGO-731] Added html as debug output and refactored structure

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
new file mode 100644
index 0000000..43e9ba6
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabBody.java
@@ -0,0 +1,149 @@
+/*
+ * 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.regex.Pattern;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.debug.DebugSupport;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+/**
+ * Response body debug information.
+ */
+public class DebugTabBody implements DebugTab {
+
+  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 DebugTabBody(final ODataResponse response, final String serviceRoot) {
+    this.response = response;
+    this.serviceRoot = serviceRoot;
+    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 {
+    if (response.getContent() == null) {
+      gen.writeNull();
+    } else {
+      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 = response.getContent() == null ? "ODataLibrary: null body." : getContentString();
+    switch (responseContent) {
+    case XML:
+      writer.append("<pre class=\"code").append("xml").append("\">\n");
+      writer.append(addLinks(DebugResponseHelperImpl.escapeHtml(body)));
+      writer.append("</pre>\n");
+      break;
+    case JSON:
+      writer.append("<pre class=\"code").append("json").append("\">\n");
+      writer.append(addLinks(DebugResponseHelperImpl.escapeHtml(body)));
+      writer.append("</pre>\n");
+      break;
+    case IMAGE:
+      // Make header query case insensitive
+      writer.append("<img src=\"data:").append(response.getHeaders().get(HttpHeader.CONTENT_TYPE)).append(";base64,")
+          .append(body)
+          .append("\" />\n");
+      break;
+    case TEXT:
+    default:
+      writer.append("<pre class=\"code").append("").append("\">\n");
+      writer.append(DebugResponseHelperImpl.escapeHtml(body));
+      writer.append("</pre>\n");
+      break;
+    }
+  }
+
+  private String addLinks(final String source) {
+    final String debugOption = DebugSupport.ODATA_DEBUG_QUERY_PARAMETER + "=" + DebugSupport.ODATA_DEBUG_HTML;
+    final String urlPattern = "("
+        + (responseContent == ResponseContent.XML ?
+            "(?:href|src|base)=" : "\"(?:uri|media_src|edit_media|__next)\":\\p{Space}*")
+        + "\")(.+?)\"";
+    return (responseContent == ResponseContent.XML ?
+        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;");
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabException.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabException.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabException.java
new file mode 100644
index 0000000..6bc69e4
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabException.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.olingo.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 DebugTabException implements DebugTab {
+
+  private final Exception exception;
+
+  public DebugTabException(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", getMessageText(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 getMessageText(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(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(DebugResponseHelperImpl.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/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
new file mode 100644
index 0000000..8eba537
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRequest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.LinkedHashMap;
+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 DebugTabRequest implements DebugTab {
+
+  private final String method;
+  private final String uri;
+  private final String protocol;
+  private final Map<String, String> headers;
+
+  public DebugTabRequest(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 LinkedHashMap<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;
+        }
+      }
+      localHeaders.put(entry.getKey(), value);
+    }
+    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");
+    DebugResponseHelperImpl.appendHtmlTable(writer, headers);
+
+//        .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/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
new file mode 100644
index 0000000..5cb153c
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabResponse.java
@@ -0,0 +1,89 @@
+/*
+ * 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 DebugTabResponse implements DebugTab {
+
+  private final ODataResponse response;
+  private final String serviceRoot;
+  private final HttpStatusCode status;
+  private final Map<String, String> headers;
+
+  public DebugTabResponse(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 DebugTabBody(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");
+    DebugResponseHelperImpl.appendHtmlTable(writer, headers);
+    writer.append("<h2>Response Body</h2>\n");
+    if (response.getContent() != null) {
+      new DebugTabBody(response, serviceRoot).appendHtml(writer);
+    } else {
+      writer.append("<p>ODataLibrary: no response body</p>");
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java
new file mode 100644
index 0000000..312b4cd
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabRuntime.java
@@ -0,0 +1,181 @@
+/*
+ * 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 DebugTabRuntime implements DebugTab {
+
+  private final RuntimeNode rootNode;
+
+  public DebugTabRuntime(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(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/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
new file mode 100644
index 0000000..4eb95ba
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabServer.java
@@ -0,0 +1,57 @@
+/*
+ * 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 DebugTabServer implements DebugTab {
+
+  private final Map<String, String> serverEnvironmentVaribles;
+
+  public DebugTabServer(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 {
+    final Package pack = DebugResponseHelperImpl.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");
+    DebugResponseHelperImpl.appendHtmlTable(writer, serverEnvironmentVaribles);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
new file mode 100644
index 0000000..5c50c0f
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTabUri.java
@@ -0,0 +1,232 @@
+/*
+ * 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.uri.UriInfo;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+
+
+/**
+ * URI parser debug information.
+ */
+public class DebugTabUri implements DebugTab {
+
+  private UriInfo uriInfo;
+
+  public DebugTabUri(UriInfo uriInfo) {
+    this.uriInfo = uriInfo;
+  }
+
+  @Override
+  public String getName() {
+    return "URI";
+  }
+
+  @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 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/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
new file mode 100644
index 0000000..fcf611d
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/ServerCoreDebugger.java
@@ -0,0 +1,137 @@
+/*
+ * 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.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+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.OData;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.debug.DebugInformation;
+import org.apache.olingo.server.api.debug.DebugSupport;
+import org.apache.olingo.server.api.debug.RuntimeMeasurement;
+import org.apache.olingo.server.api.uri.UriInfo;
+
+public class ServerCoreDebugger {
+
+  private final List<RuntimeMeasurement> runtimeInformation = new ArrayList<RuntimeMeasurement>();
+  private final OData odata;
+
+  private boolean isDebugMode = false;
+  private DebugSupport debugSupport;
+  private String debugFormat;
+
+  public ServerCoreDebugger(OData odata) {
+    this.odata = odata;
+  }
+
+  public 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);
+      if (debugFormat != null) {
+        debugSupport.init(odata);
+        isDebugMode = debugSupport.isUserAuthorized();
+      }
+    }
+  }
+
+  public ODataResponse createDebugResponse(final HttpServletRequest request, final Exception exception,
+      final ODataRequest odRequest, final ODataResponse odResponse, UriInfo uriInfo,
+      Map<String, String> serverEnvironmentVaribles) {
+    try {
+      DebugInformation debugInfo =
+          createDebugInformation(request, exception, odRequest, odResponse, uriInfo, serverEnvironmentVaribles);
+
+      return debugSupport.createDebugResponse(debugFormat, debugInfo);
+    } catch (Exception e) {
+      return createFailResponse();
+    }
+  }
+
+  private ODataResponse createFailResponse() {
+    ODataResponse odResponse = new ODataResponse();
+    odResponse.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    odResponse.setHeader(HttpHeader.CONTENT_TYPE, ContentType.TEXT_PLAIN.toContentTypeString());
+    InputStream content = new ByteArrayInputStream("ODataLibrary: Could not assemble debug response.".getBytes());
+    odResponse.setContent(content);
+    return null;
+  }
+
+  private DebugInformation createDebugInformation(final HttpServletRequest request, final Exception exception,
+      final ODataRequest odRequest, final ODataResponse odResponse, UriInfo uriInfo,
+      Map<String, String> serverEnvironmentVaribles) {
+    DebugInformation debugInfo = new DebugInformation();
+    debugInfo.setRequest(odRequest);
+    debugInfo.setApplicationResponse(odResponse);
+
+    debugInfo.setException(exception);
+
+    debugInfo.setServerEnvironmentVaribles(serverEnvironmentVaribles);
+
+    debugInfo.setUriInfo(uriInfo);
+
+    debugInfo.setRuntimeInformation(runtimeInformation);
+    return debugInfo;
+  }
+
+  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);
+      }
+    }
+  }
+
+  public void setDebugSupportProcessor(DebugSupport debugSupport) {
+    this.debugSupport = debugSupport;
+  }
+
+  public boolean isDebugMode() {
+    return isDebugMode;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
index 0b5922c..8b74a88 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
@@ -36,7 +36,6 @@ import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.debug.DefaultDebugSupport;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.edmx.EdmxReferenceInclude;
-import org.apache.olingo.server.tecsvc.async.TechnicalAsyncService;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 import org.apache.olingo.server.tecsvc.processor.TechnicalActionProcessor;
 import org.apache.olingo.server.tecsvc.processor.TechnicalBatchProcessor;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
index 236c1b7..5b347d1 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/ODataHandlerTest.java
@@ -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
@@ -77,6 +77,7 @@ import org.apache.olingo.server.api.processor.ReferenceCollectionProcessor;
 import org.apache.olingo.server.api.processor.ReferenceProcessor;
 import org.apache.olingo.server.api.processor.ServiceDocumentProcessor;
 import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
 import org.apache.olingo.server.tecsvc.provider.ContainerProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.junit.Test;
@@ -233,7 +234,8 @@ public class ODataHandlerTest {
     request.setMethod(HttpMethod.GET);
     request.setRawODataPath("EdmException");
 
-    final ODataResponse response = new ODataHandler(odata, serviceMetadata).process(request);
+    final ODataResponse response =
+        new ODataHandler(odata, serviceMetadata, new ServerCoreDebugger(odata)).process(request);
     assertNotNull(response);
     assertEquals(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode(), response.getStatusCode());
   }
@@ -720,7 +722,7 @@ public class ODataHandlerTest {
     final ServiceMetadata metadata = odata.createServiceMetadata(
         new EdmTechProvider(), Collections.<EdmxReference> emptyList());
 
-    ODataHandler handler = new ODataHandler(odata, metadata);
+    ODataHandler handler = new ODataHandler(odata, metadata, new ServerCoreDebugger(odata));
 
     if (processor != null) {
       handler.register(processor);


[16/18] olingo-odata4 git commit: Merge branch 'master' into olingo640

Posted by ch...@apache.org.
Merge branch 'master' into olingo640

Conflicts:
	fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
	lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java


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

Branch: refs/heads/OLINGO-640
Commit: 366597070f08f7435eca9b2394c3f53612efd1d5
Parents: 5b99eb7 9558233
Author: Christian Amend <ch...@sap.com>
Authored: Tue Aug 4 14:38:01 2015 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Aug 4 14:38:01 2015 +0200

----------------------------------------------------------------------
 .../fit/tecsvc/client/AsyncSupportITCase.java   | 104 +++++++
 .../fit/tecsvc/client/NavigationITCase.java     |  39 ++-
 .../fit/tecsvc/http/BasicAsyncITCase.java       | 238 ++++++++++++++++
 .../apache/olingo/fit/util/StringHelper.java    | 214 +++++++++++++++
 fit/src/test/resources/basicBatchPost.batch     |  33 +++
 .../olingo/client/api/data/ServiceDocument.java |   4 +-
 .../client/core/data/ServiceDocumentImpl.java   |  53 +++-
 .../core/data/ServiceDocumentItemImpl.java      |  32 ++-
 .../client/core/domain/ClientPropertyImpl.java  |  39 ++-
 .../client/core/domain/ClientValuableImpl.java  |  27 +-
 .../olingo/commons/api/data/ContextURL.java     |  15 +-
 .../commons/api/edm/FullQualifiedName.java      |  32 ++-
 .../apache/olingo/commons/api/edm/geo/SRID.java |  54 +++-
 .../apache/olingo/server/api/ODataRequest.java  |  22 +-
 .../apache/olingo/server/api/ODataResponse.java |   2 +-
 .../server/api/debug/DebugInformation.java      | 118 ++++++++
 .../server/api/debug/DebugResponseHelper.java   |   6 +-
 .../olingo/server/api/debug/DebugSupport.java   |   7 +-
 .../server/api/debug/DefaultDebugSupport.java   |  13 +-
 .../server/api/debug/RuntimeMeasurement.java    | 106 +++++++
 .../olingo/server/core/ServiceHandler.java      |  15 +
 .../core/legacy/ProcessorServiceHandler.java    |   7 +
 .../server/core/requests/DataRequest.java       |   2 +-
 .../olingo/server/example/TripPinHandler.java   |  12 +
 lib/server-core/pom.xml                         |  10 +-
 .../apache/olingo/server/core/ODataHandler.java |  53 ++--
 .../server/core/ODataHttpHandlerImpl.java       |  68 +++--
 .../apache/olingo/server/core/ODataImpl.java    |   2 +-
 .../core/debug/DebugResponseHelperImpl.java     | 247 ++++++++++++++++-
 .../olingo/server/core/debug/DebugTab.java      |  50 ++++
 .../olingo/server/core/debug/DebugTabBody.java  | 154 +++++++++++
 .../server/core/debug/DebugTabException.java    | 136 +++++++++
 .../server/core/debug/DebugTabRequest.java      | 128 +++++++++
 .../server/core/debug/DebugTabResponse.java     |  99 +++++++
 .../server/core/debug/DebugTabRuntime.java      | 181 ++++++++++++
 .../server/core/debug/DebugTabServer.java       |  63 +++++
 .../olingo/server/core/debug/DebugTabUri.java   | 232 ++++++++++++++++
 .../server/core/debug/ServerCoreDebugger.java   | 142 ++++++++++
 .../json/ODataJsonDeserializer.java             | 275 +++++++++++--------
 .../serializer/BatchResponseSerializer.java     |   1 -
 .../serializer/utils/ContextURLBuilder.java     |   9 +
 .../core/serializer/utils/ContextURLHelper.java |  30 ++
 .../serializer/utils/ExpandSelectHelper.java    |  11 +-
 .../core/uri/parser/UriParseTreeVisitor.java    |  29 +-
 .../server/core/debug/AbstractDebugTabTest.java |  58 ++++
 .../server/core/debug/DebugTabBodyTest.java     |  37 +++
 .../server/core/debug/DebugTabRequestTest.java  | 155 +++++++++++
 .../server/core/debug/DebugTabResponseTest.java |  79 ++++++
 .../server/core/debug/DebugTabServerTest.java   |  84 ++++++
 .../core/debug/ServerCoreDebuggerTest.java      | 121 ++++++++
 lib/server-tecsvc/pom.xml                       |   1 -
 .../olingo/server/tecsvc/TechnicalServlet.java  |   1 -
 .../processor/TechnicalBatchProcessor.java      |  17 ++
 .../processor/TechnicalEntityProcessor.java     |  98 ++++---
 lib/server-test/pom.xml                         |   1 -
 .../olingo/server/core/ODataHandlerTest.java    |  10 +-
 .../json/ODataJsonDeserializerEntityTest.java   |  50 ++++
 .../serializer/utils/ContextURLHelperTest.java  |  86 ++++++
 .../core/uri/antlr/TestFullResourcePath.java    |  56 +++-
 samples/tutorials/p5_queryoptions-tis/pom.xml   |  79 ++++++
 .../myservice/mynamespace/data/Storage.java     | 130 +++++++++
 .../mynamespace/service/DemoEdmProvider.java    | 154 +++++++++++
 .../service/DemoEntityCollectionProcessor.java  | 142 ++++++++++
 .../service/DemoEntityProcessor.java            | 118 ++++++++
 .../service/DemoPrimitiveProcessor.java         | 150 ++++++++++
 .../java/myservice/mynamespace/util/Util.java   | 105 +++++++
 .../myservice/mynamespace/web/DemoServlet.java  |  76 +++++
 .../src/main/webapp/WEB-INF/web.xml             |  40 +++
 .../src/main/webapp/index.jsp                   |  26 ++
 samples/tutorials/p6_queryoptions-es/pom.xml    |  80 ++++++
 .../myservice/mynamespace/data/Storage.java     | 252 +++++++++++++++++
 .../mynamespace/service/DemoEdmProvider.java    | 211 ++++++++++++++
 .../service/DemoEntityCollectionProcessor.java  | 160 +++++++++++
 .../service/DemoEntityProcessor.java            | 235 ++++++++++++++++
 .../service/DemoPrimitiveProcessor.java         | 150 ++++++++++
 .../java/myservice/mynamespace/util/Util.java   | 149 ++++++++++
 .../myservice/mynamespace/web/DemoServlet.java  |  75 +++++
 .../src/main/webapp/WEB-INF/web.xml             |  34 +++
 .../src/main/webapp/index.jsp                   |  43 +++
 samples/tutorials/pom.xml                       |   2 +
 80 files changed, 6057 insertions(+), 322 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/36659707/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
----------------------------------------------------------------------
diff --cc fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
index f129976,40c1de4..a153f06
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
@@@ -20,7 -20,8 +20,10 @@@ package org.apache.olingo.fit.tecsvc.cl
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
+ import static org.junit.Assert.assertTrue;
+ 
++import java.io.InputStream;
 +
  import org.apache.olingo.client.api.ODataClient;
  import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
  import org.apache.olingo.client.api.domain.ClientEntity;
@@@ -31,23 -32,49 +34,57 @@@ import org.apache.olingo.commons.api.fo
  import org.apache.olingo.commons.api.http.HttpStatusCode;
  import org.apache.olingo.fit.AbstractBaseTestITCase;
  import org.apache.olingo.fit.tecsvc.TecSvcConst;
+ import org.apache.olingo.fit.util.StringHelper;
 +import org.junit.Assert;
  import org.junit.Test;
  
- public class NavigationITCase extends AbstractBaseTestITCase {
 -import java.io.InputStream;
 -
+ public final class NavigationITCase extends AbstractBaseTestITCase {
  
    private final ODataClient client = getClient();
  
 +  
 +  void assertShortOrInt(int value, Object n) {
 +    if (n instanceof Number) {
 +      assertEquals(value, ((Number)n).intValue());
 +    } else {
 +      Assert.fail();
 +    }
 +  }
 +  
    @Test
+   public void navigationToEntityWithRelativeContextUrl() throws Exception {
+     // zero navigation
+     final InputStream zeroLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+             client.newURIBuilder(TecSvcConst.BASE_URI)
+                     .appendEntitySetSegment("ESAllPrim").
+                     appendKeySegment(32767).build()).rawExecute();
+ 
+     String zeroLevelResponseBody = StringHelper.asString(zeroLevelResponse);
+     assertTrue(zeroLevelResponseBody.contains("\"@odata.context\":\"$metadata#ESAllPrim/$entity\""));
+ 
+     // one navigation
+     final InputStream oneLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+                     client.newURIBuilder(TecSvcConst.BASE_URI)
+                             .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767)
+                             .appendNavigationSegment("NavPropertyETTwoPrimOne").build())
+                     .rawExecute();
+ 
+     String oneLevelResponseBody = StringHelper.asString(oneLevelResponse);
+     assertTrue(oneLevelResponseBody.contains("\"@odata.context\":\"../$metadata#ESTwoPrim/$entity\""));
+ 
+     // two navigation
+     final InputStream twoLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+                     client.newURIBuilder(TecSvcConst.BASE_URI)
+                             .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767)
+                             .appendNavigationSegment("NavPropertyETAllPrimOne")
+                             .appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build())
+                     .rawExecute();
+ 
+     String twoLevelResponseBody = StringHelper.asString(twoLevelResponse);
+     assertTrue(twoLevelResponseBody.contains("\"@odata.context\":\"../../$metadata#ESTwoPrim/$entity\""));
+   }
+ 
+   @Test
    public void oneLevelToEntity() throws Exception {
      final ODataRetrieveResponse<ClientEntity> response =
          client.getRetrieveRequestFactory().getEntityRequest(

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/36659707/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/36659707/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/TechnicalServlet.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/36659707/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --cc lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index 06f450d,a47f367..315623f
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@@ -147,7 -147,7 +147,7 @@@ public class TechnicalEntityProcessor e
      checkRequestFormat(requestFormat);
  
      //
--    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
++    if (odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
        TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
        TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
        processor.init(odata, serviceMetadata);
@@@ -161,7 -161,7 +161,6 @@@
      }
      //
  
--
      final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
      final EdmEntitySet edmEntitySet = resourceEntitySet.getEntitySet();
      final EdmEntityType edmEntityType = edmEntitySet.getEntityType();
@@@ -173,7 -173,7 +172,7 @@@
        dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()),
            requestFormat.toContentTypeString());
      } else {
--      final DeserializerResult deserializerResult = 
++      final DeserializerResult deserializerResult =
            odata.createDeserializer(requestFormat).entity(request.getBody(), edmEntityType);
        new RequestValidator(dataProvider, request.getRawBaseUri())
            .validate(edmEntitySet, deserializerResult.getEntity());
@@@ -187,8 -187,8 +186,8 @@@
          + odata.createUriHelper().buildCanonicalURL(edmEntitySet, entity);
      final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
      if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
-       response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
-               .getContent());
+       response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
 -              .getContent());
++          .getContent());
        response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
        response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
      } else {
@@@ -238,13 -238,13 +237,13 @@@
          request.getRawBaseUri()).validate(edmEntitySet, changedEntity);
  
      dataProvider.update(request.getRawBaseUri(), edmEntitySet, entity, changedEntity,
--            request.getMethod() == HttpMethod.PATCH, false);
++        request.getMethod() == HttpMethod.PATCH, false);
  
      final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
      if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
        response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-       response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
-               .getContent());
+       response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat)
 -              .getContent());
++          .getContent());
        response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
      } else {
        response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
@@@ -275,8 -275,8 +274,8 @@@
  
      final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
      if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
-       response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
+       response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat)
 -              .getContent());
 +          .getContent());
        response.setStatusCode(HttpStatusCode.OK.getStatusCode());
        response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
      } else {
@@@ -360,7 -360,7 +359,7 @@@
      final UriResourceNavigation navigationProperty = getLastNavigation(uriInfo);
      ensureNavigationPropertyNotNull(navigationProperty);
      dataProvider.createReference(entity, navigationProperty.getProperty(), references.getEntityReferences().get(0),
--            request.getRawBaseUri());
++        request.getRawBaseUri());
  
      response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
    }
@@@ -371,7 -371,7 +370,7 @@@
  
      final UriResourceNavigation lastNavigation = getLastNavigation(uriInfo);
      final IdOption idOption = uriInfo.getIdOption();
--    
++
      ensureNavigationPropertyNotNull(lastNavigation);
      if (lastNavigation.isCollection() && idOption == null) {
        throw new ODataApplicationException("Id system query option must be provided",
@@@ -393,8 -393,9 +392,9 @@@
    }
  
    @Override
-   public void readReferenceCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-       final ContentType requestedContentType) throws ODataApplicationException, ODataLibraryException {
+   public void readReferenceCollection(final ODataRequest request, final ODataResponse response,
 -                                      final UriInfo uriInfo, final ContentType requestedContentType)
 -          throws ODataApplicationException, ODataLibraryException {
++      final UriInfo uriInfo, final ContentType requestedContentType)
++      throws ODataApplicationException, ODataLibraryException {
      readEntityCollection(request, response, uriInfo, requestedContentType, true);
    }
  
@@@ -402,7 -403,7 +402,7 @@@
        final ContentType requestedFormat, final boolean isReference)
        throws ODataApplicationException, ODataLibraryException {
      //
--    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
++    if (odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
        TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
        TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
        processor.init(odata, serviceMetadata);
@@@ -454,7 -455,7 +454,7 @@@
        final UriInfo uriInfo, final ContentType requestedContentType, final boolean isReference)
        throws ODataApplicationException, ODataLibraryException {
      //
--    if(odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
++    if (odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).hasRespondAsync()) {
        TechnicalAsyncService asyncService = TechnicalAsyncService.getInstance();
        TechnicalEntityProcessor processor = new TechnicalEntityProcessor(dataProvider, serviceMetadata);
        processor.init(odata, serviceMetadata);
@@@ -513,12 -514,12 +513,12 @@@
      expandHandler.applyExpandQueryOptions(entitySetSerialization, edmEntitySet, expand);
      final CountOption countOption = uriInfo.getCountOption();
  
-     final String id = request.getRawBaseUri()+edmEntitySet.getName();
++    final String id = request.getRawBaseUri() + edmEntitySet.getName();
      // Serialize
--    final SerializerResult serializerResult = (isReference) ? 
++    final SerializerResult serializerResult = (isReference) ?
          serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption) :
-         serializeEntityCollection(entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
+         serializeEntityCollection(request, entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
 -            expand, select, countOption);
 -
 +            expand, select, countOption, id);
      response.setContent(serializerResult.getContent());
      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
      response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
@@@ -528,59 -529,74 +528,73 @@@
      }
    }
  
-   private SerializerResult serializeEntityCollection(final EntityCollection entityCollection,
-       final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat,
-       final ExpandOption expand, final SelectOption select, final CountOption countOption, String id)
-       throws ODataLibraryException {
-     
+   private SerializerResult serializeEntityCollection(final ODataRequest request, final EntityCollection
 -          entityCollection,
 -      final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat,
 -      final ExpandOption expand, final SelectOption select, final CountOption countOption)
 -      throws ODataLibraryException {
++      entityCollection, final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
++      final ContentType requestedFormat, final ExpandOption expand, final SelectOption select,
++      final CountOption countOption, String id) throws ODataLibraryException {
+ 
      return odata.createSerializer(requestedFormat).entityCollection(
 -            serviceMetadata,
 -            edmEntityType,
 -            entityCollection,
 -            EntityCollectionSerializerOptions.with()
 -                    .contextURL(isODataMetadataNone(requestedFormat) ? null :
 -                            getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand,
 -                                    select))
 -                    .count(countOption)
 -                    .expand(expand).select(select)
 -                    .build());
 +        serviceMetadata,
 +        edmEntityType,
 +        entityCollection,
 +        EntityCollectionSerializerOptions.with()
 +            .contextURL(isODataMetadataNone(requestedFormat) ? null :
-                 getContextUrl(edmEntitySet, edmEntityType, false, expand, select))
++                getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand, select))
 +            .count(countOption)
 +            .expand(expand).select(select)
 +            .setId(id)
 +            .build());
    }
  
--  private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection, 
--      final EdmEntitySet edmEntitySet, final ContentType requestedFormat, final CountOption countOption) 
--          throws ODataLibraryException {
++  private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection,
++      final EdmEntitySet edmEntitySet, final ContentType requestedFormat, final CountOption countOption)
++      throws ODataLibraryException {
  
      return odata.createSerializer(requestedFormat)
-         .referenceCollection(serviceMetadata, edmEntitySet, entityCollection,ReferenceCollectionSerializerOptions.with()
-             .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
-             .count(countOption).build());
+         .referenceCollection(serviceMetadata, edmEntitySet, entityCollection,
 -                ReferenceCollectionSerializerOptions.with()
 -                        .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
 -                        .count(countOption).build());
++            ReferenceCollectionSerializerOptions.with()
++                .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
++                .count(countOption).build());
    }
  
    private SerializerResult serializeReference(final Entity entity, final EdmEntitySet edmEntitySet,
        final ContentType requestedFormat) throws ODataLibraryException {
      return odata.createSerializer(requestedFormat)
          .reference(serviceMetadata, edmEntitySet, entity, ReferenceSerializerOptions.with()
 -                .contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
 -            
 +            .contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
-             
++
    }
  
-   private SerializerResult serializeEntity(final Entity entity,
-       final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat,
-       final ExpandOption expand, final SelectOption select) throws ODataLibraryException {
+   private SerializerResult serializeEntity(final ODataRequest request, final Entity entity,
 -                                           final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
 -                                           final ContentType requestedFormat) throws ODataLibraryException {
++      final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
++      final ContentType requestedFormat) throws ODataLibraryException {
+     return serializeEntity(request, entity, edmEntitySet, edmEntityType, requestedFormat, null, null);
+   }
+ 
+   private SerializerResult serializeEntity(final ODataRequest request, final Entity entity,
 -                                           final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
 -                                           final ContentType requestedFormat,
 -                                           final ExpandOption expand, final SelectOption select)
 -          throws ODataLibraryException {
++      final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
++      final ContentType requestedFormat,
++      final ExpandOption expand, final SelectOption select)
++      throws ODataLibraryException {
+ 
+     ContextURL contextUrl = isODataMetadataNone(requestedFormat) ? null :
 -          getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, true, expand, null);
++        getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, true, expand, null);
      return odata.createSerializer(requestedFormat).entity(
 -            serviceMetadata,
 -            edmEntityType,
 -            entity,
 -            EntitySerializerOptions.with()
 -                    .contextURL(contextUrl)
 -                    .expand(expand).select(select)
 -                    .build());
 +        serviceMetadata,
 +        edmEntityType,
 +        entity,
 +        EntitySerializerOptions.with()
-             .contextURL(isODataMetadataNone(requestedFormat) ? null :
-                 getContextUrl(edmEntitySet, edmEntityType, true, expand, select))
++            .contextURL(contextUrl)
 +            .expand(expand).select(select)
 +            .build());
    }
  
-   private ContextURL getContextUrl(final EdmEntitySet entitySet, final EdmEntityType entityType,
-       final boolean isSingleEntity, final ExpandOption expand, final SelectOption select) throws ODataLibraryException {
-     Builder builder = ContextURL.with();
+   private ContextURL getContextUrl(String rawODataPath, final EdmEntitySet entitySet, final EdmEntityType entityType,
 -                                   final boolean isSingleEntity, final ExpandOption expand, final SelectOption select)
 -          throws ODataLibraryException {
++      final boolean isSingleEntity, final ExpandOption expand, final SelectOption select)
++      throws ODataLibraryException {
+     //
+     //
+     Builder builder = ContextURL.with().oDataPath(rawODataPath);
      builder = entitySet == null ?
          isSingleEntity ? builder.type(entityType) : builder.asCollection().type(entityType) :
          builder.entitySet(entitySet);
@@@ -589,10 -605,10 +603,10 @@@
          .suffix(isSingleEntity && entitySet != null ? Suffix.ENTITY : null);
      return builder.build();
    }
--  
++
    private void ensureNavigationPropertyNotNull(final UriResourceNavigation navigationProperty)
        throws ODataApplicationException {
--    if(navigationProperty == null) {
++    if (navigationProperty == null) {
        throw new ODataApplicationException("Missing navigation segment", HttpStatusCode.BAD_REQUEST.getStatusCode(),
            Locale.ROOT);
      }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/36659707/lib/server-test/pom.xml
----------------------------------------------------------------------
diff --cc lib/server-test/pom.xml
index 3173137,f698028..5edc346
--- a/lib/server-test/pom.xml
+++ b/lib/server-test/pom.xml
@@@ -66,13 -66,7 +66,12 @@@
      <dependency>
        <groupId>commons-io</groupId>
        <artifactId>commons-io</artifactId>
-       <scope>test</scope>
      </dependency>
 +    <dependency>
 +      <groupId>xmlunit</groupId>
 +      <artifactId>xmlunit</artifactId>
 +      <scope>test</scope>
 +    </dependency>    
    </dependencies>
  
    <build>


[03/18] olingo-odata4 git commit: OLINGO-650: supporting the complex properties in expand context url generation

Posted by ch...@apache.org.
OLINGO-650: supporting the complex properties in expand context url generation


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

Branch: refs/heads/OLINGO-640
Commit: 8f763aadea9730ddf518663a24da3d56aa2ae2e8
Parents: cb0f7f2
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Tue Jun 2 12:12:57 2015 -0500
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Thu Jul 23 18:48:34 2015 -0500

----------------------------------------------------------------------
 .../core/serializer/utils/ContextURLHelper.java | 30 ++++++++++++++++++++
 .../serializer/utils/ExpandSelectHelper.java    | 11 ++-----
 .../serializer/utils/ContextURLHelperTest.java  | 16 +++++++++++
 3 files changed, 49 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8f763aad/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelper.java
index 421c6eb..f6c2ae3 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelper.java
@@ -29,6 +29,8 @@ import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.commons.core.Encoder;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@@ -117,11 +119,39 @@ public final class ContextURLHelper {
             }
             result.append(Encoder.encode(propertyName)).append('(').append(innerSelectList).append(')');
           }
+        } else {
+          final List<UriResource> resourceParts = expandItem.getResourcePath().getUriResourceParts();
+          if(resourceParts.size() > 1) {
+            if (result.length() > 0) {
+              result.append(',');
+            }            
+            final List<String> path = getPropertyPath(resourceParts);
+            String propertyPath = buildPropertyPath(path);            
+            result.append(Encoder.encode(propertyName));
+            result.append("/").append(propertyPath);
+          }
         }
       }
     }
   }
 
+  private static List<String> getPropertyPath(final List<UriResource> path) {
+    List<String> result = new LinkedList<String>();
+    int index = 1;
+    while (index < path.size() && path.get(index) instanceof UriResourceProperty) {
+      result.add(((UriResourceProperty) path.get(index)).getProperty().getName());
+      index++;
+    }
+    return result;
+  }
+
+  private static String buildPropertyPath(final List<String> path) {
+    StringBuilder result = new StringBuilder();
+    for (final String segment : path) {
+      result.append(result.length() == 0 ? "" : '/').append(Encoder.encode(segment)); //$NON-NLS-1$
+    }
+    return result.length() == 0?null:result.toString();
+  }  
   private static List<List<String>> getComplexSelectedPaths(final EdmProperty edmProperty,
       final Set<List<String>> selectedPaths) {
     List<List<String>> result = new ArrayList<List<String>>();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8f763aad/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
index 3acdbd3..30810f0 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ExpandSelectHelper.java
@@ -127,14 +127,9 @@ public abstract class ExpandSelectHelper {
     Set<String> expanded = new HashSet<String>();
     for (final ExpandItem item : expandItems) {
       final List<UriResource> resourceParts = item.getResourcePath().getUriResourceParts();
-      if (resourceParts.size() == 1) {
-        final UriResource resource = resourceParts.get(0);
-        if (resource instanceof UriResourceNavigation) {
-          expanded.add(((UriResourceNavigation) resource).getProperty().getName());
-        }
-      } else {
-        throw new SerializerException("Expand is not supported within complex properties.",
-            SerializerException.MessageKeys.NOT_IMPLEMENTED);
+      final UriResource resource = resourceParts.get(0);
+      if (resource instanceof UriResourceNavigation) {
+        expanded.add(((UriResourceNavigation) resource).getProperty().getName());
       }
     }
     return expanded;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/8f763aad/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
index 2416fbe..b94f97e 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
@@ -117,6 +117,22 @@ public class ContextURLHelperTest {
   }
 
   @Test
+  public void buildExpandWithNavigationProperty() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
+    final ExpandOption expand = ExpandSelectMock.mockExpandOption(Arrays.asList(
+        ExpandSelectMock.mockExpandItem(entitySet, "NavPropertyETAllPrimOne", "PropertyString")));
+    final SelectItem selectItem1 = ExpandSelectMock.mockSelectItem(entitySet, "PropertyInt16");
+    final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
+        selectItem1));
+    
+    final ContextURL contextURL = ContextURL.with().entitySet(entitySet)
+        .selectList(ContextURLHelper.buildSelectList(entitySet.getEntityType(), expand, select)).build();
+    assertEquals("$metadata#ESTwoPrim(PropertyInt16,NavPropertyETAllPrimOne/PropertyString)", 
+        ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
+  
+  @Test
   public void buildExpandSelect() throws Exception {
     final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
     final ExpandItem expandItem1 = ExpandSelectMock.mockExpandItem(entitySet, "NavPropertyETAllPrimOne");


[17/18] olingo-odata4 git commit: [OLINGO-640] Minor adjustments to tests and deleted logger

Posted by ch...@apache.org.
http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/db0b9d39/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
index abce52d..50d432c 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializerTest.java
@@ -18,8 +18,10 @@
  */
 package org.apache.olingo.server.core.serializer.xml;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.URI;
+import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.Collections;
@@ -63,6 +65,9 @@ import org.apache.olingo.server.core.uri.UriHelperImpl;
 import org.apache.olingo.server.tecsvc.MetadataETagSupport;
 import org.apache.olingo.server.tecsvc.data.DataProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.Difference;
+import org.custommonkey.xmlunit.DifferenceListener;
 import org.custommonkey.xmlunit.XMLAssert;
 import org.custommonkey.xmlunit.XMLUnit;
 import org.hamcrest.CoreMatchers;
@@ -70,11 +75,17 @@ import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
 
-public class ODataXmlSerializerTest  {
+public class ODataXmlSerializerTest {
   private static final ServiceMetadata metadata = new ServiceMetadataImpl(
       new EdmTechProvider(), Collections.<EdmxReference> emptyList(), new MetadataETagSupport("WmetadataETag"));
   private static final EdmEntityContainer entityContainer = metadata.getEdm().getEntityContainer();
+  private static final DifferenceListener DIFFERENCE_LISTENER = new CustomDifferenceListener();
+  private static final int MAX_ALLOWED_UPDATED_DIFFERENCE = 2000;
+  private static final String UPDATED_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+  
   private final DataProvider data = new DataProvider(metadata.getEdm());
   private final ODataSerializer serializer = new ODataXmlSerializer();
   private final UriHelper helper = new UriHelperImpl();
@@ -87,69 +98,70 @@ public class ODataXmlSerializerTest  {
     XMLUnit.setNormalizeWhitespace(true);
     XMLUnit.setCompareUnmatched(false);
   }
-  
+
   @Test
   public void entitySimple() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
             .build()).getContent();
     final String resultString = IOUtils.toString(result);
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
         "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\" "
-        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "
-        + "m:context=\"$metadata#ESAllPrim/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESAllPrim(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-        .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\" />\n" + 
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" + 
-        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" + 
-        "    href=\"ESTwoPrim(32767)\" />\n" + 
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" + 
-        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" + 
-        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +         
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "      <d:PropertyString>First Resource - positive values</d:PropertyString>\n" + 
-        "      <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" + 
-        "      <d:PropertyByte m:type=\"Byte\">255</d:PropertyByte>\n" + 
-        "      <d:PropertySByte m:type=\"SByte\">127</d:PropertySByte>\n" + 
-        "      <d:PropertyInt32 m:type=\"Int32\">2147483647</d:PropertyInt32>\n" + 
-        "      <d:PropertyInt64 m:type=\"Int64\">9223372036854775807\n" + 
-        "      </d:PropertyInt64>\n" + 
-        "      <d:PropertySingle m:type=\"Single\">1.79E20</d:PropertySingle>\n" + 
-        "      <d:PropertyDouble m:type=\"Double\">-1.79E19</d:PropertyDouble>\n" + 
-        "      <d:PropertyDecimal m:type=\"Decimal\">34</d:PropertyDecimal>\n" + 
-        "      <d:PropertyBinary m:type=\"Binary\">ASNFZ4mrze8=\n" + 
-        "      </d:PropertyBinary>\n" + 
-        "      <d:PropertyDate m:type=\"Date\">2012-12-03</d:PropertyDate>\n" + 
-        "      <d:PropertyDateTimeOffset m:type=\"DateTimeOffset\">2012-12-03T07:16:23Z\n" + 
-        "      </d:PropertyDateTimeOffset>\n" + 
-        "      <d:PropertyDuration m:type=\"Duration\">PT6S\n" + 
-        "      </d:PropertyDuration>\n" + 
-        "      <d:PropertyGuid m:type=\"Guid\">01234567-89ab-cdef-0123-456789abcdef\n" + 
-        "      </d:PropertyGuid>\n" + 
-        "      <d:PropertyTimeOfDay m:type=\"TimeOfDay\">03:26:05\n" + 
-        "      </d:PropertyTimeOfDay>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
+        + "m:context=\"$metadata#ESAllPrim/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESAllPrim(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\" />\n" +
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" +
+        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" +
+        "    href=\"ESTwoPrim(32767)\" />\n" +
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" +
+        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" +
+        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "      <d:PropertyString>First Resource - positive values</d:PropertyString>\n" +
+        "      <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" +
+        "      <d:PropertyByte m:type=\"Byte\">255</d:PropertyByte>\n" +
+        "      <d:PropertySByte m:type=\"SByte\">127</d:PropertySByte>\n" +
+        "      <d:PropertyInt32 m:type=\"Int32\">2147483647</d:PropertyInt32>\n" +
+        "      <d:PropertyInt64 m:type=\"Int64\">9223372036854775807\n" +
+        "      </d:PropertyInt64>\n" +
+        "      <d:PropertySingle m:type=\"Single\">1.79E20</d:PropertySingle>\n" +
+        "      <d:PropertyDouble m:type=\"Double\">-1.79E19</d:PropertyDouble>\n" +
+        "      <d:PropertyDecimal m:type=\"Decimal\">34</d:PropertyDecimal>\n" +
+        "      <d:PropertyBinary m:type=\"Binary\">ASNFZ4mrze8=\n" +
+        "      </d:PropertyBinary>\n" +
+        "      <d:PropertyDate m:type=\"Date\">2012-12-03</d:PropertyDate>\n" +
+        "      <d:PropertyDateTimeOffset m:type=\"DateTimeOffset\">2012-12-03T07:16:23Z\n" +
+        "      </d:PropertyDateTimeOffset>\n" +
+        "      <d:PropertyDuration m:type=\"Duration\">PT6S\n" +
+        "      </d:PropertyDuration>\n" +
+        "      <d:PropertyGuid m:type=\"Guid\">01234567-89ab-cdef-0123-456789abcdef\n" +
+        "      </d:PropertyGuid>\n" +
+        "      <d:PropertyTimeOfDay m:type=\"TimeOfDay\">03:26:05\n" +
+        "      </d:PropertyTimeOfDay>\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
         "</a:entry>";
-    XMLAssert.assertXMLEqual(expected, resultString);
+    checkXMLEqual(expected, resultString);
   }
 
   @Test
@@ -157,60 +169,62 @@ public class ODataXmlSerializerTest  {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
-    final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(),
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream content = serializer.entity(metadata, edmEntitySet.getEntityType(),
         entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
-            .build()).getContent());
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
-        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "+
-        "m:context=\"$metadata#ESAllPrim/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESAllPrim(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\"/>\n" + 
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" + 
-        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" + 
+            .build()).getContent();
+    final String resultString = IOUtils.toString(content);
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
+        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" " +
+        "m:context=\"$metadata#ESAllPrim/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESAllPrim(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\"/>\n" +
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" +
+        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" +
         "    href=\"ESTwoPrim(32767)\" />\n" +
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" + 
-        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" + 
-        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +         
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "      <d:PropertyString m:null=\"true\" />\n" + 
-        "      <d:PropertyBoolean m:null=\"true\" />\n" + 
-        "      <d:PropertyByte m:null=\"true\" />\n" + 
-        "      <d:PropertySByte m:null=\"true\" />\n" + 
-        "      <d:PropertyInt32 m:null=\"true\" />\n" + 
-        "      <d:PropertyInt64 m:null=\"true\" />\n" + 
-        "      <d:PropertySingle m:null=\"true\" />\n" + 
-        "      <d:PropertyDouble m:null=\"true\" />\n" + 
-        "      <d:PropertyDecimal m:null=\"true\" />\n" + 
-        "      <d:PropertyBinary m:null=\"true\" />\n" + 
-        "      <d:PropertyDate m:null=\"true\" />\n" + 
-        "      <d:PropertyDateTimeOffset\n" + 
-        "        m:null=\"true\" />\n" + 
-        "      <d:PropertyDuration m:null=\"true\" />\n" + 
-        "      <d:PropertyGuid m:null=\"true\" />\n" + 
-        "      <d:PropertyTimeOfDay m:null=\"true\" />\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
-        "</a:entry>\n" + 
-        "";    
-    XMLAssert.assertXMLEqual(expected, resultString);
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" +
+        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" +
+        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "      <d:PropertyString m:null=\"true\" />\n" +
+        "      <d:PropertyBoolean m:null=\"true\" />\n" +
+        "      <d:PropertyByte m:null=\"true\" />\n" +
+        "      <d:PropertySByte m:null=\"true\" />\n" +
+        "      <d:PropertyInt32 m:null=\"true\" />\n" +
+        "      <d:PropertyInt64 m:null=\"true\" />\n" +
+        "      <d:PropertySingle m:null=\"true\" />\n" +
+        "      <d:PropertyDouble m:null=\"true\" />\n" +
+        "      <d:PropertyDecimal m:null=\"true\" />\n" +
+        "      <d:PropertyBinary m:null=\"true\" />\n" +
+        "      <d:PropertyDate m:null=\"true\" />\n" +
+        "      <d:PropertyDateTimeOffset\n" +
+        "        m:null=\"true\" />\n" +
+        "      <d:PropertyDuration m:null=\"true\" />\n" +
+        "      <d:PropertyGuid m:null=\"true\" />\n" +
+        "      <d:PropertyTimeOfDay m:null=\"true\" />\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
+        "</a:entry>\n" +
+        "";
+    checkXMLEqual(expected, resultString);
   }
 
   @Test(expected = SerializerException.class)
@@ -254,7 +268,7 @@ public class ODataXmlSerializerTest  {
     InputStream result = serializer.entityCollection(metadata, edmEntitySet.getEntityType(), entitySet,
         EntityCollectionSerializerOptions.with()
             .contextURL(ContextURL.with().serviceRoot(new URI("http://host:port"))
-            .entitySet(edmEntitySet).build())
+                .entitySet(edmEntitySet).build())
             .setId("http://host/svc/ESCompAllPrim")
             .count(countOption)
             .build()).getContent();
@@ -277,228 +291,231 @@ public class ODataXmlSerializerTest  {
   public void entityCollAllPrim() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().serviceRoot(URI.create("http://host/service/"))
                 .entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
             .build()).getContent();
     final String resultString = IOUtils.toString(result);
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
         "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\" "
-        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "
-        + "m:context=\"http://host/service/$metadata#ESCollAllPrim/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESCollAllPrim(1)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "<a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-        .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESCollAllPrim(1)\" />\n" + 
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETCollAllPrim\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" + 
-        "      <d:CollPropertyString m:type=\"#Collection(String)\">\n" + 
-        "        <m:element>Employee1@company.example</m:element>\n" + 
-        "        <m:element>Employee2@company.example</m:element>\n" + 
-        "        <m:element>Employee3@company.example</m:element>\n" + 
-        "      </d:CollPropertyString>\n" + 
-        "      <d:CollPropertyBoolean m:type=\"#Collection(Boolean)\">\n" + 
-        "        <m:element>true</m:element>\n" + 
-        "        <m:element>false</m:element>\n" + 
-        "        <m:element>true</m:element>\n" + 
-        "      </d:CollPropertyBoolean>\n" + 
-        "      <d:CollPropertyByte m:type=\"#Collection(Byte)\">\n" + 
-        "        <m:element>50</m:element>\n" + 
-        "        <m:element>200</m:element>\n" + 
-        "        <m:element>249</m:element>\n" + 
-        "      </d:CollPropertyByte>\n" + 
-        "      <d:CollPropertySByte m:type=\"#Collection(SByte)\">\n" + 
-        "        <m:element>-120</m:element>\n" + 
-        "        <m:element>120</m:element>\n" + 
-        "        <m:element>126</m:element>\n" + 
-        "      </d:CollPropertySByte>\n" + 
-        "      <d:CollPropertyInt16 m:type=\"#Collection(Int16)\">\n" + 
-        "        <m:element>1000</m:element>\n" + 
-        "        <m:element>2000</m:element>\n" + 
-        "        <m:element>30112</m:element>\n" + 
-        "      </d:CollPropertyInt16>\n" + 
-        "      <d:CollPropertyInt32 m:type=\"#Collection(Int32)\">\n" + 
-        "        <m:element>23232323</m:element>\n" + 
-        "        <m:element>11223355</m:element>\n" + 
-        "        <m:element>10000001</m:element>\n" + 
-        "      </d:CollPropertyInt32>\n" + 
-        "      <d:CollPropertyInt64 m:type=\"#Collection(Int64)\">\n" + 
-        "        <m:element>929292929292</m:element>\n" + 
-        "        <m:element>333333333333</m:element>\n" + 
-        "        <m:element>444444444444</m:element>\n" + 
-        "      </d:CollPropertyInt64>\n" + 
-        "      <d:CollPropertySingle m:type=\"#Collection(Single)\">\n" + 
-        "        <m:element>1790.0</m:element>\n" + 
-        "        <m:element>26600.0</m:element>\n" + 
-        "        <m:element>3210.0</m:element>\n" + 
-        "      </d:CollPropertySingle>\n" + 
-        "      <d:CollPropertyDouble m:type=\"#Collection(Double)\">\n" + 
-        "        <m:element>-17900.0</m:element>\n" + 
-        "        <m:element>-2.78E7</m:element>\n" + 
-        "        <m:element>3210.0</m:element>\n" + 
-        "      </d:CollPropertyDouble>\n" + 
-        "      <d:CollPropertyDecimal m:type=\"#Collection(Decimal)\">\n" + 
-        "        <m:element>12</m:element>\n" + 
-        "        <m:element>-2</m:element>\n" + 
-        "        <m:element>1234</m:element>\n" + 
-        "      </d:CollPropertyDecimal>\n" + 
-        "      <d:CollPropertyBinary m:type=\"#Collection(Binary)\">\n" + 
-        "        <m:element>q83v</m:element>\n" + 
-        "        <m:element>ASNF</m:element>\n" + 
-        "        <m:element>VGeJ</m:element>\n" + 
-        "      </d:CollPropertyBinary>\n" + 
-        "      <d:CollPropertyDate m:type=\"#Collection(Date)\">\n" + 
-        "        <m:element>1958-12-03</m:element>\n" + 
-        "        <m:element>1999-08-05</m:element>\n" + 
-        "        <m:element>2013-06-25</m:element>\n" + 
-        "      </d:CollPropertyDate>\n" + 
-        "      <d:CollPropertyDateTimeOffset m:type=\"#Collection(DateTimeOffset)\">\n" + 
-        "        <m:element>2015-08-12T03:08:34Z</m:element>\n" + 
-        "        <m:element>1970-03-28T12:11:10Z</m:element>\n" + 
-        "        <m:element>1948-02-17T09:09:09Z</m:element>\n" + 
-        "      </d:CollPropertyDateTimeOffset>\n" + 
-        "      <d:CollPropertyDuration m:type=\"#Collection(Duration)\">\n" + 
-        "        <m:element>PT13S</m:element>\n" + 
-        "        <m:element>PT5H28M0S</m:element>\n" + 
-        "        <m:element>PT1H0S</m:element>\n" + 
-        "      </d:CollPropertyDuration>\n" + 
-        "      <d:CollPropertyGuid m:type=\"#Collection(Guid)\">\n" + 
-        "        <m:element>ffffff67-89ab-cdef-0123-456789aaaaaa</m:element>\n" + 
-        "        <m:element>eeeeee67-89ab-cdef-0123-456789bbbbbb</m:element>\n" + 
-        "        <m:element>cccccc67-89ab-cdef-0123-456789cccccc</m:element>\n" + 
-        "      </d:CollPropertyGuid>\n" + 
-        "      <d:CollPropertyTimeOfDay m:type=\"#Collection(TimeOfDay)\">\n" + 
-        "        <m:element>04:14:13</m:element>\n" + 
-        "        <m:element>23:59:59</m:element>\n" + 
-        "        <m:element>01:12:33</m:element>\n" + 
-        "      </d:CollPropertyTimeOfDay>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
+        + "m:context=\"http://host/service/$metadata#ESCollAllPrim/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESCollAllPrim(1)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "<a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESCollAllPrim(1)\" />\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETCollAllPrim\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" +
+        "      <d:CollPropertyString m:type=\"#Collection(String)\">\n" +
+        "        <m:element>Employee1@company.example</m:element>\n" +
+        "        <m:element>Employee2@company.example</m:element>\n" +
+        "        <m:element>Employee3@company.example</m:element>\n" +
+        "      </d:CollPropertyString>\n" +
+        "      <d:CollPropertyBoolean m:type=\"#Collection(Boolean)\">\n" +
+        "        <m:element>true</m:element>\n" +
+        "        <m:element>false</m:element>\n" +
+        "        <m:element>true</m:element>\n" +
+        "      </d:CollPropertyBoolean>\n" +
+        "      <d:CollPropertyByte m:type=\"#Collection(Byte)\">\n" +
+        "        <m:element>50</m:element>\n" +
+        "        <m:element>200</m:element>\n" +
+        "        <m:element>249</m:element>\n" +
+        "      </d:CollPropertyByte>\n" +
+        "      <d:CollPropertySByte m:type=\"#Collection(SByte)\">\n" +
+        "        <m:element>-120</m:element>\n" +
+        "        <m:element>120</m:element>\n" +
+        "        <m:element>126</m:element>\n" +
+        "      </d:CollPropertySByte>\n" +
+        "      <d:CollPropertyInt16 m:type=\"#Collection(Int16)\">\n" +
+        "        <m:element>1000</m:element>\n" +
+        "        <m:element>2000</m:element>\n" +
+        "        <m:element>30112</m:element>\n" +
+        "      </d:CollPropertyInt16>\n" +
+        "      <d:CollPropertyInt32 m:type=\"#Collection(Int32)\">\n" +
+        "        <m:element>23232323</m:element>\n" +
+        "        <m:element>11223355</m:element>\n" +
+        "        <m:element>10000001</m:element>\n" +
+        "      </d:CollPropertyInt32>\n" +
+        "      <d:CollPropertyInt64 m:type=\"#Collection(Int64)\">\n" +
+        "        <m:element>929292929292</m:element>\n" +
+        "        <m:element>333333333333</m:element>\n" +
+        "        <m:element>444444444444</m:element>\n" +
+        "      </d:CollPropertyInt64>\n" +
+        "      <d:CollPropertySingle m:type=\"#Collection(Single)\">\n" +
+        "        <m:element>1790.0</m:element>\n" +
+        "        <m:element>26600.0</m:element>\n" +
+        "        <m:element>3210.0</m:element>\n" +
+        "      </d:CollPropertySingle>\n" +
+        "      <d:CollPropertyDouble m:type=\"#Collection(Double)\">\n" +
+        "        <m:element>-17900.0</m:element>\n" +
+        "        <m:element>-2.78E7</m:element>\n" +
+        "        <m:element>3210.0</m:element>\n" +
+        "      </d:CollPropertyDouble>\n" +
+        "      <d:CollPropertyDecimal m:type=\"#Collection(Decimal)\">\n" +
+        "        <m:element>12</m:element>\n" +
+        "        <m:element>-2</m:element>\n" +
+        "        <m:element>1234</m:element>\n" +
+        "      </d:CollPropertyDecimal>\n" +
+        "      <d:CollPropertyBinary m:type=\"#Collection(Binary)\">\n" +
+        "        <m:element>q83v</m:element>\n" +
+        "        <m:element>ASNF</m:element>\n" +
+        "        <m:element>VGeJ</m:element>\n" +
+        "      </d:CollPropertyBinary>\n" +
+        "      <d:CollPropertyDate m:type=\"#Collection(Date)\">\n" +
+        "        <m:element>1958-12-03</m:element>\n" +
+        "        <m:element>1999-08-05</m:element>\n" +
+        "        <m:element>2013-06-25</m:element>\n" +
+        "      </d:CollPropertyDate>\n" +
+        "      <d:CollPropertyDateTimeOffset m:type=\"#Collection(DateTimeOffset)\">\n" +
+        "        <m:element>2015-08-12T03:08:34Z</m:element>\n" +
+        "        <m:element>1970-03-28T12:11:10Z</m:element>\n" +
+        "        <m:element>1948-02-17T09:09:09Z</m:element>\n" +
+        "      </d:CollPropertyDateTimeOffset>\n" +
+        "      <d:CollPropertyDuration m:type=\"#Collection(Duration)\">\n" +
+        "        <m:element>PT13S</m:element>\n" +
+        "        <m:element>PT5H28M0S</m:element>\n" +
+        "        <m:element>PT1H0S</m:element>\n" +
+        "      </d:CollPropertyDuration>\n" +
+        "      <d:CollPropertyGuid m:type=\"#Collection(Guid)\">\n" +
+        "        <m:element>ffffff67-89ab-cdef-0123-456789aaaaaa</m:element>\n" +
+        "        <m:element>eeeeee67-89ab-cdef-0123-456789bbbbbb</m:element>\n" +
+        "        <m:element>cccccc67-89ab-cdef-0123-456789cccccc</m:element>\n" +
+        "      </d:CollPropertyGuid>\n" +
+        "      <d:CollPropertyTimeOfDay m:type=\"#Collection(TimeOfDay)\">\n" +
+        "        <m:element>04:14:13</m:element>\n" +
+        "        <m:element>23:59:59</m:element>\n" +
+        "        <m:element>01:12:33</m:element>\n" +
+        "      </d:CollPropertyTimeOfDay>\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
         "</a:entry>";
-    XMLAssert.assertXMLEqual(expected, resultString);
+    checkXMLEqual(expected, resultString);
   }
 
   @Test
   public void entityCompAllPrim() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCompAllPrim");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
             .build()).getContent();
-    
+
     final String resultString = IOUtils.toString(result);
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
         "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\" "
-        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "
-        + "m:context=\"$metadata#ESCompAllPrim/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\" m:etag=\"W/&quot;32767&quot;\">\n" + 
-        "  <a:id>ESCompAllPrim(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "<a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-        .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESCompAllPrim(32767)\" />\n" + 
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETCompAllPrim\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "      <d:PropertyComp m:type=\"#olingo.odata.test1.CTAllPrim\">\n" + 
-        "        <d:PropertyString>First Resource - first</d:PropertyString>\n" + 
-        "        <d:PropertyBinary m:type=\"Binary\">ASNFZ4mrze8=</d:PropertyBinary>\n" + 
-        "        <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" + 
-        "        <d:PropertyByte m:type=\"Byte\">255</d:PropertyByte>\n" + 
-        "        <d:PropertyDate m:type=\"Date\">2012-10-03</d:PropertyDate>\n" + 
+        + "m:context=\"$metadata#ESCompAllPrim/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\" m:etag=\"W/&quot;32767&quot;\">\n" +
+        "  <a:id>ESCompAllPrim(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "<a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESCompAllPrim(32767)\" />\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETCompAllPrim\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "      <d:PropertyComp m:type=\"#olingo.odata.test1.CTAllPrim\">\n" +
+        "        <d:PropertyString>First Resource - first</d:PropertyString>\n" +
+        "        <d:PropertyBinary m:type=\"Binary\">ASNFZ4mrze8=</d:PropertyBinary>\n" +
+        "        <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" +
+        "        <d:PropertyByte m:type=\"Byte\">255</d:PropertyByte>\n" +
+        "        <d:PropertyDate m:type=\"Date\">2012-10-03</d:PropertyDate>\n" +
         "        <d:PropertyDateTimeOffset m:type=\"DateTimeOffset\">2012-10-03T07:16:23.1234567Z"
-        + "</d:PropertyDateTimeOffset>\n" + 
-        "        <d:PropertyDecimal m:type=\"Decimal\">34.27</d:PropertyDecimal>\n" + 
-        "        <d:PropertySingle m:type=\"Single\">1.79E20</d:PropertySingle>\n" + 
-        "        <d:PropertyDouble m:type=\"Double\">-1.79E19</d:PropertyDouble>\n" + 
-        "        <d:PropertyDuration m:type=\"Duration\">PT6S</d:PropertyDuration>\n" + 
-        "        <d:PropertyGuid m:type=\"Guid\">01234567-89ab-cdef-0123-456789abcdef</d:PropertyGuid>\n" + 
-        "        <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "        <d:PropertyInt32 m:type=\"Int32\">2147483647</d:PropertyInt32>\n" + 
-        "        <d:PropertyInt64 m:type=\"Int64\">9223372036854775807</d:PropertyInt64>\n" + 
-        "        <d:PropertySByte m:type=\"SByte\">127</d:PropertySByte>\n" + 
-        "        <d:PropertyTimeOfDay m:type=\"TimeOfDay\">01:00:01</d:PropertyTimeOfDay>\n" + 
-        "      </d:PropertyComp>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
+        + "</d:PropertyDateTimeOffset>\n" +
+        "        <d:PropertyDecimal m:type=\"Decimal\">34.27</d:PropertyDecimal>\n" +
+        "        <d:PropertySingle m:type=\"Single\">1.79E20</d:PropertySingle>\n" +
+        "        <d:PropertyDouble m:type=\"Double\">-1.79E19</d:PropertyDouble>\n" +
+        "        <d:PropertyDuration m:type=\"Duration\">PT6S</d:PropertyDuration>\n" +
+        "        <d:PropertyGuid m:type=\"Guid\">01234567-89ab-cdef-0123-456789abcdef</d:PropertyGuid>\n" +
+        "        <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "        <d:PropertyInt32 m:type=\"Int32\">2147483647</d:PropertyInt32>\n" +
+        "        <d:PropertyInt64 m:type=\"Int64\">9223372036854775807</d:PropertyInt64>\n" +
+        "        <d:PropertySByte m:type=\"SByte\">127</d:PropertySByte>\n" +
+        "        <d:PropertyTimeOfDay m:type=\"TimeOfDay\">01:00:01</d:PropertyTimeOfDay>\n" +
+        "      </d:PropertyComp>\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
         "</a:entry>";
-    XMLAssert.assertXMLEqual(expected, resultString);
+    checkXMLEqual(expected, resultString);
   }
 
   @Test
   public void entityMixPrimCollComp() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer.entity(metadata, edmEntitySet.getEntityType(), entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
             .build()).getContent();
     final String resultString = IOUtils.toString(result);
-    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
-        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" \n" + 
-        "  m:context=\"$metadata#ESMixPrimCollComp/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESMixPrimCollComp(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-          .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESMixPrimCollComp(32767)\"/>\n" + 
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETMixPrimCollComp\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "      <d:CollPropertyString m:type=\"#Collection(String)\">\n" + 
-        "        <m:element>Employee1@company.example</m:element>\n" + 
-        "        <m:element>Employee2@company.example</m:element>\n" + 
-        "        <m:element>Employee3@company.example</m:element>\n" + 
-        "      </d:CollPropertyString>\n" + 
-        "      <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" + 
-        "        <d:PropertyInt16 m:type=\"Int16\">111</d:PropertyInt16>\n" + 
-        "        <d:PropertyString>TEST A</d:PropertyString>\n" + 
-        "      </d:PropertyComp>\n" + 
-        "        <d:CollPropertyComp m:type=\"#Collection(olingo.odata.test1.CTTwoPrim)\">\n" + 
-        "          <m:element>\n" + 
-        "            <d:PropertyInt16 m:type=\"Int16\">123</d:PropertyInt16>\n" + 
-        "            <d:PropertyString>TEST 1</d:PropertyString>\n" + 
-        "          </m:element>\n" + 
-        "          <m:element>\n" + 
-        "            <d:PropertyInt16 m:type=\"Int16\">456</d:PropertyInt16>\n" + 
-        "            <d:PropertyString>TEST 2</d:PropertyString>\n" + 
-        "          </m:element>\n" + 
-        "          <m:element>\n" + 
-        "            <d:PropertyInt16 m:type=\"Int16\">789</d:PropertyInt16>\n" + 
-        "            <d:PropertyString>TEST 3</d:PropertyString>\n" + 
-        "          </m:element>\n" + 
-        "        </d:CollPropertyComp>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
-        "</a:entry>\n"; 
+    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
+        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" \n" +
+        "  m:context=\"$metadata#ESMixPrimCollComp/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESMixPrimCollComp(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESMixPrimCollComp(32767)\"/>\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETMixPrimCollComp\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "      <d:CollPropertyString m:type=\"#Collection(String)\">\n" +
+        "        <m:element>Employee1@company.example</m:element>\n" +
+        "        <m:element>Employee2@company.example</m:element>\n" +
+        "        <m:element>Employee3@company.example</m:element>\n" +
+        "      </d:CollPropertyString>\n" +
+        "      <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" +
+        "        <d:PropertyInt16 m:type=\"Int16\">111</d:PropertyInt16>\n" +
+        "        <d:PropertyString>TEST A</d:PropertyString>\n" +
+        "      </d:PropertyComp>\n" +
+        "        <d:CollPropertyComp m:type=\"#Collection(olingo.odata.test1.CTTwoPrim)\">\n" +
+        "          <m:element>\n" +
+        "            <d:PropertyInt16 m:type=\"Int16\">123</d:PropertyInt16>\n" +
+        "            <d:PropertyString>TEST 1</d:PropertyString>\n" +
+        "          </m:element>\n" +
+        "          <m:element>\n" +
+        "            <d:PropertyInt16 m:type=\"Int16\">456</d:PropertyInt16>\n" +
+        "            <d:PropertyString>TEST 2</d:PropertyString>\n" +
+        "          </m:element>\n" +
+        "          <m:element>\n" +
+        "            <d:PropertyInt16 m:type=\"Int16\">789</d:PropertyInt16>\n" +
+        "            <d:PropertyString>TEST 3</d:PropertyString>\n" +
+        "          </m:element>\n" +
+        "        </d:CollPropertyComp>\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
+        "</a:entry>\n";
     XMLAssert.assertXMLEqual(expectedResult, resultString);
   }
 
@@ -507,36 +524,38 @@ public class ODataXmlSerializerTest  {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
     Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
     entity.getProperties().retainAll(Arrays.asList(entity.getProperties().get(0)));
-    final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(), 
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream content = serializer.entity(metadata, edmEntitySet.getEntityType(),
         entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
-            .build()).getContent());
-    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+            .build()).getContent();
+    final String resultString = IOUtils.toString(content);
+    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "
-        + "m:context=\"$metadata#ESMixPrimCollComp/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESMixPrimCollComp(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-            .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESMixPrimCollComp(32767)\"/>\n" + 
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETMixPrimCollComp\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" + 
-        "      <d:CollPropertyString m:null=\"true\" />\n" + 
-        "      <d:PropertyComp m:null=\"true\" />\n" + 
-        "      <d:CollPropertyComp m:null=\"true\" />\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
+        + "m:context=\"$metadata#ESMixPrimCollComp/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESMixPrimCollComp(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESMixPrimCollComp(32767)\"/>\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETMixPrimCollComp\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">32767</d:PropertyInt16>\n" +
+        "      <d:CollPropertyString m:null=\"true\" />\n" +
+        "      <d:PropertyComp m:null=\"true\" />\n" +
+        "      <d:CollPropertyComp m:null=\"true\" />\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
         "</a:entry>";
     XMLAssert.assertXMLEqual(expectedResult, resultString);
   }
@@ -573,33 +592,35 @@ public class ODataXmlSerializerTest  {
   public void entityMedia() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
     final Entity entity = data.readAll(edmEntitySet).getEntities().get(0);
-    final String resultString = IOUtils.toString(serializer.entity(metadata, edmEntitySet.getEntityType(),
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream content = serializer.entity(metadata, edmEntitySet.getEntityType(),
         entity,
         EntitySerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build())
-            .build()).getContent());
-    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+            .build()).getContent();
+    final String resultString = IOUtils.toString(content);
+    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" " +
-        "  m:context=\"$metadata#ESMedia/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESMedia(1)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESMedia(1)\"/>\n" + 
+        "  m:context=\"$metadata#ESMedia/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESMedia(1)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESMedia(1)\"/>\n" +
         "  <a:content type=\"image/svg+xml\" src=\"ESMedia(1)/$value\" />\n" +
         "  <a:link rel=\"edit-media\" title=\"ESMedia\" href=\"ESMedia(1)/$value\"/>\n" +
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETMedia\" />\n" + 
-        "  <m:properties>\n" + 
-        "    <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" + 
-        "  </m:properties>\n" + 
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETMedia\" />\n" +
+        "  <m:properties>\n" +
+        "    <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" +
+        "  </m:properties>\n" +
         "</a:entry>";
     XMLAssert.assertXMLEqual(expectedResult, resultString);
   }
@@ -608,92 +629,94 @@ public class ODataXmlSerializerTest  {
   public void entitySetMedia() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMedia");
     final EntityCollection entitySet = data.readAll(edmEntitySet);
-    final String resultString = IOUtils.toString(serializer.entityCollection(metadata,
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream content = serializer.entityCollection(metadata,
         edmEntitySet.getEntityType(), entitySet,
         EntityCollectionSerializerOptions.with()
             .contextURL(ContextURL.with().entitySet(edmEntitySet).build())
             .setId("http://host/svc/ESMedia")
-            .build()).getContent());
-    
-    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
-        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" m:context=\"$metadata#ESMedia\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>http://host/svc/ESMedia</a:id>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESMedia(1)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESMedia(1)\"/>\n" + 
+            .build()).getContent();
+    final String resultString = IOUtils.toString(content);
+
+    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
+        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" m:context=\"$metadata#ESMedia\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>http://host/svc/ESMedia</a:id>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESMedia(1)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESMedia(1)\"/>\n" +
         "    <a:content type=\"image/svg+xml\" src=\"ESMedia(1)/$value\" />\n" +
         "    <a:link rel=\"edit-media\" title=\"ESMedia\" href=\"ESMedia(1)/$value\"/>\n" +
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETMedia\" />\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:entry>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESMedia(2)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESMedia(2)\"/>\n" + 
-        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(2)/$value\" />\n" + 
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETMedia\" />\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">1</d:PropertyInt16>\n" +
+        "    </m:properties>\n" +
+        "  </a:entry>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESMedia(2)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESMedia(2)\"/>\n" +
+        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(2)/$value\" />\n" +
         "    <a:link rel=\"edit-media\" title=\"ESMedia\" href=\"ESMedia(2)/$value\"/>\n" +
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETMedia\" />\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">2</d:PropertyInt16>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:entry>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESMedia(3)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESMedia(3)\"/>\n" + 
-        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(3)/$value\" />\n" + 
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETMedia\" />\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">2</d:PropertyInt16>\n" +
+        "    </m:properties>\n" +
+        "  </a:entry>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESMedia(3)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESMedia(3)\"/>\n" +
+        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(3)/$value\" />\n" +
         "    <a:link rel=\"edit-media\" title=\"ESMedia\" href=\"ESMedia(3)/$value\"/>\n" +
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETMedia\" />\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">3</d:PropertyInt16>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:entry>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESMedia(4)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "  <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-              .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESMedia(4)\"/>\n" + 
-        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(4)/$value\" />\n" + 
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETMedia\" />\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">3</d:PropertyInt16>\n" +
+        "    </m:properties>\n" +
+        "  </a:entry>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESMedia(4)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "  <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESMedia(4)\"/>\n" +
+        "    <a:content type=\"image/svg+xml\" src=\"ESMedia(4)/$value\" />\n" +
         "    <a:link rel=\"edit-media\" title=\"ESMedia\" href=\"ESMedia(4)/$value\"/>\n" +
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETMedia\" />\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyInt16 m:type=\"Int16\">4</d:PropertyInt16>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:entry>\n" + 
-        "</a:feed>\n" + 
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETMedia\" />\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyInt16 m:type=\"Int16\">4</d:PropertyInt16>\n" +
+        "    </m:properties>\n" +
+        "  </a:entry>\n" +
+        "</a:feed>\n" +
         "";
     XMLAssert.assertXMLEqual(expectedResult, resultString);
   }
@@ -702,136 +725,138 @@ public class ODataXmlSerializerTest  {
   public void primitiveValuesAllNull() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllNullable");
     final EntityCollection entitySet = data.readAll(edmEntitySet);
-    final String resultString = IOUtils.toString(serializer.entityCollection(metadata,
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream content = serializer.entityCollection(metadata,
         edmEntitySet.getEntityType(), entitySet,
-                EntityCollectionSerializerOptions.with()
-                    .contextURL(ContextURL.with().serviceRoot(URI.create("http://host/svc"))
-                        .entitySet(edmEntitySet).build())
-                    .setId("http://host/svc/ESAllNullable")
-                    .build()).getContent());
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
+        EntityCollectionSerializerOptions.with()
+            .contextURL(ContextURL.with().serviceRoot(URI.create("http://host/svc"))
+                .entitySet(edmEntitySet).build())
+            .setId("http://host/svc/ESAllNullable")
+            .build()).getContent();
+    final String resultString = IOUtils.toString(content);
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
         "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\" "
-        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+        + "xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" "
-        + "m:context=\"http://host/svc$metadata#ESAllNullable\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>http://host/svc/ESAllNullable</a:id>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESAllNullable(1)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "    <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-        .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESAllNullable(1)\" />\n" + 
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETAllNullable\" />\n" + 
-        "    <a:content type=\"application/xml\">\n" + 
-        "      <m:properties>\n" + 
-        "        <d:PropertyKey m:type=\"Int16\">1</d:PropertyKey>\n" + 
-        "        <d:PropertyInt16 m:null=\"true\" />\n" + 
-        "        <d:PropertyString m:null=\"true\" />\n" + 
-        "        <d:PropertyBoolean m:null=\"true\" />\n" + 
-        "        <d:PropertyByte m:null=\"true\" />\n" + 
-        "        <d:PropertySByte m:null=\"true\" />\n" + 
-        "        <d:PropertyInt32 m:null=\"true\" />\n" + 
-        "        <d:PropertyInt64 m:null=\"true\" />\n" + 
-        "        <d:PropertySingle m:null=\"true\" />\n" + 
-        "        <d:PropertyDouble m:null=\"true\" />\n" + 
-        "        <d:PropertyDecimal m:null=\"true\" />\n" + 
-        "        <d:PropertyBinary m:null=\"true\" />\n" + 
-        "        <d:PropertyDate m:null=\"true\" />\n" + 
-        "        <d:PropertyDateTimeOffset m:null=\"true\" />\n" + 
-        "        <d:PropertyDuration m:null=\"true\" />\n" + 
-        "        <d:PropertyGuid m:null=\"true\" />\n" + 
-        "        <d:PropertyTimeOfDay m:null=\"true\" />\n" + 
-        "        <d:CollPropertyString m:type=\"#Collection(String)\">\n" + 
-        "          <m:element>spiderman@comic.com</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>spidergirl@comic.com</m:element>\n" + 
-        "        </d:CollPropertyString>\n" + 
-        "        <d:CollPropertyBoolean m:type=\"#Collection(Boolean)\">\n" + 
-        "          <m:element>true</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>false</m:element>\n" + 
-        "        </d:CollPropertyBoolean>\n" + 
-        "        <d:CollPropertyByte m:type=\"#Collection(Byte)\">\n" + 
-        "          <m:element>50</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>249</m:element>\n" + 
-        "        </d:CollPropertyByte>\n" + 
-        "        <d:CollPropertySByte m:type=\"#Collection(SByte)\">\n" + 
-        "          <m:element>-120</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>126</m:element>\n" + 
-        "        </d:CollPropertySByte>\n" + 
-        "        <d:CollPropertyInt16 m:type=\"#Collection(Int16)\">\n" + 
-        "          <m:element>1000</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>30112</m:element>\n" + 
-        "        </d:CollPropertyInt16>\n" + 
-        "        <d:CollPropertyInt32 m:type=\"#Collection(Int32)\">\n" + 
-        "          <m:element>23232323</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>10000001</m:element>\n" + 
-        "        </d:CollPropertyInt32>\n" + 
-        "        <d:CollPropertyInt64 m:type=\"#Collection(Int64)\">\n" + 
-        "          <m:element>929292929292</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>444444444444</m:element>\n" + 
-        "        </d:CollPropertyInt64>\n" + 
-        "        <d:CollPropertySingle m:type=\"#Collection(Single)\">\n" + 
-        "          <m:element>1790.0</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>3210.0</m:element>\n" + 
-        "        </d:CollPropertySingle>\n" + 
-        "        <d:CollPropertyDouble m:type=\"#Collection(Double)\">\n" + 
-        "          <m:element>-17900.0</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>3210.0</m:element>\n" + 
-        "        </d:CollPropertyDouble>\n" + 
-        "        <d:CollPropertyDecimal m:type=\"#Collection(Decimal)\">\n" + 
-        "          <m:element>12</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>1234</m:element>\n" + 
-        "        </d:CollPropertyDecimal>\n" + 
-        "        <d:CollPropertyBinary m:type=\"#Collection(Binary)\">\n" + 
-        "          <m:element>q83v</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>VGeJ</m:element>\n" + 
-        "        </d:CollPropertyBinary>\n" + 
-        "        <d:CollPropertyDate m:type=\"#Collection(Date)\">\n" + 
-        "          <m:element>1958-12-03</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>2013-06-25</m:element>\n" + 
-        "        </d:CollPropertyDate>\n" + 
-        "        <d:CollPropertyDateTimeOffset m:type=\"#Collection(DateTimeOffset)\">\n" + 
-        "          <m:element>2015-08-12T03:08:34Z</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>1948-02-17T09:09:09Z</m:element>\n" + 
-        "        </d:CollPropertyDateTimeOffset>\n" + 
-        "        <d:CollPropertyDuration m:type=\"#Collection(Duration)\">\n" + 
-        "          <m:element>PT13S</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>PT1H0S</m:element>\n" + 
-        "        </d:CollPropertyDuration>\n" + 
-        "        <d:CollPropertyGuid m:type=\"#Collection(Guid)\">\n" + 
-        "          <m:element>ffffff67-89ab-cdef-0123-456789aaaaaa</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>cccccc67-89ab-cdef-0123-456789cccccc</m:element>\n" + 
-        "        </d:CollPropertyGuid>\n" + 
-        "        <d:CollPropertyTimeOfDay m:type=\"#Collection(TimeOfDay)\">\n" + 
-        "          <m:element>04:14:13</m:element>\n" + 
-        "          <m:element d:null=\"true\" />\n" + 
-        "          <m:element>00:37:13</m:element>\n" + 
-        "        </d:CollPropertyTimeOfDay>\n" + 
-        "      </m:properties>\n" + 
-        "    </a:content>\n" + 
-        "  </a:entry>\n" + 
+        + "m:context=\"http://host/svc$metadata#ESAllNullable\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>http://host/svc/ESAllNullable</a:id>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESAllNullable(1)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "    <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESAllNullable(1)\" />\n" +
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETAllNullable\" />\n" +
+        "    <a:content type=\"application/xml\">\n" +
+        "      <m:properties>\n" +
+        "        <d:PropertyKey m:type=\"Int16\">1</d:PropertyKey>\n" +
+        "        <d:PropertyInt16 m:null=\"true\" />\n" +
+        "        <d:PropertyString m:null=\"true\" />\n" +
+        "        <d:PropertyBoolean m:null=\"true\" />\n" +
+        "        <d:PropertyByte m:null=\"true\" />\n" +
+        "        <d:PropertySByte m:null=\"true\" />\n" +
+        "        <d:PropertyInt32 m:null=\"true\" />\n" +
+        "        <d:PropertyInt64 m:null=\"true\" />\n" +
+        "        <d:PropertySingle m:null=\"true\" />\n" +
+        "        <d:PropertyDouble m:null=\"true\" />\n" +
+        "        <d:PropertyDecimal m:null=\"true\" />\n" +
+        "        <d:PropertyBinary m:null=\"true\" />\n" +
+        "        <d:PropertyDate m:null=\"true\" />\n" +
+        "        <d:PropertyDateTimeOffset m:null=\"true\" />\n" +
+        "        <d:PropertyDuration m:null=\"true\" />\n" +
+        "        <d:PropertyGuid m:null=\"true\" />\n" +
+        "        <d:PropertyTimeOfDay m:null=\"true\" />\n" +
+        "        <d:CollPropertyString m:type=\"#Collection(String)\">\n" +
+        "          <m:element>spiderman@comic.com</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>spidergirl@comic.com</m:element>\n" +
+        "        </d:CollPropertyString>\n" +
+        "        <d:CollPropertyBoolean m:type=\"#Collection(Boolean)\">\n" +
+        "          <m:element>true</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>false</m:element>\n" +
+        "        </d:CollPropertyBoolean>\n" +
+        "        <d:CollPropertyByte m:type=\"#Collection(Byte)\">\n" +
+        "          <m:element>50</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>249</m:element>\n" +
+        "        </d:CollPropertyByte>\n" +
+        "        <d:CollPropertySByte m:type=\"#Collection(SByte)\">\n" +
+        "          <m:element>-120</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>126</m:element>\n" +
+        "        </d:CollPropertySByte>\n" +
+        "        <d:CollPropertyInt16 m:type=\"#Collection(Int16)\">\n" +
+        "          <m:element>1000</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>30112</m:element>\n" +
+        "        </d:CollPropertyInt16>\n" +
+        "        <d:CollPropertyInt32 m:type=\"#Collection(Int32)\">\n" +
+        "          <m:element>23232323</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>10000001</m:element>\n" +
+        "        </d:CollPropertyInt32>\n" +
+        "        <d:CollPropertyInt64 m:type=\"#Collection(Int64)\">\n" +
+        "          <m:element>929292929292</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>444444444444</m:element>\n" +
+        "        </d:CollPropertyInt64>\n" +
+        "        <d:CollPropertySingle m:type=\"#Collection(Single)\">\n" +
+        "          <m:element>1790.0</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>3210.0</m:element>\n" +
+        "        </d:CollPropertySingle>\n" +
+        "        <d:CollPropertyDouble m:type=\"#Collection(Double)\">\n" +
+        "          <m:element>-17900.0</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>3210.0</m:element>\n" +
+        "        </d:CollPropertyDouble>\n" +
+        "        <d:CollPropertyDecimal m:type=\"#Collection(Decimal)\">\n" +
+        "          <m:element>12</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>1234</m:element>\n" +
+        "        </d:CollPropertyDecimal>\n" +
+        "        <d:CollPropertyBinary m:type=\"#Collection(Binary)\">\n" +
+        "          <m:element>q83v</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>VGeJ</m:element>\n" +
+        "        </d:CollPropertyBinary>\n" +
+        "        <d:CollPropertyDate m:type=\"#Collection(Date)\">\n" +
+        "          <m:element>1958-12-03</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>2013-06-25</m:element>\n" +
+        "        </d:CollPropertyDate>\n" +
+        "        <d:CollPropertyDateTimeOffset m:type=\"#Collection(DateTimeOffset)\">\n" +
+        "          <m:element>2015-08-12T03:08:34Z</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>1948-02-17T09:09:09Z</m:element>\n" +
+        "        </d:CollPropertyDateTimeOffset>\n" +
+        "        <d:CollPropertyDuration m:type=\"#Collection(Duration)\">\n" +
+        "          <m:element>PT13S</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>PT1H0S</m:element>\n" +
+        "        </d:CollPropertyDuration>\n" +
+        "        <d:CollPropertyGuid m:type=\"#Collection(Guid)\">\n" +
+        "          <m:element>ffffff67-89ab-cdef-0123-456789aaaaaa</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>cccccc67-89ab-cdef-0123-456789cccccc</m:element>\n" +
+        "        </d:CollPropertyGuid>\n" +
+        "        <d:CollPropertyTimeOfDay m:type=\"#Collection(TimeOfDay)\">\n" +
+        "          <m:element>04:14:13</m:element>\n" +
+        "          <m:element d:null=\"true\" />\n" +
+        "          <m:element>00:37:13</m:element>\n" +
+        "        </d:CollPropertyTimeOfDay>\n" +
+        "      </m:properties>\n" +
+        "    </a:content>\n" +
+        "  </a:entry>\n" +
         "</a:feed>";
-    XMLAssert.assertXMLEqual(expected, resultString);
+    checkXMLEqual(expected, resultString);
   }
 
   @Test
@@ -843,6 +868,7 @@ public class ODataXmlSerializerTest  {
     final SelectItem selectItem2 = ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyBoolean");
     final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
         selectItem1, selectItem2, selectItem2));
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer
         .entity(metadata, entityType, entity,
             EntitySerializerOptions.with()
@@ -852,37 +878,37 @@ public class ODataXmlSerializerTest  {
                 .select(select)
                 .build()).getContent();
     final String resultString = IOUtils.toString(result);
-    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
+    final String expectedResult = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:entry xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
         "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" " +
-        "  m:context=\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>ESAllPrim(32767)</a:id>\n" + 
-        "  <a:title />\n" + 
-        "  <a:summary />\n" + 
-        "    <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-                .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "  <a:author>\n" + 
-        "    <a:name />\n" + 
-        "  </a:author>\n" + 
-        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\"/>\n" + 
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" + 
-        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" + 
+        "  m:context=\"$metadata#ESAllPrim(PropertyBoolean,PropertyDate)/$entity\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>ESAllPrim(32767)</a:id>\n" +
+        "  <a:title />\n" +
+        "  <a:summary />\n" +
+        "    <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "  <a:author>\n" +
+        "    <a:name />\n" +
+        "  </a:author>\n" +
+        "  <a:link rel=\"edit\" href=\"ESAllPrim(32767)\"/>\n" +
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimOne\"\n" +
+        "    type=\"application/atom+xml;type=entry\" title=\"NavPropertyETTwoPrimOne\"\n" +
         "    href=\"ESTwoPrim(32767)\" />\n" +
-        "  <a:link\n" + 
-        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" + 
-        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" + 
-        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +         
-        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" + 
-        "  <a:content type=\"application/xml\">\n" + 
-        "    <m:properties>\n" + 
-        "      <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" + 
-        "      <d:PropertyDate m:type=\"Date\">2012-12-03</d:PropertyDate>\n" + 
-        "    </m:properties>\n" + 
-        "  </a:content>\n" + 
+        "  <a:link\n" +
+        "    rel=\"http://docs.oasis-open.org/odata/ns/related/NavPropertyETTwoPrimMany\"\n" +
+        "    type=\"application/atom+xml;type=feed\" title=\"NavPropertyETTwoPrimMany\"\n" +
+        "    href=\"ESAllPrim(32767)/NavPropertyETTwoPrimMany\" />\n" +
+        "  <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "    term=\"#olingo.odata.test1.ETAllPrim\" />\n" +
+        "  <a:content type=\"application/xml\">\n" +
+        "    <m:properties>\n" +
+        "      <d:PropertyBoolean m:type=\"Boolean\">true</d:PropertyBoolean>\n" +
+        "      <d:PropertyDate m:type=\"Date\">2012-12-03</d:PropertyDate>\n" +
+        "    </m:properties>\n" +
+        "  </a:content>\n" +
         "</a:entry>";
     XMLAssert.assertXMLEqual(expectedResult, resultString);
   }
@@ -894,6 +920,7 @@ public class ODataXmlSerializerTest  {
     final EntityCollection entitySet = data.readAll(edmEntitySet);
     final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
         ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString")));
+    long currentTimeMillis = System.currentTimeMillis();
     InputStream result = serializer
         .entityCollection(metadata, entityType, entitySet,
             EntityCollectionSerializerOptions.with()
@@ -904,59 +931,59 @@ public class ODataXmlSerializerTest  {
                 .select(select)
                 .build()).getContent();
     final String resultString = IOUtils.toString(result);
-    final String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
-        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\"\n" + 
-        "  m:context=\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>http://host/svc/ESCompComp</a:id>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESCompComp(1)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "<a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 
-          .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESCompComp(1)\"/>\n" + 
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" + 
-        "    <a:content type=\"application/xml\">\n" + 
-        "      <m:properties>\n" + 
-        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" + 
-        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" + 
-        "            <d:PropertyString>String 1</d:PropertyString>\n" + 
-        "          </d:PropertyComp>\n" + 
-        "        </d:PropertyComp>\n" + 
-        "      </m:properties>\n" + 
-        "    </a:content>\n" + 
-        "  </a:entry>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESCompComp(2)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "<a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 
-            .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESCompComp(2)\"/>\n" + 
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" + 
-        "    <a:content type=\"application/xml\">\n" + 
-        "      <m:properties>\n" + 
-        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" + 
-        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" + 
-        "            <d:PropertyString>String 2</d:PropertyString>\n" + 
-        "          </d:PropertyComp>\n" + 
-        "        </d:PropertyComp>\n" + 
-        "      </m:properties>\n" + 
-        "    </a:content>\n" + 
-        "  </a:entry>\n" + 
-        "</a:feed>\n"; 
-    XMLAssert.assertXMLEqual(expected, resultString);
+    final String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
+        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\"\n" +
+        "  m:context=\"$metadata#ESCompComp(PropertyComp/PropertyComp/PropertyString)\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>http://host/svc/ESCompComp</a:id>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESCompComp(1)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "<a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESCompComp(1)\"/>\n" +
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" +
+        "    <a:content type=\"application/xml\">\n" +
+        "      <m:properties>\n" +
+        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" +
+        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" +
+        "            <d:PropertyString>String 1</d:PropertyString>\n" +
+        "          </d:PropertyComp>\n" +
+        "        </d:PropertyComp>\n" +
+        "      </m:properties>\n" +
+        "    </a:content>\n" +
+        "  </a:entry>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESCompComp(2)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "<a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESCompComp(2)\"/>\n" +
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" +
+        "    <a:content type=\"application/xml\">\n" +
+        "      <m:properties>\n" +
+        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" +
+        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" +
+        "            <d:PropertyString>String 2</d:PropertyString>\n" +
+        "          </d:PropertyComp>\n" +
+        "        </d:PropertyComp>\n" +
+        "      </m:properties>\n" +
+        "    </a:content>\n" +
+        "  </a:entry>\n" +
+        "</a:feed>\n";
+    checkXMLEqual(expected, resultString);
   }
 
   @Test
@@ -967,7 +994,8 @@ public class ODataXmlSerializerTest  {
     final SelectOption select = ExpandSelectMock.mockSelectOption(Arrays.asList(
         ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp", "PropertyString"),
         ExpandSelectMock.mockSelectItem(edmEntitySet, "PropertyComp", "PropertyComp")));
-    final String resultString = IOUtils.toString(serializer
+    long currentTimeMillis = System.currentTimeMillis();
+    InputStream inputStream = serializer
         .entityCollection(metadata, entityType, entitySet,
             EntityCollectionSerializerOptions.with()
                 .contextURL(ContextURL.with().entitySet(edmEntitySet)
@@ -975,62 +1003,63 @@ public class ODataXmlSerializerTest  {
                     .build())
                 .setId("http://host/svc/ESCompComp")
                 .select(select)
-                .build()).getContent());
-    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" + 
-        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" + 
-        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" + 
-        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" \n" + 
-        "  m:context=\"$metadata#ESCompComp(PropertyComp/PropertyComp)\"\n" + 
-        "  m:metadata-etag=\"WmetadataETag\">\n" + 
-        "  <a:id>http://host/svc/ESCompComp</a:id>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESCompComp(1)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "    <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 
-                .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESCompComp(1)\"/>\n" + 
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" + 
-        "    <a:content type=\"application/xml\">\n" + 
-        "      <m:properties>\n" + 
-        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" + 
-        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" + 
-        "            <d:PropertyInt16 m:type=\"Int16\">123</d:PropertyInt16>\n" + 
-        "            <d:PropertyString>String 1</d:PropertyString>\n" + 
-        "          </d:PropertyComp>\n" + 
-        "        </d:PropertyComp>\n" + 
-        "      </m:properties>\n" + 
-        "    </a:content>\n" + 
-        "  </a:entry>\n" + 
-        "  <a:entry>\n" + 
-        "    <a:id>ESCompComp(2)</a:id>\n" + 
-        "    <a:title />\n" + 
-        "    <a:summary />\n" + 
-        "    <a:updated>"+new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 
-                .format(new Date(System.currentTimeMillis()))+"</a:updated>" +
-        "    <a:author>\n" + 
-        "      <a:name />\n" + 
-        "    </a:author>\n" + 
-        "    <a:link rel=\"edit\" href=\"ESCompComp(2)\"/>\n" + 
-        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" + 
-        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" + 
-        "    <a:content type=\"application/xml\">\n" + 
-        "      <m:properties>\n" + 
-        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" + 
-        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" + 
-        "            <d:PropertyInt16 m:type=\"Int16\">987</d:PropertyInt16>\n" + 
-        "            <d:PropertyString>String 2</d:PropertyString>\n" + 
-        "          </d:PropertyComp>\n" + 
-        "        </d:PropertyComp>\n" + 
-        "      </m:properties>\n" + 
-        "    </a:content>\n" + 
-        "  </a:entry>\n" + 
+                .build()).getContent();
+    final String resultString = IOUtils.toString(inputStream);
+    String expected = "<?xml version='1.0' encoding='UTF-8'?>\n" +
+        "<a:feed xmlns:a=\"http://www.w3.org/2005/Atom\"\n" +
+        "  xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\"\n" +
+        "  xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" \n" +
+        "  m:context=\"$metadata#ESCompComp(PropertyComp/PropertyComp)\"\n" +
+        "  m:metadata-etag=\"WmetadataETag\">\n" +
+        "  <a:id>http://host/svc/ESCompComp</a:id>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESCompComp(1)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "    <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+        .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESCompComp(1)\"/>\n" +
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" +
+        "    <a:content type=\"application/xml\">\n" +
+        "      <m:properties>\n" +
+        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" +
+        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" +
+        "            <d:PropertyInt16 m:type=\"Int16\">123</d:PropertyInt16>\n" +
+        "            <d:PropertyString>String 1</d:PropertyString>\n" +
+        "          </d:PropertyComp>\n" +
+        "        </d:PropertyComp>\n" +
+        "      </m:properties>\n" +
+        "    </a:content>\n" +
+        "  </a:entry>\n" +
+        "  <a:entry>\n" +
+        "    <a:id>ESCompComp(2)</a:id>\n" +
+        "    <a:title />\n" +
+        "    <a:summary />\n" +
+        "    <a:updated>" + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
+            .format(new Date(currentTimeMillis)) + "</a:updated>" +
+        "    <a:author>\n" +
+        "      <a:name />\n" +
+        "    </a:author>\n" +
+        "    <a:link rel=\"edit\" href=\"ESCompComp(2)\"/>\n" +
+        "    <a:category scheme=\"http://docs.oasis-open.org/odata/ns/scheme\"\n" +
+        "      term=\"#olingo.odata.test1.ETCompComp\" />\n" +
+        "    <a:content type=\"application/xml\">\n" +
+        "      <m:properties>\n" +
+        "        <d:PropertyComp m:type=\"#olingo.odata.test1.CTCompComp\">\n" +
+        "          <d:PropertyComp m:type=\"#olingo.odata.test1.CTTwoPrim\">\n" +
+        "            <d:PropertyInt16 m:type=\"Int16\">987</d:PropertyInt16>\n"

<TRUNCATED>

[13/18] olingo-odata4 git commit: [OLINGO-741] Add pre-validation for properties in UriParseTreeVisitor

Posted by ch...@apache.org.
[OLINGO-741] Add pre-validation for properties in UriParseTreeVisitor


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

Branch: refs/heads/OLINGO-640
Commit: ac6e9e725de08d8b74e1e878239f80b64789d85a
Parents: 305f54d
Author: Michael Bolz <mi...@sap.com>
Authored: Thu Jul 30 21:33:49 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Thu Jul 30 21:34:35 2015 +0200

----------------------------------------------------------------------
 .../core/uri/parser/UriParseTreeVisitor.java    | 29 ++++++----
 .../core/uri/antlr/TestFullResourcePath.java    | 56 +++++++++++++++++---
 2 files changed, 68 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ac6e9e72/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
index 16aa42e..dcccf7c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/UriParseTreeVisitor.java
@@ -288,8 +288,21 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
 
     String odi = ctx.vODI.getText();
 
-    if (checkFirst && ctx.vNS == null) {
+    boolean searchInContainer = true;
+    // validate if context type and according property is available
+    // otherwise search in container for first element
+    if (checkFirst && ctx.vNS == null && !context.contextTypes.empty()) {
+      TypeInformation source = context.contextTypes.peek();
+      if (source.type instanceof EdmStructuredType) {
+        EdmStructuredType str = (EdmStructuredType) source.type;
+        EdmElement property = str.getProperty(odi);
+        if (property != null) {
+          searchInContainer = false;
+        }
+      }
+    }
 
+    if(searchInContainer) {
       // check EntitySet
       EdmEntitySet edmEntitySet = edmEntityContainer.getEntitySet(odi);
       if (edmEntitySet != null) {
@@ -362,8 +375,8 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       }
     }
 
-    TypeInformation source = null;
-    UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
+    final TypeInformation source;
+    final UriResource lastResourcePart = context.contextUriInfo.getLastResourcePart();
 
     if (lastResourcePart == null) {
       if (context.contextTypes.empty()) {
@@ -427,7 +440,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
       }
 
       if (property instanceof EdmProperty) {
-        if (((EdmProperty) property).isPrimitive() == true) {
+        if (((EdmProperty) property).isPrimitive()) {
           // create simple property
           UriResourcePrimitivePropertyImpl simpleResource = new UriResourcePrimitivePropertyImpl()
               .setProperty((EdmProperty) property);
@@ -485,7 +498,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
             if (lastResourcePart instanceof UriResourceWithKeysImpl) {
               UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
 
-              if (lastPartWithKeys.isCollection() == false) {
+              if (!lastPartWithKeys.isCollection()) {
                 if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
                   throw wrap(new UriParserSemanticException("Entry typefilters are not chainable, used '"
                       + getName(filterEntityType) + "' behind '"
@@ -559,7 +572,7 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
               // e.g. in case of function returning complex data or a list of complex data
               UriResourceWithKeysImpl lastPartWithKeys = (UriResourceWithKeysImpl) lastResourcePart;
 
-              if (lastPartWithKeys.isCollection() == false) {
+              if (!lastPartWithKeys.isCollection()) {
                 if (lastPartWithKeys.getTypeFilterOnEntry() != null) {
                   throw wrap(new UriParserSemanticException("Entry typefilters are not chainable, used '"
                       + getName(filterComplexType) + "' behind '"
@@ -1193,9 +1206,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
   public Object visitExpandPath(final ExpandPathContext ctx) {
     ExpandItemImpl expandItem = new ExpandItemImpl();
 
-    // UriResourceItImpl pathInfoIT = new UriResourceItImpl();
-    context.contextUriInfo.getLastResourcePart();
-
     // save context
     ExpandItemImpl contextExpandItemPathBU = context.contextExpandItemPath;
     UriInfoImpl uriInfoResourceBU = context.contextUriInfo;
@@ -1203,7 +1213,6 @@ public class UriParseTreeVisitor extends UriParserBaseVisitor<Object> {
     // set tmp context
     context.contextExpandItemPath = expandItem;
     context.contextUriInfo = new UriInfoImpl().setKind(UriInfoKind.resource);
-    // contextUriInfo.addPathInfo(pathInfoIT);
 
     super.visitExpandPath(ctx);
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ac6e9e72/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
index d1ffaab..10240ab 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/uri/antlr/TestFullResourcePath.java
@@ -22,6 +22,11 @@ import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 
 import org.apache.olingo.commons.api.edm.Edm;
+import org.apache.olingo.commons.api.edm.EdmEntityContainer;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.http.HttpContentType;
 import org.apache.olingo.commons.core.Encoder;
 import org.apache.olingo.commons.core.edm.EdmProviderImpl;
@@ -46,6 +51,7 @@ import org.apache.olingo.server.tecsvc.provider.EnumTypeProvider;
 import org.apache.olingo.server.tecsvc.provider.PropertyProvider;
 import org.junit.Ignore;
 import org.junit.Test;
+import org.mockito.Mockito;
 
 public class TestFullResourcePath {
   Edm edm = null;
@@ -248,8 +254,8 @@ public class TestFullResourcePath {
         .isFunction("BFCESBaseTwoKeyNavRTESBaseTwoKey");
 
     testUri.run("ESTwoKeyNav/olingo.odata.test1.ETBaseTwoKeyNav"
-        + "/olingo.odata.test1.BFCESBaseTwoKeyNavRTESBaseTwoKey()"
-        + "/olingo.odata.test1.ETTwoBaseTwoKeyNav")
+            + "/olingo.odata.test1.BFCESBaseTwoKeyNavRTESBaseTwoKey()"
+            + "/olingo.odata.test1.ETTwoBaseTwoKeyNav")
         .isKind(UriInfoKind.resource).goPath()
         .first()
         .isEntitySet("ESTwoKeyNav")
@@ -1474,7 +1480,7 @@ public class TestFullResourcePath {
         .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/olingo.odata.test1.ETBaseTwoKeyNav"
-        + "/NavPropertyETKeyNavMany(3)")
+            + "/NavPropertyETKeyNavMany(3)")
         .isKind(UriInfoKind.resource).goPath()
         .first()
         .isEntitySet("ESTwoKeyNav")
@@ -1766,7 +1772,7 @@ public class TestFullResourcePath {
     .isTypeFilterOnEntry(EntityTypeProvider.nameETBaseTwoKeyNav);
 
     testUri.run("FICRTETTwoKeyNavParam(ParameterInt16=1)(PropertyInt16=2,PropertyString='3')"
-        + "/olingo.odata.test1.ETBaseTwoKeyNav")
+            + "/olingo.odata.test1.ETBaseTwoKeyNav")
         .isKind(UriInfoKind.resource).goPath()
         .first()
         .isFunctionImport("FICRTETTwoKeyNavParam")
@@ -2072,6 +2078,45 @@ public class TestFullResourcePath {
     .isCount();
   }
 
+  /**
+   * Test for EntitySet and NavigationProperty with same name defined in metadata.
+   * (related to Olingo issue OLINGO-741)
+   */
+  @Test
+  public void yetAnotherSmallTest() throws Exception {
+    TestUriValidator testUri = new TestUriValidator();
+
+    Edm mockEdm = Mockito.mock(Edm.class);
+    EdmEntitySet esCategory = Mockito.mock(EdmEntitySet.class);
+    EdmEntitySet esProduct = Mockito.mock(EdmEntitySet.class);
+    EdmEntityType typeCategory = Mockito.mock(EdmEntityType.class);
+    EdmEntityContainer container = Mockito.mock(EdmEntityContainer.class);
+    EdmNavigationProperty productsNavigation = Mockito.mock(EdmNavigationProperty.class);
+    EdmEntityType productsType = Mockito.mock(EdmEntityType.class);
+
+    Mockito.when(mockEdm.getEntityContainer(null)).thenReturn(container);
+    Mockito.when(typeCategory.getName()).thenReturn("Category");
+    Mockito.when(typeCategory.getNamespace()).thenReturn("NS");
+    Mockito.when(esCategory.getEntityType()).thenReturn(typeCategory);
+    Mockito.when(productsNavigation.getName()).thenReturn("Products");
+    Mockito.when(typeCategory.getProperty("Products")).thenReturn(productsNavigation);
+    Mockito.when(container.getEntitySet("Category")).thenReturn(esCategory);
+    Mockito.when(container.getEntitySet("Products")).thenReturn(esProduct);
+    Mockito.when(productsType.getName()).thenReturn("Products");
+    Mockito.when(productsType.getNamespace()).thenReturn("NS");
+    Mockito.when(productsNavigation.getType()).thenReturn(productsType);
+
+    // test and verify
+    testUri.setEdm(mockEdm)
+            .run("Category", "$expand=Products")
+            .isKind(UriInfoKind.resource).goPath().goExpand()
+            .first()
+            .goPath().first()
+            .isNavProperty("Products", new FullQualifiedName("NS", "Products"), false)
+            .isType(new FullQualifiedName("NS", "Products"), false);
+    Mockito.verifyZeroInteractions(esProduct);
+  }
+
   @Test
   public void runExpand() throws Exception {
 
@@ -2362,9 +2407,6 @@ public class TestFullResourcePath {
     .goExpand().first()
     .isExpandStartType(EntityTypeProvider.nameETBaseTwoKeyNav)
     .goPath().first()
-    // .isType(EntityTypeProvider.nameETTwoKeyNav)
-    // .isTypeFilterOnCollection(EntityTypeProvider.nameETBaseTwoKeyNav)
-    // .n()
     .isNavProperty("NavPropertyETKeyNavMany", EntityTypeProvider.nameETKeyNav, true);
 
     testUri.run("ESTwoKeyNav(PropertyInt16=1,PropertyString='Hugo')",


[14/18] olingo-odata4 git commit: [OLINGO-743] Add odatapath to ContextURL

Posted by ch...@apache.org.
[OLINGO-743] Add odatapath to ContextURL


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

Branch: refs/heads/OLINGO-640
Commit: 5e481b23ec0bf41fa83160eca4ce370e936fd7c7
Parents: ac6e9e7
Author: Michael Bolz <mi...@sap.com>
Authored: Fri Jul 31 15:51:34 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Jul 31 15:51:34 2015 +0200

----------------------------------------------------------------------
 .../fit/tecsvc/client/NavigationITCase.java     |  37 ++++
 .../apache/olingo/fit/util/StringHelper.java    | 214 +++++++++++++++++++
 .../olingo/commons/api/data/ContextURL.java     |  15 +-
 .../serializer/utils/ContextURLBuilder.java     |   9 +
 .../processor/TechnicalEntityProcessor.java     |  99 +++++----
 .../serializer/utils/ContextURLHelperTest.java  |  70 ++++++
 6 files changed, 401 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
index e8147a4..40c1de4 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
@@ -20,6 +20,7 @@ package org.apache.olingo.fit.tecsvc.client;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import org.apache.olingo.client.api.ODataClient;
 import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
@@ -31,13 +32,49 @@ import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
 import org.apache.olingo.fit.AbstractBaseTestITCase;
 import org.apache.olingo.fit.tecsvc.TecSvcConst;
+import org.apache.olingo.fit.util.StringHelper;
 import org.junit.Test;
 
+import java.io.InputStream;
+
 public final class NavigationITCase extends AbstractBaseTestITCase {
 
   private final ODataClient client = getClient();
 
   @Test
+  public void navigationToEntityWithRelativeContextUrl() throws Exception {
+    // zero navigation
+    final InputStream zeroLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+            client.newURIBuilder(TecSvcConst.BASE_URI)
+                    .appendEntitySetSegment("ESAllPrim").
+                    appendKeySegment(32767).build()).rawExecute();
+
+    String zeroLevelResponseBody = StringHelper.asString(zeroLevelResponse);
+    assertTrue(zeroLevelResponseBody.contains("\"@odata.context\":\"$metadata#ESAllPrim/$entity\""));
+
+    // one navigation
+    final InputStream oneLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+                    client.newURIBuilder(TecSvcConst.BASE_URI)
+                            .appendEntitySetSegment("ESAllPrim").appendKeySegment(32767)
+                            .appendNavigationSegment("NavPropertyETTwoPrimOne").build())
+                    .rawExecute();
+
+    String oneLevelResponseBody = StringHelper.asString(oneLevelResponse);
+    assertTrue(oneLevelResponseBody.contains("\"@odata.context\":\"../$metadata#ESTwoPrim/$entity\""));
+
+    // two navigation
+    final InputStream twoLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
+                    client.newURIBuilder(TecSvcConst.BASE_URI)
+                            .appendEntitySetSegment("ESTwoPrim").appendKeySegment(32767)
+                            .appendNavigationSegment("NavPropertyETAllPrimOne")
+                            .appendNavigationSegment("NavPropertyETTwoPrimMany").appendKeySegment(-365).build())
+                    .rawExecute();
+
+    String twoLevelResponseBody = StringHelper.asString(twoLevelResponse);
+    assertTrue(twoLevelResponseBody.contains("\"@odata.context\":\"../../$metadata#ESTwoPrim/$entity\""));
+  }
+
+  @Test
   public void oneLevelToEntity() throws Exception {
     final ODataRetrieveResponse<ClientEntity> response =
         client.getRetrieveRequestFactory().getEntityRequest(

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/fit/src/test/java/org/apache/olingo/fit/util/StringHelper.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/util/StringHelper.java b/fit/src/test/java/org/apache/olingo/fit/util/StringHelper.java
new file mode 100644
index 0000000..8b2e9a1
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/util/StringHelper.java
@@ -0,0 +1,214 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ******************************************************************************/
+package org.apache.olingo.fit.util;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Random;
+
+/**
+ *  
+ */
+public class StringHelper {
+
+  public static final String DEFAULT_ENCODING = "UTF-8";
+
+  public static class Stream {
+    private final byte[] data;
+
+    private Stream(final byte[] data) {
+      this.data = data;
+    }
+
+    public Stream(final String content, final String charset) throws UnsupportedEncodingException {
+      this(content.getBytes(charset));
+    }
+
+    public InputStream asStream() {
+      return new ByteArrayInputStream(data);
+    }
+
+    public byte[] asArray() {
+      return data;
+    }
+
+    public int byteLength() {
+      if(data == null) {
+        return -1;
+      }
+      return data.length;
+    }
+
+    public String asString() {
+      return asString(DEFAULT_ENCODING);
+    }
+
+    public String asString(final String charsetName) {
+      return new String(data, Charset.forName(charsetName));
+    }
+
+    public Stream print(final OutputStream out) throws IOException {
+      out.write(data);
+      return this;
+    }
+
+    public Stream print() throws IOException {
+      return print(System.out);
+    }
+
+    public String asStringWithLineSeparation(String separator) throws IOException {
+      BufferedReader br = new BufferedReader(new StringReader(asString()));
+      StringBuilder sb = new StringBuilder(br.readLine());
+      String line = br.readLine();
+      while (line != null) {
+        sb.append(separator).append(line);
+        line = br.readLine();
+      }
+      return sb.toString();
+    }
+
+    public InputStream asStreamWithLineSeparation(String separator) throws IOException {
+      String asString = asStringWithLineSeparation(separator);
+      return new ByteArrayInputStream(asString.getBytes(DEFAULT_ENCODING));
+    }
+
+    /**
+     * Number of lines separated by line breaks (<code>CRLF</code>).
+     * A content string like <code>text\r\nmoreText</code> will result in
+     * a line count of <code>2</code>.
+     * 
+     * @return lines count
+     */
+    public int linesCount() {
+      return StringHelper.countLines(asString(), "\r\n");
+    }
+  }
+
+  public static Stream toStream(final InputStream stream) throws IOException {
+    byte[] result = new byte[0];
+    byte[] tmp = new byte[8192];
+    int readCount = stream.read(tmp);
+    while (readCount >= 0) {
+      byte[] innerTmp = new byte[result.length + readCount];
+      System.arraycopy(result, 0, innerTmp, 0, result.length);
+      System.arraycopy(tmp, 0, innerTmp, result.length, readCount);
+      result = innerTmp;
+      readCount = stream.read(tmp);
+    }
+    stream.close();
+    return new Stream(result);
+  }
+
+  public static Stream toStream(final String content) {
+    return toStream(content, DEFAULT_ENCODING);
+  }
+
+  public static Stream toStream(final String content, final String charset) {
+    try {
+      return new Stream(content, charset);
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 should be supported on each system.");
+    }
+  }
+
+  /**
+   * Read the input stream into an string with default encoding (see StringHelper.DEFAULT_ENCODING).
+   *
+   * @param in stream which is read
+   * @return content of stream as string
+   * @throws IOException
+   */
+  public static String asString(final InputStream in) throws IOException {
+    return toStream(in).asString();
+  }
+
+  public static int countLines(final String content, final String lineBreak) {
+    if (content == null) {
+      return -1;
+    }
+
+    int lastPos = content.indexOf(lineBreak);
+    int count = 1;
+
+    while (lastPos >= 0) {
+      lastPos = content.indexOf(lineBreak, lastPos + 1);
+      count++;
+    }
+    return count;
+  }
+
+  /**
+   * Encapsulate given content in an {@link InputStream} with charset <code>UTF-8</code>.
+   *
+   * @param content to encapsulate content
+   * @return content as stream
+   */
+  public static InputStream encapsulate(final String content) {
+    try {
+      return encapsulate(content, DEFAULT_ENCODING);
+    } catch (UnsupportedEncodingException e) {
+      // we know that UTF-8 is supported
+      throw new RuntimeException("UTF-8 MUST be supported.", e);
+    }
+  }
+
+  /**
+   * Encapsulate given content in an {@link InputStream} with given charset.
+   * 
+   * @param content to encapsulate content
+   * @param charset to be used charset
+   * @return content as stream
+   * @throws UnsupportedEncodingException if charset is not supported
+   */
+  public static InputStream encapsulate(final String content, final String charset)
+      throws UnsupportedEncodingException {
+    return new ByteArrayInputStream(content.getBytes(charset));
+  }
+
+  /**
+   * Generate a string with given length containing random upper case characters ([A-Z]).
+   * 
+   * @param len length of to generated string
+   * @return random upper case characters ([A-Z]).
+   */
+  public static InputStream generateDataStream(final int len) {
+    return encapsulate(generateData(len));
+  }
+
+  /**
+   * Generates a string with given length containing random upper case characters ([A-Z]).
+   * @param len length of the generated string
+   * @return random upper case characters ([A-Z])
+   */
+  public static String generateData(final int len) {
+    Random random = new Random();
+    StringBuilder b = new StringBuilder(len);
+    for (int j = 0; j < len; j++) {
+      final char c = (char) ('A' + random.nextInt('Z' - 'A' + 1));
+      b.append(c);
+    }
+    return b.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
index 3c482c7..bf31d71 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ContextURL.java
@@ -48,6 +48,12 @@ public class ContextURL {
 
   private Suffix suffix;
 
+  private String odataPath;
+
+  public String getODataPath() {
+    return odataPath;
+  }
+
   public enum Suffix {
 
     ENTITY("$entity"), REFERENCE("$ref"),
@@ -55,7 +61,7 @@ public class ContextURL {
 
     private final String representation;
 
-    private Suffix(final String representation) {
+    Suffix(final String representation) {
       this.representation = representation;
     }
 
@@ -128,7 +134,12 @@ public class ContextURL {
 
   public static final class Builder {
 
-    private ContextURL contextURL = new ContextURL();
+    private final ContextURL contextURL = new ContextURL();
+
+    public Builder oDataPath(String oDataPath) {
+      contextURL.odataPath = oDataPath;
+      return this;
+    }
 
     public Builder serviceRoot(final URI serviceRoot) {
       contextURL.serviceRoot = serviceRoot;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
index e79a295..3cc7744 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilder.java
@@ -35,7 +35,16 @@ public final class ContextURLBuilder {
     StringBuilder result = new StringBuilder();
     if (contextURL.getServiceRoot() != null) {
       result.append(contextURL.getServiceRoot());
+    } else if(contextURL.getODataPath() != null) {
+      String oDataPath = contextURL.getODataPath();
+      char[] chars = oDataPath.toCharArray();
+      for (int i = 1; i < chars.length-1; i++) {
+        if(chars[i] == '/' && chars[i-1] != '/') {
+          result.append("../");
+        }
+      }
     }
+
     result.append(Constants.METADATA);
     if (contextURL.getEntitySetOrSingletonOrType() != null) {
       result.append('#');

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
index cba853d..a47f367 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalEntityProcessor.java
@@ -187,7 +187,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
         + odata.createUriHelper().buildCanonicalURL(edmEntitySet, entity);
     final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
     if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
-      response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
+      response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat, expand, null)
               .getContent());
       response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
       response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
@@ -243,7 +243,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
     if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
       response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-      response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
+      response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat)
               .getContent());
       response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
     } else {
@@ -271,12 +271,12 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
         request.getHeaders(HttpHeader.IF_NONE_MATCH));
     checkRequestFormat(requestFormat);
     dataProvider.setMedia(entity, odata.createFixedFormatDeserializer().binary(request.getBody()),
-        requestFormat.toContentTypeString());
+            requestFormat.toContentTypeString());
 
     final Return returnPreference = odata.createPreferences(request.getHeaders(HttpHeader.PREFER)).getReturn();
     if (returnPreference == null || returnPreference == Return.REPRESENTATION) {
-      response.setContent(serializeEntity(entity, edmEntitySet, edmEntityType, responseFormat, null, null)
-          .getContent());
+      response.setContent(serializeEntity(request, entity, edmEntitySet, edmEntityType, responseFormat)
+              .getContent());
       response.setStatusCode(HttpStatusCode.OK.getStatusCode());
       response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
     } else {
@@ -385,16 +385,17 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
 
     final Entity entity = readEntity(uriInfo, true);
     dataProvider.deleteReference(entity,
-        lastNavigation.getProperty(),
-        (uriInfo.getIdOption() != null) ? uriInfo.getIdOption().getValue() : null,
-        request.getRawBaseUri());
+            lastNavigation.getProperty(),
+            (uriInfo.getIdOption() != null) ? uriInfo.getIdOption().getValue() : null,
+            request.getRawBaseUri());
 
     response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
   }
 
   @Override
-  public void readReferenceCollection(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
-      final ContentType requestedContentType) throws ODataApplicationException, ODataLibraryException {
+  public void readReferenceCollection(final ODataRequest request, final ODataResponse response,
+                                      final UriInfo uriInfo, final ContentType requestedContentType)
+          throws ODataApplicationException, ODataLibraryException {
     readEntityCollection(request, response, uriInfo, requestedContentType, true);
   }
 
@@ -440,7 +441,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
 
     final SerializerResult serializerResult = isReference ?
         serializeReference(entity, edmEntitySet, requestedFormat) :
-        serializeEntity(entitySerialization, edmEntitySet, edmEntityType, requestedFormat, expand, select);
+        serializeEntity(request, entitySerialization, edmEntitySet, edmEntityType, requestedFormat, expand, select);
 
     if (entity.getETag() != null) {
       response.setHeader(HttpHeader.ETAG, entity.getETag());
@@ -516,7 +517,7 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     // Serialize
     final SerializerResult serializerResult = (isReference) ? 
         serializeReferenceCollection(entitySetSerialization, edmEntitySet, requestedContentType, countOption) :
-        serializeEntityCollection(entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
+        serializeEntityCollection(request, entitySetSerialization, edmEntitySet, edmEntityType, requestedContentType,
             expand, select, countOption);
 
     response.setContent(serializerResult.getContent());
@@ -528,21 +529,23 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
     }
   }
 
-  private SerializerResult serializeEntityCollection(final EntityCollection entityCollection,
+  private SerializerResult serializeEntityCollection(final ODataRequest request, final EntityCollection
+          entityCollection,
       final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat,
       final ExpandOption expand, final SelectOption select, final CountOption countOption)
       throws ODataLibraryException {
-    
+
     return odata.createSerializer(requestedFormat).entityCollection(
-        serviceMetadata,
-        edmEntityType,
-        entityCollection,
-        EntityCollectionSerializerOptions.with()
-            .contextURL(isODataMetadataNone(requestedFormat) ? null :
-                getContextUrl(edmEntitySet, edmEntityType, false, expand, select))
-            .count(countOption)
-            .expand(expand).select(select)
-            .build());
+            serviceMetadata,
+            edmEntityType,
+            entityCollection,
+            EntityCollectionSerializerOptions.with()
+                    .contextURL(isODataMetadataNone(requestedFormat) ? null :
+                            getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, false, expand,
+                                    select))
+                    .count(countOption)
+                    .expand(expand).select(select)
+                    .build());
   }
 
   private SerializerResult serializeReferenceCollection(final EntityCollection entityCollection, 
@@ -550,36 +553,50 @@ public class TechnicalEntityProcessor extends TechnicalProcessor
           throws ODataLibraryException {
 
     return odata.createSerializer(requestedFormat)
-        .referenceCollection(serviceMetadata, edmEntitySet, entityCollection,ReferenceCollectionSerializerOptions.with()
-            .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
-            .count(countOption).build());
+        .referenceCollection(serviceMetadata, edmEntitySet, entityCollection,
+                ReferenceCollectionSerializerOptions.with()
+                        .contextURL(ContextURL.with().asCollection().suffix(Suffix.REFERENCE).build())
+                        .count(countOption).build());
   }
 
   private SerializerResult serializeReference(final Entity entity, final EdmEntitySet edmEntitySet,
       final ContentType requestedFormat) throws ODataLibraryException {
     return odata.createSerializer(requestedFormat)
         .reference(serviceMetadata, edmEntitySet, entity, ReferenceSerializerOptions.with()
-            .contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
+                .contextURL(ContextURL.with().suffix(Suffix.REFERENCE).build()).build());
             
   }
 
-  private SerializerResult serializeEntity(final Entity entity,
-      final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType, final ContentType requestedFormat,
-      final ExpandOption expand, final SelectOption select) throws ODataLibraryException {
+  private SerializerResult serializeEntity(final ODataRequest request, final Entity entity,
+                                           final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
+                                           final ContentType requestedFormat) throws ODataLibraryException {
+    return serializeEntity(request, entity, edmEntitySet, edmEntityType, requestedFormat, null, null);
+  }
+
+  private SerializerResult serializeEntity(final ODataRequest request, final Entity entity,
+                                           final EdmEntitySet edmEntitySet, final EdmEntityType edmEntityType,
+                                           final ContentType requestedFormat,
+                                           final ExpandOption expand, final SelectOption select)
+          throws ODataLibraryException {
+
+    ContextURL contextUrl = isODataMetadataNone(requestedFormat) ? null :
+          getContextUrl(request.getRawODataPath(), edmEntitySet, edmEntityType, true, expand, null);
     return odata.createSerializer(requestedFormat).entity(
-        serviceMetadata,
-        edmEntityType,
-        entity,
-        EntitySerializerOptions.with()
-            .contextURL(isODataMetadataNone(requestedFormat) ? null :
-                getContextUrl(edmEntitySet, edmEntityType, true, expand, select))
-            .expand(expand).select(select)
-            .build());
+            serviceMetadata,
+            edmEntityType,
+            entity,
+            EntitySerializerOptions.with()
+                    .contextURL(contextUrl)
+                    .expand(expand).select(select)
+                    .build());
   }
 
-  private ContextURL getContextUrl(final EdmEntitySet entitySet, final EdmEntityType entityType,
-      final boolean isSingleEntity, final ExpandOption expand, final SelectOption select) throws ODataLibraryException {
-    Builder builder = ContextURL.with();
+  private ContextURL getContextUrl(String rawODataPath, final EdmEntitySet entitySet, final EdmEntityType entityType,
+                                   final boolean isSingleEntity, final ExpandOption expand, final SelectOption select)
+          throws ODataLibraryException {
+    //
+    //
+    Builder builder = ContextURL.with().oDataPath(rawODataPath);
     builder = entitySet == null ?
         isSingleEntity ? builder.type(entityType) : builder.asCollection().type(entityType) :
         builder.entitySet(entitySet);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/5e481b23/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
index b94f97e..fe86896 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLHelperTest.java
@@ -95,6 +95,76 @@ public class ContextURLHelperTest {
         ContextURLBuilder.create(contextURL).toASCIIString());
   }
 
+
+  @Test
+  public void buildEntity() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
+    final ContextURL contextURL = ContextURL.with().entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("$metadata#ESTwoPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
+  // /odata.svc/ESAllPrim(32767)/NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne/
+  //                            NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne/NavPropertyETTwoPrimOne
+  // @odata.context: "../../../../../$metadata#ESTwoPrim/$entity"
+  @Test
+  public void buildRelativeFiveNavigation() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
+    String odataPath = "ESAllPrim(32767)/NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne/" +
+                        "NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne/NavPropertyETTwoPrimOne";
+    ContextURL contextURL = ContextURL.with()
+            .oDataPath("/" + odataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../../../../$metadata#ESTwoPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+
+    // removed leading '/'
+    contextURL = ContextURL.with()
+            .oDataPath(odataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../../../../$metadata#ESTwoPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
+  // odata.svc/ESAllPrim(32767)/NavPropertyETTwoPrimOne
+  // @odata.context: "$metadata#ESTwoPrim/$entity",
+  @Test
+  public void buildRelativeNavigation() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
+    final String oDataPath = "ESAllPrim(32767)/NavPropertyETTwoPrimOne";
+    ContextURL contextURL = ContextURL.with().oDataPath("/" + oDataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../$metadata#ESTwoPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+
+    // without leading '/'
+    contextURL = ContextURL.with().oDataPath(oDataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../$metadata#ESTwoPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
+  // /odata.svc/ESAllPrim(32767)/NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne
+  // @odata.context: "$metadata#ESAllPrim/$entity",
+  @Test
+  public void buildRelativeTwoNavigation() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESAllPrim");
+    String oDataPath = "ESAllPrim(32767)/NavPropertyETTwoPrimOne/NavPropertyETAllPrimOne";
+    ContextURL contextURL = ContextURL.with()
+            .oDataPath("/" + oDataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../$metadata#ESAllPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+
+    // without leading '/'
+    contextURL = ContextURL.with().oDataPath(oDataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../$metadata#ESAllPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+
+    // without unnecessary '///'
+    contextURL = ContextURL.with().oDataPath("///" + oDataPath)
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../$metadata#ESAllPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+    // without unnecessary '///' between
+    contextURL = ContextURL.with().oDataPath(oDataPath.replace("/", "///"))
+            .entitySet(entitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    assertEquals("../../$metadata#ESAllPrim/$entity", ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
   @Test
   public void buildExpandAll() throws Exception {
     final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");


[09/18] olingo-odata4 git commit: [OLINGO-713] Added tutorial project for system query options - expand/select

Posted by ch...@apache.org.
[OLINGO-713] Added tutorial project for system query options - expand/select


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

Branch: refs/heads/OLINGO-640
Commit: b477bde07b190717b0e6ef443efcef1ca1b3d57e
Parents: 3dae763
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Jul 27 09:57:17 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Jul 27 10:12:14 2015 +0200

----------------------------------------------------------------------
 samples/tutorials/p5_queryoptions-tis/pom.xml   |  79 ++++++
 .../myservice/mynamespace/data/Storage.java     | 130 ++++++++++
 .../mynamespace/service/DemoEdmProvider.java    | 154 ++++++++++++
 .../service/DemoEntityCollectionProcessor.java  | 142 +++++++++++
 .../service/DemoEntityProcessor.java            | 118 +++++++++
 .../service/DemoPrimitiveProcessor.java         | 150 +++++++++++
 .../java/myservice/mynamespace/util/Util.java   | 105 ++++++++
 .../myservice/mynamespace/web/DemoServlet.java  |  76 ++++++
 .../src/main/webapp/WEB-INF/web.xml             |  40 +++
 .../src/main/webapp/index.jsp                   |  26 ++
 samples/tutorials/p5_queryoptions/pom.xml       |  79 ------
 .../myservice/mynamespace/data/Storage.java     | 130 ----------
 .../mynamespace/service/DemoEdmProvider.java    | 154 ------------
 .../service/DemoEntityCollectionProcessor.java  | 142 -----------
 .../service/DemoEntityProcessor.java            | 118 ---------
 .../service/DemoPrimitiveProcessor.java         | 150 -----------
 .../java/myservice/mynamespace/util/Util.java   | 105 --------
 .../myservice/mynamespace/web/DemoServlet.java  |  76 ------
 .../src/main/webapp/WEB-INF/web.xml             |  40 ---
 .../p5_queryoptions/src/main/webapp/index.jsp   |  26 --
 samples/tutorials/p6_queryoptions-es/pom.xml    |  80 ++++++
 .../myservice/mynamespace/data/Storage.java     | 252 +++++++++++++++++++
 .../mynamespace/service/DemoEdmProvider.java    | 211 ++++++++++++++++
 .../service/DemoEntityCollectionProcessor.java  | 160 ++++++++++++
 .../service/DemoEntityProcessor.java            | 235 +++++++++++++++++
 .../service/DemoPrimitiveProcessor.java         | 150 +++++++++++
 .../java/myservice/mynamespace/util/Util.java   | 149 +++++++++++
 .../myservice/mynamespace/web/DemoServlet.java  |  75 ++++++
 .../src/main/webapp/WEB-INF/web.xml             |  34 +++
 .../src/main/webapp/index.jsp                   |  43 ++++
 samples/tutorials/pom.xml                       |   3 +-
 31 files changed, 2411 insertions(+), 1021 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/pom.xml b/samples/tutorials/p5_queryoptions-tis/pom.xml
new file mode 100755
index 0000000..db1e18c
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/pom.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<groupId>my.group.id</groupId>
+	<artifactId>DemoService-QueryOptions-TIS</artifactId>
+	<packaging>war</packaging>
+	<version>0.0.1</version>
+
+	<name>${project.artifactId}-Webapp</name>
+
+	<build>
+		<finalName>DemoService</finalName>
+	</build>
+
+	<properties>
+		<javax.version>2.5</javax.version>
+		<odata.version>4.0.0-beta-03</odata.version>
+		<slf4j.version>1.7.7</slf4j.version>
+	</properties>
+
+	<dependencies>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>servlet-api</artifactId>
+			<version>${javax.version}</version>
+			<scope>provided</scope>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-server-core</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-api</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.olingo</groupId>
+			<artifactId>odata-commons-core</artifactId>
+			<version>${odata.version}</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-simple</artifactId>
+			<version>${slf4j.version}</version>
+			<scope>runtime</scope>
+		</dependency>
+	</dependencies>
+</project>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/data/Storage.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/data/Storage.java
new file mode 100755
index 0000000..2aa9fac
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/data/Storage.java
@@ -0,0 +1,130 @@
+/*
+ * 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 myservice.mynamespace.data;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.util.Util;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.data.ValueType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriParameter;
+
+public class Storage {
+
+	private List<Entity> productList;
+
+	public Storage() {
+		productList = new ArrayList<Entity>();
+		initSampleData();
+	}
+
+	/* PUBLIC FACADE */
+
+	public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet)throws ODataApplicationException{
+
+		// actually, this is only required if we have more than one Entity Sets
+		if(edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)){
+			return getProducts();
+		}
+
+		return null;
+	}
+
+	public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
+					throws ODataApplicationException{
+
+		EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+
+		// actually, this is only required if we have more than one Entity Type
+		if(edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)){
+			return getProduct(edmEntityType, keyParams);
+		}
+
+		return null;
+	}
+
+
+
+	/*  INTERNAL */
+
+	private EntityCollection getProducts(){
+		EntityCollection retEntitySet = new EntityCollection();
+
+		for(Entity productEntity : this.productList){
+			   retEntitySet.getEntities().add(productEntity);
+		}
+
+		return retEntitySet;
+	}
+
+
+	private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
+					throws ODataApplicationException{
+
+		// the list of entities at runtime
+		EntityCollection entitySet = getProducts();
+		
+		/*  generic approach  to find the requested entity */
+		Entity requestedEntity = Util.findEntity(edmEntityType, entitySet, keyParams);
+		
+		if(requestedEntity == null){
+			// this variable is null if our data doesn't contain an entity for the requested key
+			// Throw suitable exception
+			throw new ODataApplicationException("Entity for requested key doesn't exist",
+          HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
+		}
+
+		return requestedEntity;
+	}
+
+	/* HELPER */
+
+	private void initSampleData(){
+
+		// add some sample product entities
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")));
+
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")));
+
+		productList.add(new Entity()
+			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3))
+			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"))
+			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
+              "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
+
+	}
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
new file mode 100755
index 0000000..3c28a21
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
@@ -0,0 +1,154 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.olingo.commons.api.ODataException;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
+import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
+import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
+import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
+import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
+
+public class DemoEdmProvider extends CsdlAbstractEdmProvider {
+
+  // Service Namespace
+  public static final String NAMESPACE = "OData.Demo";
+
+  // EDM Container
+  public static final String CONTAINER_NAME = "Container";
+  public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
+
+  // Entity Types Names
+  public static final String ET_PRODUCT_NAME = "Product";
+  public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);
+
+  // Entity Set Names
+  public static final String ES_PRODUCTS_NAME = "Products";
+
+  @Override
+  public CsdlEntityType getEntityType(FullQualifiedName entityTypeName)
+      throws ODataException {
+    // this method is called for one of the EntityTypes that are configured in the Schema
+    if (ET_PRODUCT_FQN.equals(entityTypeName)) {
+
+      // create EntityType properties
+      CsdlProperty id = new CsdlProperty().setName("ID").setType(
+          EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
+      CsdlProperty name = new CsdlProperty().setName("Name").setType(
+          EdmPrimitiveTypeKind.String.getFullQualifiedName());
+      CsdlProperty description = new CsdlProperty().setName("Description").setType(
+          EdmPrimitiveTypeKind.String.getFullQualifiedName());
+
+      // create PropertyRef for Key element
+      CsdlPropertyRef propertyRef = new CsdlPropertyRef();
+      propertyRef.setName("ID");
+
+      // configure EntityType
+      CsdlEntityType entityType = new CsdlEntityType();
+      entityType.setName(ET_PRODUCT_NAME);
+      entityType.setProperties(Arrays.asList(id, name, description));
+      entityType.setKey(Collections.singletonList(propertyRef));
+
+      return entityType;
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer,
+      String entitySetName) throws ODataException {
+    if (entityContainer.equals(CONTAINER)) {
+      if (entitySetName.equals(ES_PRODUCTS_NAME)) {
+        CsdlEntitySet entitySet = new CsdlEntitySet();
+        entitySet.setName(ES_PRODUCTS_NAME);
+        entitySet.setType(ET_PRODUCT_FQN);
+
+        return entitySet;
+      }
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public CsdlEntityContainerInfo getEntityContainerInfo(
+      FullQualifiedName entityContainerName) throws ODataException {
+    // This method is invoked when displaying the service document at
+    // e.g. http://localhost:8080/DemoService/DemoService.svc
+    if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
+      CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
+      entityContainerInfo.setContainerName(CONTAINER);
+      return entityContainerInfo;
+    }
+
+    return null;
+
+  }
+
+  @Override
+  public List<CsdlSchema> getSchemas() throws ODataException {
+    // create Schema
+    CsdlSchema schema = new CsdlSchema();
+    schema.setNamespace(NAMESPACE);
+
+    // add EntityTypes
+    List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
+    entityTypes.add(getEntityType(ET_PRODUCT_FQN));
+    schema.setEntityTypes(entityTypes);
+
+    // add EntityContainer
+    schema.setEntityContainer(getEntityContainer());
+
+    // finally
+    List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
+    schemas.add(schema);
+
+    return schemas;
+
+  }
+
+  @Override
+  public CsdlEntityContainer getEntityContainer() throws ODataException {
+    // create EntitySets
+    List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
+    entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
+
+    // create EntityContainer
+    CsdlEntityContainer entityContainer = new CsdlEntityContainer();
+    entityContainer.setName(CONTAINER_NAME);
+    entityContainer.setEntitySets(entitySets);
+
+    return entityContainer;
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
new file mode 100755
index 0000000..fc58c23
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.queryoption.CountOption;
+import org.apache.olingo.server.api.uri.queryoption.SkipOption;
+import org.apache.olingo.server.api.uri.queryoption.TopOption;
+
+public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
+
+  private OData odata;
+  private ServiceMetadata serviceMetadata;
+  private Storage storage;
+
+  public DemoEntityCollectionProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+  }
+
+  public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+      ContentType responseFormat) throws ODataApplicationException, SerializerException {
+
+    // 1st retrieve the requested EntitySet from the uriInfo (representation of the parsed URI)
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    // in our example, the first segment is the EntitySet
+    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+    // 2nd: fetch the data from backend for this requested EntitySetName and deliver as EntitySet
+    EntityCollection entityCollection = storage.readEntitySetData(edmEntitySet);
+
+    // 3rd: apply System Query Options
+    // modify the result set according to the query options, specified by the end user
+    List<Entity> entityList = entityCollection.getEntities();
+    EntityCollection returnEntityCollection = new EntityCollection();
+
+    // handle $count: always return the original number of entities, without considering $top and $skip
+    CountOption countOption = uriInfo.getCountOption();
+    if (countOption != null) {
+      boolean isCount = countOption.getValue();
+      if (isCount) {
+        returnEntityCollection.setCount(entityList.size());
+      }
+    }
+
+    // handle $skip
+    SkipOption skipOption = uriInfo.getSkipOption();
+    if (skipOption != null) {
+      int skipNumber = skipOption.getValue();
+      if (skipNumber >= 0 && skipNumber <= entityList.size()) {
+        entityList = entityList.subList(skipNumber, entityList.size());
+      } else {
+        throw new ODataApplicationException("Invalid value for $skip", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+            Locale.ROOT);
+      }
+    }
+
+    // handle $top
+    TopOption topOption = uriInfo.getTopOption();
+    if (topOption != null) {
+      int topNumber = topOption.getValue();
+      if (topNumber >= 0 && topNumber <= entityList.size()) {
+        entityList = entityList.subList(0, topNumber);
+      } else {
+        throw new ODataApplicationException("Invalid value for $top", HttpStatusCode.BAD_REQUEST.getStatusCode(),
+            Locale.ROOT);
+      }
+    }
+
+    // after applying the system query options, create the EntityCollection based on the reduced list
+    for (Entity entity : entityList) {
+      returnEntityCollection.getEntities().add(entity);
+    }
+
+    // 4th: create a serializer based on the requested format (json)
+    ODataFormat format = ODataFormat.fromContentType(responseFormat);
+    ODataSerializer serializer = odata.createSerializer(format);
+
+    // and serialize the content: transform from the EntitySet object to InputStream
+    EdmEntityType edmEntityType = edmEntitySet.getEntityType();
+    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
+
+    EntityCollectionSerializerOptions opts =
+        EntityCollectionSerializerOptions.with().contextURL(contextUrl).count(countOption).build();
+    SerializerResult serializerResult =
+        serializer.entityCollection(serviceMetadata, edmEntityType, returnEntityCollection, opts);
+    InputStream serializedContent = serializerResult.getContent();
+
+    // 5th: configure the response object: set the body, headers and status code
+    response.setContent(serializedContent);
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
new file mode 100755
index 0000000..81453a0
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
@@ -0,0 +1,118 @@
+/*
+ * 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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.EntityProcessor;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+
+public class DemoEntityProcessor implements EntityProcessor {
+
+  private OData odata;
+  private ServiceMetadata serviceMetadata;
+  private Storage storage;
+
+  public DemoEntityProcessor(Storage storage) {
+    this.storage = storage;
+  }
+
+  public void init(OData odata, ServiceMetadata serviceMetadata) {
+    this.odata = odata;
+    this.serviceMetadata = serviceMetadata;
+  }
+
+  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
+      throws ODataApplicationException, SerializerException {
+
+    // 1. retrieve the Entity Type
+    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
+    // Note: only in our example we can assume that the first segment is the EntitySet
+    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
+    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
+
+    // 2. retrieve the data from backend
+    List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
+    Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+
+    // 3. serialize
+    EdmEntityType entityType = edmEntitySet.getEntityType();
+
+    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).suffix(ContextURL.Suffix.ENTITY).build();
+    // expand and select currently not supported
+    EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();
+
+    ODataFormat oDataFormat = ODataFormat.fromContentType(responseFormat);
+    ODataSerializer serializer = this.odata.createSerializer(oDataFormat);
+    SerializerResult serializerResult = serializer.entity(serviceMetadata, entityType, entity, options);
+    InputStream entityStream = serializerResult.getContent();
+
+    // 4. configure the response object
+    response.setContent(entityStream);
+    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+  }
+
+  /*
+   * These processor methods are not handled in this tutorial
+   */
+
+  public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
+      ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
+      ContentType responseFormat)
+      throws ODataApplicationException, DeserializerException, SerializerException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+  public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+      throws ODataApplicationException {
+    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
new file mode 100755
index 0000000..64f7949
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.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 myservice.mynamespace.service;
+
+import java.io.InputStream;
+import java.util.List;
+import java.util.Locale;
+
+import myservice.mynamespace.data.Storage;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.processor.PrimitiveProcessor;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.serializer.SerializerResult;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+
+public class DemoPrimitiveProcessor implements PrimitiveProcessor {
+
+	private OData odata;
+	private Storage storage;
+
+	public DemoPrimitiveProcessor(Storage storage) {
+		this.storage = storage;
+	}
+
+	public void init(OData odata, ServiceMetadata serviceMetadata) {
+		this.odata = odata;
+
+	}
+
+	/*
+	 * In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name
+	 * and the response:
+	 * {
+	 *	  @odata.context: "$metadata#Products/Name",
+	 *	  value: "Notebook Basic 15"
+	 * }
+	 * */
+	public void readPrimitive(ODataRequest request, ODataResponse response,
+								UriInfo uriInfo, ContentType responseFormat)
+								throws ODataApplicationException, SerializerException {
+
+		// 1. Retrieve info from URI
+		// 1.1. retrieve the info about the requested entity set
+		List<UriResource> resourceParts = uriInfo.getUriResourceParts();
+		// Note: only in our example we can rely that the first segment is the EntitySet
+		UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
+		EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
+		// the key for the entity
+		List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();
+
+		// 1.2. retrieve the requested (Edm) property
+		// the last segment is the Property
+		UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1);
+		EdmProperty edmProperty = uriProperty.getProperty();
+		String edmPropertyName = edmProperty.getName();
+		// in our example, we know we have only primitive types in our model
+		EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();
+
+
+		// 2. retrieve data from backend
+		// 2.1. retrieve the entity data, for which the property has to be read
+		Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
+		if (entity == null) { // Bad request
+			throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+		}
+
+		// 2.2. retrieve the property data from the entity
+		Property property = entity.getProperty(edmPropertyName);
+		if (property == null) {
+			throw new ODataApplicationException("Property not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
+		}
+
+		// 3. serialize
+		Object value = property.getValue();
+		if (value != null) {
+			// 3.1. configure the serializer
+			ODataFormat format = ODataFormat.fromContentType(responseFormat);
+			ODataSerializer serializer = odata.createSerializer(format);
+
+			ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
+			PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
+			// 3.2. serialize
+			SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options);
+			InputStream propertyStream = serializerResult.getContent();
+
+			//4. configure the response object
+			response.setContent(propertyStream);
+			response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+			response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
+		} else {
+			// in case there's no value for the property, we can skip the serialization
+			response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
+		}
+	}
+
+
+
+	/*
+	 * These processor methods are not handled in this tutorial
+	 * */
+
+	public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo,
+                              ContentType requestFormat, ContentType responseFormat)
+								throws ODataApplicationException, DeserializerException, SerializerException {
+		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+	}
+
+	public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
+          throws ODataApplicationException {
+		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
+	}
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/util/Util.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/util/Util.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/util/Util.java
new file mode 100755
index 0000000..c21d352
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/util/Util.java
@@ -0,0 +1,105 @@
+/*
+ * 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 myservice.mynamespace.util;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+
+public class Util {
+  
+  public static Entity findEntity(EdmEntityType edmEntityType, EntityCollection entitySet,
+                                  List<UriParameter> keyParams) throws ODataApplicationException {
+
+    List<Entity> entityList = entitySet.getEntities();
+
+    // loop over all entities in order to find that one that matches all keys in request
+    // e.g. contacts(ContactID=1, CompanyID=1)
+    for (Entity entity: entityList) {
+      boolean foundEntity = entityMatchesAllKeys(edmEntityType, entity, keyParams);
+      if (foundEntity) {
+        return entity;
+      }
+    }
+
+    return null;
+  }
+
+  public static boolean entityMatchesAllKeys(EdmEntityType edmEntityType, Entity entity, List<UriParameter> keyParams)
+          throws ODataApplicationException {
+
+    // loop over all keys
+    for (final UriParameter key : keyParams) {
+      // key
+      String keyName = key.getName();
+      String keyText = key.getText();
+
+      // Edm: we need this info for the comparison below
+      EdmProperty edmKeyProperty = (EdmProperty) edmEntityType.getProperty(keyName);
+      Boolean isNullable = edmKeyProperty.isNullable();
+      Integer maxLength = edmKeyProperty.getMaxLength();
+      Integer precision = edmKeyProperty.getPrecision();
+      Boolean isUnicode = edmKeyProperty.isUnicode();
+      Integer scale = edmKeyProperty.getScale();
+      // get the EdmType in order to compare
+      EdmType edmType = edmKeyProperty.getType();
+      EdmPrimitiveType edmPrimitiveType = (EdmPrimitiveType) edmType;
+
+      // Runtime data: the value of the current entity
+      // don't need to check for null, this is done in olingo library
+      Object valueObject = entity.getProperty(keyName).getValue();
+
+      // now need to compare the valueObject with the keyText String
+      // this is done using the type.valueToString
+      String valueAsString;
+      try {
+        valueAsString = edmPrimitiveType.valueToString(valueObject, isNullable, maxLength, precision, scale, isUnicode);
+      } catch (EdmPrimitiveTypeException e) {
+        throw new ODataApplicationException("Failed to retrieve String value", HttpStatusCode.INTERNAL_SERVER_ERROR
+                .getStatusCode(), Locale.ENGLISH, e);
+      }
+
+      if (valueAsString == null) {
+        return false;
+      }
+
+      boolean matches = valueAsString.equals(keyText);
+      if (!matches) {
+        // if any of the key properties is not found in the entity, we don't need to search further
+        return false;
+      }
+    }
+
+    return true;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/web/DemoServlet.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/web/DemoServlet.java b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/web/DemoServlet.java
new file mode 100755
index 0000000..fe5cdbb
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/java/myservice/mynamespace/web/DemoServlet.java
@@ -0,0 +1,76 @@
+/*
+ * 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 myservice.mynamespace.web;
+
+import java.io.IOException;
+import java.lang.Override;import java.lang.RuntimeException;import java.util.ArrayList;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import myservice.mynamespace.data.Storage;
+import myservice.mynamespace.service.DemoEdmProvider;
+import myservice.mynamespace.service.DemoEntityCollectionProcessor;
+import myservice.mynamespace.service.DemoEntityProcessor;
+import myservice.mynamespace.service.DemoPrimitiveProcessor;
+
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataHttpHandler;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DemoServlet extends HttpServlet {
+
+  private static final long serialVersionUID = 1L;
+  private static final Logger LOG = LoggerFactory.getLogger(DemoServlet.class);
+
+
+  @Override
+  protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+    try {
+      HttpSession session = req.getSession(true);
+      Storage storage = (Storage) session.getAttribute(Storage.class.getName());
+      if (storage == null) {
+        storage = new Storage();
+        session.setAttribute(Storage.class.getName(), storage);
+      }
+
+      // create odata handler and configure it with EdmProvider and Processor
+      OData odata = OData.newInstance();
+      ServiceMetadata edm = odata.createServiceMetadata(new DemoEdmProvider(), new ArrayList<EdmxReference>());
+      ODataHttpHandler handler = odata.createHandler(edm);
+      handler.register(new DemoEntityCollectionProcessor(storage));
+      handler.register(new DemoEntityProcessor(storage));
+      handler.register(new DemoPrimitiveProcessor(storage));
+
+      // let the handler do the work
+      handler.process(req, resp);
+    } catch (RuntimeException e) {
+      LOG.error("Server Error occurred in ExampleServlet", e);
+      throw new ServletException(e);
+    }
+
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/webapp/WEB-INF/web.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/webapp/WEB-INF/web.xml b/samples/tutorials/p5_queryoptions-tis/src/main/webapp/WEB-INF/web.xml
new file mode 100755
index 0000000..21de52a
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+				 id="WebApp_ID" version="2.5">
+
+	<!-- Register the HttpServlet implementation -->
+	<servlet>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <servlet-class>myservice.mynamespace.web.DemoServlet</servlet-class>
+	  <load-on-startup>1</load-on-startup>
+	</servlet>
+	
+	<!-- 
+		Our OData service can be invoked at 
+		http://localhost:8080/DemoService/DemoService.svc
+	-->
+	<servlet-mapping>
+	  <servlet-name>DemoServlet</servlet-name>
+	  <url-pattern>/DemoService.svc/*</url-pattern>
+	</servlet-mapping>
+</web-app>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions-tis/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions-tis/src/main/webapp/index.jsp b/samples/tutorials/p5_queryoptions-tis/src/main/webapp/index.jsp
new file mode 100755
index 0000000..7ffb4ba
--- /dev/null
+++ b/samples/tutorials/p5_queryoptions-tis/src/main/webapp/index.jsp
@@ -0,0 +1,26 @@
+<!--
+
+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.
+
+-->
+<html>
+<body>
+<h2>Hello World!</h2>
+<a href="DemoService.svc/">OData Olingo V4 Demo Service</a>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/pom.xml
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/pom.xml b/samples/tutorials/p5_queryoptions/pom.xml
deleted file mode 100755
index 117f59d..0000000
--- a/samples/tutorials/p5_queryoptions/pom.xml
+++ /dev/null
@@ -1,79 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-
-    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.
-
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-	<modelVersion>4.0.0</modelVersion>
-	<groupId>my.group.id</groupId>
-	<artifactId>DemoService-QueryOptions</artifactId>
-	<packaging>war</packaging>
-	<version>0.0.1</version>
-
-	<name>${project.artifactId}-Webapp</name>
-
-	<build>
-		<finalName>DemoService</finalName>
-	</build>
-
-	<properties>
-		<javax.version>2.5</javax.version>
-		<odata.version>4.0.0-beta-03</odata.version>
-		<slf4j.version>1.7.7</slf4j.version>
-	</properties>
-
-	<dependencies>
-		<dependency>
-			<groupId>javax.servlet</groupId>
-			<artifactId>servlet-api</artifactId>
-			<version>${javax.version}</version>
-			<scope>provided</scope>
-		</dependency>
-
-		<dependency>
-			<groupId>org.apache.olingo</groupId>
-			<artifactId>odata-server-api</artifactId>
-			<version>${odata.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.olingo</groupId>
-			<artifactId>odata-server-core</artifactId>
-			<version>${odata.version}</version>
-		</dependency>
-
-		<dependency>
-			<groupId>org.apache.olingo</groupId>
-			<artifactId>odata-commons-api</artifactId>
-			<version>${odata.version}</version>
-		</dependency>
-		<dependency>
-			<groupId>org.apache.olingo</groupId>
-			<artifactId>odata-commons-core</artifactId>
-			<version>${odata.version}</version>
-		</dependency>
-
-		<dependency>
-			<groupId>org.slf4j</groupId>
-			<artifactId>slf4j-simple</artifactId>
-			<version>${slf4j.version}</version>
-			<scope>runtime</scope>
-		</dependency>
-	</dependencies>
-</project>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
deleted file mode 100755
index 2aa9fac..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/data/Storage.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.data;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import myservice.mynamespace.service.DemoEdmProvider;
-import myservice.mynamespace.util.Util;
-
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.EntityCollection;
-import org.apache.olingo.commons.api.data.Property;
-import org.apache.olingo.commons.api.data.ValueType;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.uri.UriParameter;
-
-public class Storage {
-
-	private List<Entity> productList;
-
-	public Storage() {
-		productList = new ArrayList<Entity>();
-		initSampleData();
-	}
-
-	/* PUBLIC FACADE */
-
-	public EntityCollection readEntitySetData(EdmEntitySet edmEntitySet)throws ODataApplicationException{
-
-		// actually, this is only required if we have more than one Entity Sets
-		if(edmEntitySet.getName().equals(DemoEdmProvider.ES_PRODUCTS_NAME)){
-			return getProducts();
-		}
-
-		return null;
-	}
-
-	public Entity readEntityData(EdmEntitySet edmEntitySet, List<UriParameter> keyParams)
-					throws ODataApplicationException{
-
-		EdmEntityType edmEntityType = edmEntitySet.getEntityType();
-
-		// actually, this is only required if we have more than one Entity Type
-		if(edmEntityType.getName().equals(DemoEdmProvider.ET_PRODUCT_NAME)){
-			return getProduct(edmEntityType, keyParams);
-		}
-
-		return null;
-	}
-
-
-
-	/*  INTERNAL */
-
-	private EntityCollection getProducts(){
-		EntityCollection retEntitySet = new EntityCollection();
-
-		for(Entity productEntity : this.productList){
-			   retEntitySet.getEntities().add(productEntity);
-		}
-
-		return retEntitySet;
-	}
-
-
-	private Entity getProduct(EdmEntityType edmEntityType, List<UriParameter> keyParams)
-					throws ODataApplicationException{
-
-		// the list of entities at runtime
-		EntityCollection entitySet = getProducts();
-		
-		/*  generic approach  to find the requested entity */
-		Entity requestedEntity = Util.findEntity(edmEntityType, entitySet, keyParams);
-		
-		if(requestedEntity == null){
-			// this variable is null if our data doesn't contain an entity for the requested key
-			// Throw suitable exception
-			throw new ODataApplicationException("Entity for requested key doesn't exist",
-          HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ENGLISH);
-		}
-
-		return requestedEntity;
-	}
-
-	/* HELPER */
-
-	private void initSampleData(){
-
-		// add some sample product entities
-		productList.add(new Entity()
-			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 1))
-			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Notebook Basic 15"))
-			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
-              "Notebook Basic, 1.7GHz - 15 XGA - 1024MB DDR2 SDRAM - 40GB")));
-
-		productList.add(new Entity()
-			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 2))
-			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "1UMTS PDA"))
-			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
-              "Ultrafast 3G UMTS/HSDPA Pocket PC, supports GSM network")));
-
-		productList.add(new Entity()
-			.addProperty(new Property(null, "ID", ValueType.PRIMITIVE, 3))
-			.addProperty(new Property(null, "Name", ValueType.PRIMITIVE, "Ergo Screen"))
-			.addProperty(new Property(null, "Description", ValueType.PRIMITIVE,
-              "19 Optimum Resolution 1024 x 768 @ 85Hz, resolution 1280 x 960")));
-
-	}
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
deleted file mode 100755
index 3c28a21..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.service;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-import org.apache.olingo.commons.api.ODataException;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
-import org.apache.olingo.commons.api.edm.FullQualifiedName;
-import org.apache.olingo.commons.api.edm.provider.CsdlAbstractEdmProvider;
-import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainer;
-import org.apache.olingo.commons.api.edm.provider.CsdlEntityContainerInfo;
-import org.apache.olingo.commons.api.edm.provider.CsdlEntitySet;
-import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
-import org.apache.olingo.commons.api.edm.provider.CsdlProperty;
-import org.apache.olingo.commons.api.edm.provider.CsdlPropertyRef;
-import org.apache.olingo.commons.api.edm.provider.CsdlSchema;
-
-public class DemoEdmProvider extends CsdlAbstractEdmProvider {
-
-  // Service Namespace
-  public static final String NAMESPACE = "OData.Demo";
-
-  // EDM Container
-  public static final String CONTAINER_NAME = "Container";
-  public static final FullQualifiedName CONTAINER = new FullQualifiedName(NAMESPACE, CONTAINER_NAME);
-
-  // Entity Types Names
-  public static final String ET_PRODUCT_NAME = "Product";
-  public static final FullQualifiedName ET_PRODUCT_FQN = new FullQualifiedName(NAMESPACE, ET_PRODUCT_NAME);
-
-  // Entity Set Names
-  public static final String ES_PRODUCTS_NAME = "Products";
-
-  @Override
-  public CsdlEntityType getEntityType(FullQualifiedName entityTypeName)
-      throws ODataException {
-    // this method is called for one of the EntityTypes that are configured in the Schema
-    if (ET_PRODUCT_FQN.equals(entityTypeName)) {
-
-      // create EntityType properties
-      CsdlProperty id = new CsdlProperty().setName("ID").setType(
-          EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
-      CsdlProperty name = new CsdlProperty().setName("Name").setType(
-          EdmPrimitiveTypeKind.String.getFullQualifiedName());
-      CsdlProperty description = new CsdlProperty().setName("Description").setType(
-          EdmPrimitiveTypeKind.String.getFullQualifiedName());
-
-      // create PropertyRef for Key element
-      CsdlPropertyRef propertyRef = new CsdlPropertyRef();
-      propertyRef.setName("ID");
-
-      // configure EntityType
-      CsdlEntityType entityType = new CsdlEntityType();
-      entityType.setName(ET_PRODUCT_NAME);
-      entityType.setProperties(Arrays.asList(id, name, description));
-      entityType.setKey(Collections.singletonList(propertyRef));
-
-      return entityType;
-    }
-
-    return null;
-
-  }
-
-  @Override
-  public CsdlEntitySet getEntitySet(FullQualifiedName entityContainer,
-      String entitySetName) throws ODataException {
-    if (entityContainer.equals(CONTAINER)) {
-      if (entitySetName.equals(ES_PRODUCTS_NAME)) {
-        CsdlEntitySet entitySet = new CsdlEntitySet();
-        entitySet.setName(ES_PRODUCTS_NAME);
-        entitySet.setType(ET_PRODUCT_FQN);
-
-        return entitySet;
-      }
-    }
-
-    return null;
-
-  }
-
-  @Override
-  public CsdlEntityContainerInfo getEntityContainerInfo(
-      FullQualifiedName entityContainerName) throws ODataException {
-    // This method is invoked when displaying the service document at
-    // e.g. http://localhost:8080/DemoService/DemoService.svc
-    if (entityContainerName == null || entityContainerName.equals(CONTAINER)) {
-      CsdlEntityContainerInfo entityContainerInfo = new CsdlEntityContainerInfo();
-      entityContainerInfo.setContainerName(CONTAINER);
-      return entityContainerInfo;
-    }
-
-    return null;
-
-  }
-
-  @Override
-  public List<CsdlSchema> getSchemas() throws ODataException {
-    // create Schema
-    CsdlSchema schema = new CsdlSchema();
-    schema.setNamespace(NAMESPACE);
-
-    // add EntityTypes
-    List<CsdlEntityType> entityTypes = new ArrayList<CsdlEntityType>();
-    entityTypes.add(getEntityType(ET_PRODUCT_FQN));
-    schema.setEntityTypes(entityTypes);
-
-    // add EntityContainer
-    schema.setEntityContainer(getEntityContainer());
-
-    // finally
-    List<CsdlSchema> schemas = new ArrayList<CsdlSchema>();
-    schemas.add(schema);
-
-    return schemas;
-
-  }
-
-  @Override
-  public CsdlEntityContainer getEntityContainer() throws ODataException {
-    // create EntitySets
-    List<CsdlEntitySet> entitySets = new ArrayList<CsdlEntitySet>();
-    entitySets.add(getEntitySet(CONTAINER, ES_PRODUCTS_NAME));
-
-    // create EntityContainer
-    CsdlEntityContainer entityContainer = new CsdlEntityContainer();
-    entityContainer.setName(CONTAINER_NAME);
-    entityContainer.setEntitySets(entitySets);
-
-    return entityContainer;
-
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
deleted file mode 100755
index fc58c23..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityCollectionProcessor.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.service;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Locale;
-
-import myservice.mynamespace.data.Storage;
-
-import org.apache.olingo.commons.api.data.ContextURL;
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.EntityCollection;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.api.format.ODataFormat;
-import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.ODataRequest;
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.ServiceMetadata;
-import org.apache.olingo.server.api.processor.EntityCollectionProcessor;
-import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.serializer.SerializerException;
-import org.apache.olingo.server.api.serializer.SerializerResult;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-import org.apache.olingo.server.api.uri.queryoption.CountOption;
-import org.apache.olingo.server.api.uri.queryoption.SkipOption;
-import org.apache.olingo.server.api.uri.queryoption.TopOption;
-
-public class DemoEntityCollectionProcessor implements EntityCollectionProcessor {
-
-  private OData odata;
-  private ServiceMetadata serviceMetadata;
-  private Storage storage;
-
-  public DemoEntityCollectionProcessor(Storage storage) {
-    this.storage = storage;
-  }
-
-  public void init(OData odata, ServiceMetadata serviceMetadata) {
-    this.odata = odata;
-    this.serviceMetadata = serviceMetadata;
-  }
-
-  public void readEntityCollection(ODataRequest request, ODataResponse response, UriInfo uriInfo,
-      ContentType responseFormat) throws ODataApplicationException, SerializerException {
-
-    // 1st retrieve the requested EntitySet from the uriInfo (representation of the parsed URI)
-    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
-    // in our example, the first segment is the EntitySet
-    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
-    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
-
-    // 2nd: fetch the data from backend for this requested EntitySetName and deliver as EntitySet
-    EntityCollection entityCollection = storage.readEntitySetData(edmEntitySet);
-
-    // 3rd: apply System Query Options
-    // modify the result set according to the query options, specified by the end user
-    List<Entity> entityList = entityCollection.getEntities();
-    EntityCollection returnEntityCollection = new EntityCollection();
-
-    // handle $count: always return the original number of entities, without considering $top and $skip
-    CountOption countOption = uriInfo.getCountOption();
-    if (countOption != null) {
-      boolean isCount = countOption.getValue();
-      if (isCount) {
-        returnEntityCollection.setCount(entityList.size());
-      }
-    }
-
-    // handle $skip
-    SkipOption skipOption = uriInfo.getSkipOption();
-    if (skipOption != null) {
-      int skipNumber = skipOption.getValue();
-      if (skipNumber >= 0 && skipNumber <= entityList.size()) {
-        entityList = entityList.subList(skipNumber, entityList.size());
-      } else {
-        throw new ODataApplicationException("Invalid value for $skip", HttpStatusCode.BAD_REQUEST.getStatusCode(),
-            Locale.ROOT);
-      }
-    }
-
-    // handle $top
-    TopOption topOption = uriInfo.getTopOption();
-    if (topOption != null) {
-      int topNumber = topOption.getValue();
-      if (topNumber >= 0 && topNumber <= entityList.size()) {
-        entityList = entityList.subList(0, topNumber);
-      } else {
-        throw new ODataApplicationException("Invalid value for $top", HttpStatusCode.BAD_REQUEST.getStatusCode(),
-            Locale.ROOT);
-      }
-    }
-
-    // after applying the system query options, create the EntityCollection based on the reduced list
-    for (Entity entity : entityList) {
-      returnEntityCollection.getEntities().add(entity);
-    }
-
-    // 4th: create a serializer based on the requested format (json)
-    ODataFormat format = ODataFormat.fromContentType(responseFormat);
-    ODataSerializer serializer = odata.createSerializer(format);
-
-    // and serialize the content: transform from the EntitySet object to InputStream
-    EdmEntityType edmEntityType = edmEntitySet.getEntityType();
-    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).build();
-
-    EntityCollectionSerializerOptions opts =
-        EntityCollectionSerializerOptions.with().contextURL(contextUrl).count(countOption).build();
-    SerializerResult serializerResult =
-        serializer.entityCollection(serviceMetadata, edmEntityType, returnEntityCollection, opts);
-    InputStream serializedContent = serializerResult.getContent();
-
-    // 5th: configure the response object: set the body, headers and status code
-    response.setContent(serializedContent);
-    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
deleted file mode 100755
index 81453a0..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoEntityProcessor.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.service;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Locale;
-
-import myservice.mynamespace.data.Storage;
-
-import org.apache.olingo.commons.api.data.ContextURL;
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmEntityType;
-import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.api.format.ODataFormat;
-import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.ODataRequest;
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.ServiceMetadata;
-import org.apache.olingo.server.api.deserializer.DeserializerException;
-import org.apache.olingo.server.api.processor.EntityProcessor;
-import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.serializer.SerializerException;
-import org.apache.olingo.server.api.serializer.SerializerResult;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriParameter;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-
-public class DemoEntityProcessor implements EntityProcessor {
-
-  private OData odata;
-  private ServiceMetadata serviceMetadata;
-  private Storage storage;
-
-  public DemoEntityProcessor(Storage storage) {
-    this.storage = storage;
-  }
-
-  public void init(OData odata, ServiceMetadata serviceMetadata) {
-    this.odata = odata;
-    this.serviceMetadata = serviceMetadata;
-  }
-
-  public void readEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType responseFormat)
-      throws ODataApplicationException, SerializerException {
-
-    // 1. retrieve the Entity Type
-    List<UriResource> resourcePaths = uriInfo.getUriResourceParts();
-    // Note: only in our example we can assume that the first segment is the EntitySet
-    UriResourceEntitySet uriResourceEntitySet = (UriResourceEntitySet) resourcePaths.get(0);
-    EdmEntitySet edmEntitySet = uriResourceEntitySet.getEntitySet();
-
-    // 2. retrieve the data from backend
-    List<UriParameter> keyPredicates = uriResourceEntitySet.getKeyPredicates();
-    Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
-
-    // 3. serialize
-    EdmEntityType entityType = edmEntitySet.getEntityType();
-
-    ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).suffix(ContextURL.Suffix.ENTITY).build();
-    // expand and select currently not supported
-    EntitySerializerOptions options = EntitySerializerOptions.with().contextURL(contextUrl).build();
-
-    ODataFormat oDataFormat = ODataFormat.fromContentType(responseFormat);
-    ODataSerializer serializer = this.odata.createSerializer(oDataFormat);
-    SerializerResult serializerResult = serializer.entity(serviceMetadata, entityType, entity, options);
-    InputStream entityStream = serializerResult.getContent();
-
-    // 4. configure the response object
-    response.setContent(entityStream);
-    response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-    response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
-  }
-
-  /*
-   * These processor methods are not handled in this tutorial
-   */
-
-  public void createEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
-      ContentType responseFormat)
-      throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-  }
-
-  public void updateEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo, ContentType requestFormat,
-      ContentType responseFormat)
-      throws ODataApplicationException, DeserializerException, SerializerException {
-    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-  }
-
-  public void deleteEntity(ODataRequest request, ODataResponse response, UriInfo uriInfo)
-      throws ODataApplicationException {
-    throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b477bde0/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java b/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
deleted file mode 100755
index 64f7949..0000000
--- a/samples/tutorials/p5_queryoptions/src/main/java/myservice/mynamespace/service/DemoPrimitiveProcessor.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package myservice.mynamespace.service;
-
-import java.io.InputStream;
-import java.util.List;
-import java.util.Locale;
-
-import myservice.mynamespace.data.Storage;
-
-import org.apache.olingo.commons.api.data.ContextURL;
-import org.apache.olingo.commons.api.data.Entity;
-import org.apache.olingo.commons.api.data.Property;
-import org.apache.olingo.commons.api.edm.EdmEntitySet;
-import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
-import org.apache.olingo.commons.api.edm.EdmProperty;
-import org.apache.olingo.commons.api.format.ContentType;
-import org.apache.olingo.commons.api.format.ODataFormat;
-import org.apache.olingo.commons.api.http.HttpHeader;
-import org.apache.olingo.commons.api.http.HttpStatusCode;
-import org.apache.olingo.server.api.OData;
-import org.apache.olingo.server.api.ODataApplicationException;
-import org.apache.olingo.server.api.ODataRequest;
-import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.ServiceMetadata;
-import org.apache.olingo.server.api.deserializer.DeserializerException;
-import org.apache.olingo.server.api.processor.PrimitiveProcessor;
-import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
-import org.apache.olingo.server.api.serializer.SerializerException;
-import org.apache.olingo.server.api.serializer.SerializerResult;
-import org.apache.olingo.server.api.uri.UriInfo;
-import org.apache.olingo.server.api.uri.UriParameter;
-import org.apache.olingo.server.api.uri.UriResource;
-import org.apache.olingo.server.api.uri.UriResourceEntitySet;
-import org.apache.olingo.server.api.uri.UriResourceProperty;
-
-public class DemoPrimitiveProcessor implements PrimitiveProcessor {
-
-	private OData odata;
-	private Storage storage;
-
-	public DemoPrimitiveProcessor(Storage storage) {
-		this.storage = storage;
-	}
-
-	public void init(OData odata, ServiceMetadata serviceMetadata) {
-		this.odata = odata;
-
-	}
-
-	/*
-	 * In our example, the URL would be: http://localhost:8080/DemoService/DemoService.svc/Products(1)/Name
-	 * and the response:
-	 * {
-	 *	  @odata.context: "$metadata#Products/Name",
-	 *	  value: "Notebook Basic 15"
-	 * }
-	 * */
-	public void readPrimitive(ODataRequest request, ODataResponse response,
-								UriInfo uriInfo, ContentType responseFormat)
-								throws ODataApplicationException, SerializerException {
-
-		// 1. Retrieve info from URI
-		// 1.1. retrieve the info about the requested entity set
-		List<UriResource> resourceParts = uriInfo.getUriResourceParts();
-		// Note: only in our example we can rely that the first segment is the EntitySet
-		UriResourceEntitySet uriEntityset = (UriResourceEntitySet) resourceParts.get(0);
-		EdmEntitySet edmEntitySet = uriEntityset.getEntitySet();
-		// the key for the entity
-		List<UriParameter> keyPredicates = uriEntityset.getKeyPredicates();
-
-		// 1.2. retrieve the requested (Edm) property
-		// the last segment is the Property
-		UriResourceProperty uriProperty = (UriResourceProperty)resourceParts.get(resourceParts.size() -1);
-		EdmProperty edmProperty = uriProperty.getProperty();
-		String edmPropertyName = edmProperty.getName();
-		// in our example, we know we have only primitive types in our model
-		EdmPrimitiveType edmPropertyType = (EdmPrimitiveType) edmProperty.getType();
-
-
-		// 2. retrieve data from backend
-		// 2.1. retrieve the entity data, for which the property has to be read
-		Entity entity = storage.readEntityData(edmEntitySet, keyPredicates);
-		if (entity == null) { // Bad request
-			throw new ODataApplicationException("Entity not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
-		}
-
-		// 2.2. retrieve the property data from the entity
-		Property property = entity.getProperty(edmPropertyName);
-		if (property == null) {
-			throw new ODataApplicationException("Property not found", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
-		}
-
-		// 3. serialize
-		Object value = property.getValue();
-		if (value != null) {
-			// 3.1. configure the serializer
-			ODataFormat format = ODataFormat.fromContentType(responseFormat);
-			ODataSerializer serializer = odata.createSerializer(format);
-
-			ContextURL contextUrl = ContextURL.with().entitySet(edmEntitySet).navOrPropertyPath(edmPropertyName).build();
-			PrimitiveSerializerOptions options = PrimitiveSerializerOptions.with().contextURL(contextUrl).build();
-			// 3.2. serialize
-			SerializerResult serializerResult = serializer.primitive(edmPropertyType, property, options);
-			InputStream propertyStream = serializerResult.getContent();
-
-			//4. configure the response object
-			response.setContent(propertyStream);
-			response.setStatusCode(HttpStatusCode.OK.getStatusCode());
-			response.setHeader(HttpHeader.CONTENT_TYPE, responseFormat.toContentTypeString());
-		} else {
-			// in case there's no value for the property, we can skip the serialization
-			response.setStatusCode(HttpStatusCode.NO_CONTENT.getStatusCode());
-		}
-	}
-
-
-
-	/*
-	 * These processor methods are not handled in this tutorial
-	 * */
-
-	public void updatePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo,
-                              ContentType requestFormat, ContentType responseFormat)
-								throws ODataApplicationException, DeserializerException, SerializerException {
-		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-	}
-
-	public void deletePrimitive(ODataRequest request, ODataResponse response, UriInfo uriInfo)
-          throws ODataApplicationException {
-		throw new ODataApplicationException("Not supported.", HttpStatusCode.NOT_IMPLEMENTED.getStatusCode(), Locale.ROOT);
-	}
-}


[07/18] olingo-odata4 git commit: [OLINGO-731] Added html as debug output and refactored structure

Posted by ch...@apache.org.
[OLINGO-731] Added html as debug output and refactored structure


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

Branch: refs/heads/OLINGO-640
Commit: 3dae763f359b27c4c2d13dd95193dc4f76e778ab
Parents: 010d94f
Author: Christian Amend <ch...@sap.com>
Authored: Fri Jul 24 16:11:13 2015 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Fri Jul 24 16:12:01 2015 +0200

----------------------------------------------------------------------
 .../apache/olingo/server/api/ODataResponse.java |   2 +-
 .../server/api/debug/DebugInformation.java      | 118 ++++++++++
 .../server/api/debug/DebugResponseHelper.java   |   7 +-
 .../olingo/server/api/debug/DebugSupport.java   |  10 +-
 .../server/api/debug/DefaultDebugSupport.java   |  17 +-
 .../apache/olingo/server/core/ODataHandler.java |  10 +-
 .../server/core/ODataHttpHandlerImpl.java       |  89 ++-----
 .../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     | 229 +++++++++---------
 .../olingo/server/core/debug/DebugTab.java      |  50 ++++
 .../olingo/server/core/debug/DebugTabBody.java  | 149 ++++++++++++
 .../server/core/debug/DebugTabException.java    | 136 +++++++++++
 .../server/core/debug/DebugTabRequest.java      | 115 +++++++++
 .../server/core/debug/DebugTabResponse.java     |  89 +++++++
 .../server/core/debug/DebugTabRuntime.java      | 181 +++++++++++++++
 .../server/core/debug/DebugTabServer.java       |  57 +++++
 .../olingo/server/core/debug/DebugTabUri.java   | 232 +++++++++++++++++++
 .../server/core/debug/ServerCoreDebugger.java   | 137 +++++++++++
 .../olingo/server/tecsvc/TechnicalServlet.java  |   1 -
 .../olingo/server/core/ODataHandlerTest.java    |  10 +-
 27 files changed, 1423 insertions(+), 1261 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataResponse.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataResponse.java
index 493e794..7b9e9c9 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataResponse.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/ODataResponse.java
@@ -31,7 +31,7 @@ import org.apache.olingo.commons.api.http.HttpStatusCode;
 public class ODataResponse {
 
   private int statusCode = HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode();
-  private Map<String, String> headers = new HashMap<String, String>();
+  private final Map<String, String> headers = new HashMap<String, String>();
   private InputStream content;
 
   /**

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugInformation.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugInformation.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugInformation.java
new file mode 100644
index 0000000..9198c6b
--- /dev/null
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/debug/DebugInformation.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.uri.UriInfo;
+
+/**
+ * This class contains all information necessary to construct a debug response.
+ */
+public class DebugInformation {
+
+  private ODataRequest request;
+  private ODataResponse applicationResponse;
+  private UriInfo uriInfo;
+  private Exception exception;
+  private Map<String, String> serverEnvironmentVaribles;
+  private List<RuntimeMeasurement> runtimeInformation;
+
+  /**
+   * This method will return the ODataRequest the library created. This request will never be null but might be filled
+   * incompletely if there has been an exception during the request parsing.
+   * @return the ODataRequest the library built
+   */
+  public ODataRequest getRequest() {
+    return request;
+  }
+
+  public void setRequest(ODataRequest request) {
+    this.request = request;
+  }
+
+  /**
+   * This method will return the ODataResponse which was filled by the Application or the library in an exception case.
+   * The response might be null or might not be filled completely.
+   * @return the response filled by the application
+   */
+  public ODataResponse getApplicationResponse() {
+    return applicationResponse;
+  }
+
+  public void setApplicationResponse(ODataResponse applicationResponse) {
+    this.applicationResponse = applicationResponse;
+  }
+
+  /**
+   * The URI Info object the library created during URI parsing. Might be null if there was an exception during URI
+   * parsing.
+   * @return the URI Info Object
+   */
+  public UriInfo getUriInfo() {
+    return uriInfo;
+  }
+
+  public void setUriInfo(UriInfo uriInfo) {
+    this.uriInfo = uriInfo;
+  }
+
+  /**
+   * This method will return any exception that was thrown from the application or library. Will be null if there was no
+   * exception.
+   * @return an exception if thrown.
+   */
+  public Exception getException() {
+    return exception;
+  }
+
+  public void setException(Exception exception) {
+    this.exception = exception;
+  }
+
+  /**
+   * A map containing information about the runtime environment. Depending on the servlet or webserver used this map
+   * might contain different information. Will never be null but might be empty.
+   * @return environment variables
+   */
+  public Map<String, String> getServerEnvironmentVaribles() {
+    return serverEnvironmentVaribles;
+  }
+
+  public void setServerEnvironmentVaribles(Map<String, String> serverEnvironmentVaribles) {
+    this.serverEnvironmentVaribles = serverEnvironmentVaribles;
+  }
+
+  /**
+   * This method will return all runtime information which was collected inside the library. Might be null if no data
+   * could be collected.
+   * @return runtime information collected by the library
+   */
+  public List<RuntimeMeasurement> getRuntimeInformation() {
+    return runtimeInformation;
+  }
+
+  public void setRuntimeInformation(List<RuntimeMeasurement> runtimeInformation) {
+    this.runtimeInformation = runtimeInformation;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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 bf6fc56..e2f6933 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,10 +18,6 @@
  */
 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;
 
 /**
@@ -38,6 +34,5 @@ public interface DebugResponseHelper {
    * @param runtimeInformation
    * @return the debug response or the raw application response in case an exception occurred.
    */
-  ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse, Exception exception,
-      Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
+  ODataResponse createDebugResponse(DebugInformation debugInfo);
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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 995ba34..7a94c44 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,11 +18,7 @@
  */
 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;
 
 /**
@@ -35,8 +31,11 @@ public interface DebugSupport {
   public static final String ODATA_DEBUG_HTML = "html";
   public static final String ODATA_DEBUG_DOWNLOAD = "download";
 
+  //TODO:JavaDoc
   void init(OData odata);
 
+  boolean isUserAuthorized();
+  
   /**
    * This method should create a debug response and deliver it back to the Olingo library. This method MUST NEVER throw
    * an exception.
@@ -46,7 +45,6 @@ public interface DebugSupport {
    * @param exception which has been thrown. Might be null in case there was no exception
    * @return a new debug response which will be send to the client
    */
-  ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse response,
-      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation);
+  ODataResponse createDebugResponse(String debugFormat, DebugInformation debugInfo);
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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 cca537f..7079e76 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,11 +18,7 @@
  */
 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;
 
 /**
@@ -38,18 +34,21 @@ public class DefaultDebugSupport implements DebugSupport {
   }
 
   @Override
-  public ODataResponse createDebugResponse(String debugFormat, ODataRequest request, ODataResponse applicationResponse,
-      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
+  public boolean isUserAuthorized() {
+    return true;
+  }
+
+  @Override
+  public ODataResponse createDebugResponse(String debugFormat, DebugInformation debugInfo) {
     // 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,
-          serverEnvironmentVaribles, runtimeInformation);
+      return odata.createDebugResponseHelper(debugFormat).createDebugResponse(debugInfo);
     } 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.
-      return applicationResponse;
+      return debugInfo.getApplicationResponse();
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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 1a0df8d..1d1b270 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
@@ -42,6 +42,7 @@ import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
 import org.apache.olingo.server.api.serializer.RepresentationType;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
 import org.apache.olingo.server.core.uri.parser.Parser;
 import org.apache.olingo.server.core.uri.parser.UriParserException;
 import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
@@ -54,15 +55,18 @@ public class ODataHandler {
   private final OData odata;
   private final ServiceMetadata serviceMetadata;
   private final List<Processor> processors = new LinkedList<Processor>();
+  private final ServerCoreDebugger debugger;
+
   private CustomContentTypeSupport customContentTypeSupport;
   private CustomETagSupport customETagSupport;
 
   private UriInfo uriInfo;
   private Exception lastThrownException;
 
-  public ODataHandler(final OData server, final ServiceMetadata serviceMetadata) {
+  public ODataHandler(final OData server, final ServiceMetadata serviceMetadata, ServerCoreDebugger debugger) {
     odata = server;
     this.serviceMetadata = serviceMetadata;
+    this.debugger = debugger;
 
     register(new DefaultRedirectProcessor());
     register(new DefaultProcessor());
@@ -192,4 +196,8 @@ public class ODataHandler {
   public Exception getLastThrownException() {
     return lastThrownException;
   }
+  
+  public UriInfo getUriInfo(){
+    return uriInfo;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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 2bab186..e443591 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
@@ -35,19 +35,19 @@ import javax.servlet.http.HttpServletResponse;
 import org.apache.olingo.commons.api.ODataRuntimeException;
 import org.apache.olingo.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpMethod;
-import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataHttpHandler;
+import org.apache.olingo.server.api.ODataLibraryException;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
-import org.apache.olingo.server.api.ODataLibraryException;
+import org.apache.olingo.server.api.ODataServerError;
 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;
 import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.debug.ServerCoreDebugger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -56,99 +56,52 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
   private static final Logger LOG = LoggerFactory.getLogger(ODataHttpHandlerImpl.class);
 
   private final ODataHandler handler;
-  private final OData odata;
-  private int split = 0;
+  private final ServerCoreDebugger debugger;
 
-  // debug stuff
-  private final List<RuntimeMeasurement> runtimeInformation = new ArrayList<RuntimeMeasurement>();
-  private DebugSupport debugSupport;
-  private String debugFormat;
-  private boolean isDebugMode = false;
+  private int split = 0;
 
   public ODataHttpHandlerImpl(final OData odata, final ServiceMetadata serviceMetadata) {
-    this.odata = odata;
-    handler = new ODataHandler(odata, serviceMetadata);
+    debugger = new ServerCoreDebugger(odata);
+    handler = new ODataHandler(odata, serviceMetadata, debugger);
   }
 
   @Override
   public void process(final HttpServletRequest request, final HttpServletResponse response) {
+    ODataRequest odRequest = new ODataRequest();
     Exception exception = null;
-    ODataRequest odRequest = null;
     ODataResponse odResponse;
-    resolveDebugMode(request);
-    int processMethodHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "process");
+    debugger.resolveDebugMode(request);
 
+    int processMethodHandel = debugger.startRuntimeMeasurement("ODataHttpHandlerImpl", "process");
     try {
-      odRequest = new ODataRequest();
-      int requestHandel = startRuntimeMeasurement("ODataHttpHandlerImpl", "fillODataRequest");
+      int requestHandel = debugger.startRuntimeMeasurement("ODataHttpHandlerImpl", "fillODataRequest");
       fillODataRequest(odRequest, request, split);
-      stopRuntimeMeasurement(requestHandel);
-      
-      int responseHandel = startRuntimeMeasurement("ODataHandler", "process");
+      debugger.stopRuntimeMeasurement(requestHandel);
+
+      int responseHandel = debugger.startRuntimeMeasurement("ODataHandler", "process");
       odResponse = handler.process(odRequest);
-      stopRuntimeMeasurement(responseHandel);
+      debugger.stopRuntimeMeasurement(responseHandel);
       // ALL future methods after process must not throw exceptions!
     } catch (Exception e) {
       exception = e;
       odResponse = handleException(odRequest, e);
     }
-    stopRuntimeMeasurement(processMethodHandel);
+    debugger.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 (debugger.isDebugMode()) {
+      Map<String, String> serverEnvironmentVaribles = createEnvironmentVariablesMap(request);
       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);
+          debugger.createDebugResponse(request, exception, odRequest, odResponse, handler.getUriInfo(),
+              serverEnvironmentVaribles);
     }
 
     convertToHttp(response, odResponse);
   }
 
-  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());
@@ -350,6 +303,6 @@ public class ODataHttpHandlerImpl implements ODataHttpHandler {
 
   @Override
   public void register(final DebugSupport debugSupport) {
-    this.debugSupport = debugSupport;
+    debugger.setDebugSupportProcessor(debugSupport);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/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
deleted file mode 100644
index 9c5a1d4..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfo.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index e266aae..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoBody.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index b19252f..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoException.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index e28bbb9..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRequest.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index 0781d50..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoResponse.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index 2465ce4..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoRuntime.java
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index e974d03..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoServer.java
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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
deleted file mode 100644
index 2ddeb07..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugInfoUri.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.olingo.server.core.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/3dae763f/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 6952018..d99dd4c 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
@@ -22,6 +22,7 @@ import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringWriter;
+import java.io.Writer;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
@@ -32,8 +33,8 @@ 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.DebugInformation;
 import org.apache.olingo.server.api.debug.DebugResponseHelper;
 import org.apache.olingo.server.api.debug.DebugSupport;
 import org.apache.olingo.server.api.debug.RuntimeMeasurement;
@@ -62,13 +63,10 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
   }
 
   @Override
-  public ODataResponse createDebugResponse(ODataRequest request, ODataResponse applicationResponse,
-      Exception exception, Map<String, String> serverEnvironmentVaribles, List<RuntimeMeasurement> runtimeInformation) {
-
+  public ODataResponse createDebugResponse(DebugInformation debugInfo) {
     try {
-      final List<DebugInfo> parts =
-          createParts(request, applicationResponse, exception, serverEnvironmentVaribles, runtimeInformation);
-      
+      final List<DebugTab> parts = createParts(debugInfo);
+
       ODataResponse response = new ODataResponse();
       String contentTypeString;
       InputStream body;
@@ -78,7 +76,9 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
             + new Date().toString().replace(' ', '_').replace(':', '.') + ".html");
         // Download is the same as html except for the above header
       case HTML:
-        body = wrapInHtml(parts);
+        String title = debugInfo.getRequest() == null ? 
+            "V4 Service" : "V4 Service: " + debugInfo.getRequest().getRawODataPath();
+        body = wrapInHtml(parts, title);
         contentTypeString = ContentType.TEXT_HTML.toContentTypeString();
         break;
       case JSON:
@@ -93,65 +93,58 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
 
       return response;
     } catch (IOException e) {
-      // Should not happen
-      // TODO: Check what we can do here.
+      // Should not happen. In case it does the library will deliver a default response. So no handling 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>();
+  private List<DebugTab> createParts(DebugInformation debugInfo) {
+    List<DebugTab> parts = new ArrayList<DebugTab>();
 
     // request
-    parts.add(new DebugInfoRequest(request));
+    parts.add(new DebugTabRequest(debugInfo.getRequest()));
 
     // response
-    // TODO: Check service URI
-    parts.add(new DebugInfoResponse(applicationResponse, request.getRawBaseUri()));
+    parts.add(new DebugTabResponse(debugInfo.getApplicationResponse(), debugInfo.getRequest().getRawBaseUri()));
 
     // server
+    Map<String, String> serverEnvironmentVaribles = debugInfo.getServerEnvironmentVaribles();
     if (serverEnvironmentVaribles != null && !serverEnvironmentVaribles.isEmpty()) {
-      parts.add(new DebugInfoServer(serverEnvironmentVaribles));
+      parts.add(new DebugTabServer(serverEnvironmentVaribles));
     }
 
-//    // URI
-//    Throwable candidate = exception;
-//    while (candidate != null && !(candidate instanceof ExpressionParserException)) {
-//      candidate = candidate.getCause();
+    // TODO:Enable URIDebugInfo
+    // URI
+//    if (uriInfo != null && (uriInfo.getFilterOption() != null || uriInfo.getOrderByOption() != null
+//        || uriInfo.getExpandOption() != null || uriInfo.getSelectOption() != null)) {
+//      parts.add(new DebugInfoUri(uriInfo));
 //    }
-//    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
+
+    // runtime measurements
+    List<RuntimeMeasurement> runtimeInformation = debugInfo.getRuntimeInformation();
     if (runtimeInformation != null && !runtimeInformation.isEmpty()) {
-      parts.add(new DebugInfoRuntime(runtimeInformation));
+      parts.add(new DebugTabRuntime(runtimeInformation));
     }
-//
-//    // exceptions
-    if (exception != null) {
-      parts.add(new DebugInfoException(exception));
+
+    // exceptions
+    if (debugInfo.getException() != null) {
+      parts.add(new DebugTabException(debugInfo.getException()));
     }
 
     return parts;
   }
 
-  private InputStream wrapInJson(final List<DebugInfo> parts) throws IOException {
+  private InputStream wrapInJson(final List<DebugTab> parts) throws IOException {
     CircleStreamBuffer csb = new CircleStreamBuffer();
     JsonGenerator gen = new JsonFactory().createGenerator(csb.getOutputStream(), JsonEncoding.UTF8);
 
     gen.writeStartObject();
-    DebugInfo requestInfo = parts.get(0);
+    DebugTab 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);
+    DebugTab responseInfo = parts.get(1);
     gen.writeFieldName(responseInfo.getName().toLowerCase(Locale.ROOT));
     responseInfo.appendJson(gen);
 
@@ -163,7 +156,7 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
     } else {
       gen.writeNullField("version");
     }
-    for (DebugInfo part : parts.subList(2, parts.size())) {
+    for (DebugTab part : parts.subList(2, parts.size())) {
       gen.writeFieldName(part.getName().toLowerCase(Locale.ROOT));
       part.appendJson(gen);
     }
@@ -171,76 +164,72 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
 
     gen.writeEndObject();
     gen.close();
+    csb.close();
 
     return csb.getInputStream();
   }
 
-  private InputStream wrapInHtml(final List<DebugInfo> parts) throws IOException {
+  private InputStream wrapInHtml(final List<DebugTab> parts, String title) 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();
+
+    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(escapeHtml(title))
+        .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 DebugTab 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);
   }
@@ -262,21 +251,21 @@ public class DebugResponseHelperImpl implements DebugResponseHelper {
     }
     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");
-//  }
+
+  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(escapeHtml(value))
+            .append("</td></tr>\n");
+      }
+    }
+    writer.append("</tbody>\n</table>\n");
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3dae763f/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTab.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTab.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTab.java
new file mode 100644
index 0000000..8847e33
--- /dev/null
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/debug/DebugTab.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 DebugTab {
+
+  /**
+   * 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;
+}


[10/18] olingo-odata4 git commit: [OLINGO-713] Minor change system query options - expand

Posted by ch...@apache.org.
[OLINGO-713] Minor change system query options - expand


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

Branch: refs/heads/OLINGO-640
Commit: b146a403bb4e8333d2152c9b5667bd0ab063ed02
Parents: b477bde
Author: Michael Bolz <mi...@sap.com>
Authored: Mon Jul 27 10:21:14 2015 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Mon Jul 27 10:21:14 2015 +0200

----------------------------------------------------------------------
 .../java/myservice/mynamespace/service/DemoEdmProvider.java    | 6 +++---
 samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp | 4 ++--
 2 files changed, 5 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b146a403/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
index 7b1fef8..248cfba 100755
--- a/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
+++ b/samples/tutorials/p6_queryoptions-es/src/main/java/myservice/mynamespace/service/DemoEdmProvider.java
@@ -77,7 +77,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
 
       // navigation property: many-to-one, null not allowed (product must have a category)
       CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Category")
-          .setType(ET_CATEGORY_FQN).setNullable(false).setPartner("Products");
+          .setType(ET_CATEGORY_FQN).setNullable(false).setPartner("RelProducts");
       List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
       navPropList.add(navProp);
 
@@ -100,7 +100,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
       propertyRef.setName("ID");
 
       // navigation property: one-to-many
-      CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("Products")
+      CsdlNavigationProperty navProp = new CsdlNavigationProperty().setName("RelProducts")
           .setType(ET_PRODUCT_FQN).setCollection(true).setPartner("Category");
       List<CsdlNavigationProperty> navPropList = new ArrayList<CsdlNavigationProperty>();
       navPropList.add(navProp);
@@ -147,7 +147,7 @@ public class DemoEdmProvider extends CsdlAbstractEdmProvider {
         // navigation
         CsdlNavigationPropertyBinding navPropBinding = new CsdlNavigationPropertyBinding();
         navPropBinding.setTarget("Products"); // the target entity set, where the navigation property points to
-        navPropBinding.setPath("Products"); // the path from entity type to navigation property
+        navPropBinding.setPath("RelProducts"); // the path from entity type to navigation property
         List<CsdlNavigationPropertyBinding> navPropBindingList = new ArrayList<CsdlNavigationPropertyBinding>();
         navPropBindingList.add(navPropBinding);
         entitySet.setNavigationPropertyBindings(navPropBindingList);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b146a403/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
----------------------------------------------------------------------
diff --git a/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp b/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
index cee3a31..344b026 100755
--- a/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
+++ b/samples/tutorials/p6_queryoptions-es/src/main/webapp/index.jsp
@@ -31,10 +31,10 @@ under the License.
         <a href="DemoService.svc/Products/?$expand=Category">Expand - /Products/?$expand=Category</a>
     </li>
     <li>
-        <a href="DemoService.svc/Categories(1)/?$expand=Products">Expand - /Categories(1)/?$expand=Products</a>
+        <a href="DemoService.svc/Categories(1)/?$expand=RelProducts">Expand - /Categories(1)/?$expand=RelProducts</a>
     </li>
     <li>
-        <a href="DemoService.svc/Categories/?$expand=Products">Expand - /DemoService.svc/Categories/?$expand=Products</a>
+        <a href="DemoService.svc/Categories/?$expand=RelProducts">Expand - /Categories/?$expand=RelProducts</a>
     </li>
 </ul>
 


[18/18] olingo-odata4 git commit: [OLINGO-640] Minor adjustments to tests and deleted logger

Posted by ch...@apache.org.
[OLINGO-640] Minor adjustments to tests and deleted logger


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

Branch: refs/heads/OLINGO-640
Commit: db0b9d39de3a708320e5141bf4c9fed3b9c0e68a
Parents: 3665970
Author: Christian Amend <ch...@sap.com>
Authored: Tue Aug 4 16:23:42 2015 +0200
Committer: Christian Amend <ch...@sap.com>
Committed: Tue Aug 4 16:23:42 2015 +0200

----------------------------------------------------------------------
 .../fit/tecsvc/client/NavigationITCase.java     |    8 +-
 .../core/serializer/xml/ODataXmlSerializer.java |  247 +-
 .../serializer/xml/ODataXmlSerializerTest.java  | 2434 +++++++++---------
 3 files changed, 1386 insertions(+), 1303 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/db0b9d39/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
index a153f06..efcb168 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/NavigationITCase.java
@@ -38,7 +38,7 @@ import org.apache.olingo.fit.util.StringHelper;
 import org.junit.Assert;
 import org.junit.Test;
 
-public final class NavigationITCase extends AbstractBaseTestITCase {
+public class NavigationITCase extends AbstractBaseTestITCase {
 
   private final ODataClient client = getClient();
 
@@ -60,7 +60,7 @@ public final class NavigationITCase extends AbstractBaseTestITCase {
                     appendKeySegment(32767).build()).rawExecute();
 
     String zeroLevelResponseBody = StringHelper.asString(zeroLevelResponse);
-    assertTrue(zeroLevelResponseBody.contains("\"@odata.context\":\"$metadata#ESAllPrim/$entity\""));
+    assertTrue(zeroLevelResponseBody.contains("\"$metadata#ESAllPrim/$entity\""));
 
     // one navigation
     final InputStream oneLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
@@ -70,7 +70,7 @@ public final class NavigationITCase extends AbstractBaseTestITCase {
                     .rawExecute();
 
     String oneLevelResponseBody = StringHelper.asString(oneLevelResponse);
-    assertTrue(oneLevelResponseBody.contains("\"@odata.context\":\"../$metadata#ESTwoPrim/$entity\""));
+    assertTrue(oneLevelResponseBody.contains("\"../$metadata#ESTwoPrim/$entity\""));
 
     // two navigation
     final InputStream twoLevelResponse = client.getRetrieveRequestFactory().getEntityRequest(
@@ -81,7 +81,7 @@ public final class NavigationITCase extends AbstractBaseTestITCase {
                     .rawExecute();
 
     String twoLevelResponseBody = StringHelper.asString(twoLevelResponse);
-    assertTrue(twoLevelResponseBody.contains("\"@odata.context\":\"../../$metadata#ESTwoPrim/$entity\""));
+    assertTrue(twoLevelResponseBody.contains("\"../../$metadata#ESTwoPrim/$entity\""));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/db0b9d39/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index de50032..b9413f7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.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
@@ -67,8 +67,6 @@ import org.apache.olingo.server.core.serializer.SerializerResultImpl;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class ODataXmlSerializer implements ODataSerializer {
   private static final String DATA = "d";
@@ -81,18 +79,16 @@ public class ODataXmlSerializer implements ODataSerializer {
   private static final String NS_METADATA = "http://docs.oasis-open.org/odata/ns/metadata";
   private static final String NS_DATA = "http://docs.oasis-open.org/odata/ns/data";
   private static final String NS_SCHEMA = "http://docs.oasis-open.org/odata/ns/scheme";
-  
-  private static final Logger log = LoggerFactory.getLogger(ODataXmlSerializer.class);
 
   @Override
   public SerializerResult serviceDocument(final ServiceMetadata metadata, final String serviceRoot)
       throws SerializerException {
     CircleStreamBuffer buffer;
     XMLStreamWriter xmlStreamWriter = null;
-
+    SerializerException cachedException = null;
     try {
       buffer = new CircleStreamBuffer();
-      xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), 
+      xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
           DEFAULT_CHARSET);
       ServiceDocumentXmlSerializer serializer = new ServiceDocumentXmlSerializer(metadata, serviceRoot);
       serializer.writeServiceDocument(xmlStreamWriter);
@@ -101,16 +97,20 @@ public class ODataXmlSerializer implements ODataSerializer {
 
       return SerializerResultImpl.with().content(buffer.getInputStream()).build();
     } catch (final XMLStreamException e) {
-      log.error(e.getMessage(), e);
-      throw new SerializerException("An I/O exception occurred.", e,
-          SerializerException.MessageKeys.IO_EXCEPTION);
+      cachedException =
+          new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION);
+      throw cachedException;
     } finally {
       if (xmlStreamWriter != null) {
         try {
           xmlStreamWriter.close();
         } catch (XMLStreamException e) {
-          throw new SerializerException("An I/O exception occurred.", e,
-              SerializerException.MessageKeys.IO_EXCEPTION);
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new SerializerException("An I/O exception occurred.", e,
+                SerializerException.MessageKeys.IO_EXCEPTION);
+          }
         }
       }
     }
@@ -120,10 +120,10 @@ public class ODataXmlSerializer implements ODataSerializer {
   public SerializerResult metadataDocument(final ServiceMetadata serviceMetadata) throws SerializerException {
     CircleStreamBuffer buffer;
     XMLStreamWriter xmlStreamWriter = null;
-
+    SerializerException cachedException = null;
     try {
       buffer = new CircleStreamBuffer();
-      xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), 
+      xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
           DEFAULT_CHARSET);
       MetadataDocumentXmlSerializer serializer = new MetadataDocumentXmlSerializer(serviceMetadata);
       serializer.writeMetadataDocument(xmlStreamWriter);
@@ -132,16 +132,20 @@ public class ODataXmlSerializer implements ODataSerializer {
 
       return SerializerResultImpl.with().content(buffer.getInputStream()).build();
     } catch (final XMLStreamException e) {
-      log.error(e.getMessage(), e);
-      throw new SerializerException("An I/O exception occurred.", e,
-          SerializerException.MessageKeys.IO_EXCEPTION);
+      cachedException =
+          new SerializerException("An I/O exception occurred.", e, SerializerException.MessageKeys.IO_EXCEPTION);
+      throw cachedException;
     } finally {
       if (xmlStreamWriter != null) {
         try {
           xmlStreamWriter.close();
         } catch (XMLStreamException e) {
-          throw new SerializerException("An I/O exception occurred.", e,
-              SerializerException.MessageKeys.IO_EXCEPTION);
+          if (cachedException != null) {
+            throw cachedException;
+          } else {
+            throw new SerializerException("An I/O exception occurred.", e,
+                SerializerException.MessageKeys.IO_EXCEPTION);
+          }
         }
       }
     }
@@ -151,31 +155,31 @@ public class ODataXmlSerializer implements ODataSerializer {
   public SerializerResult error(final ODataServerError error) throws SerializerException {
     CircleStreamBuffer buffer;
     XMLStreamWriter writer = null;
-    
+
     if (error == null) {
       throw new SerializerException("ODataError object MUST NOT be null!",
           SerializerException.MessageKeys.NULL_INPUT);
     }
-    
+
     try {
       buffer = new CircleStreamBuffer();
-      writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(), 
+      writer = XMLOutputFactory.newInstance().createXMLStreamWriter(buffer.getOutputStream(),
           DEFAULT_CHARSET);
       writer.writeStartDocument(ODataSerializer.DEFAULT_CHARSET, "1.0");
-      
+
       writer.writeStartElement("error");
       writer.writeDefaultNamespace(NS_METADATA);
       writeErrorDetails(String.valueOf(error.getStatusCode()), error.getMessage(), error.getTarget(), writer);
       if (error.getDetails() != null && !error.getDetails().isEmpty()) {
         writer.writeStartElement("details");
-        for (ODataErrorDetail inner:error.getDetails()) {
+        for (ODataErrorDetail inner : error.getDetails()) {
           writeErrorDetails(inner.getCode(), inner.getMessage(), inner.getTarget(), writer);
         }
         writer.writeEndElement();
       }
-      writer.writeEndElement();      
+      writer.writeEndElement();
       writer.writeEndDocument();
-      
+
       writer.flush();
       writer.close();
       return SerializerResultImpl.with().content(buffer.getInputStream()).build();
@@ -192,7 +196,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeCharacters(String.valueOf(code));
       writer.writeEndElement();
     }
-    
+
     writer.writeStartElement("message");
     writer.writeCharacters(message);
     writer.writeEndElement();
@@ -200,22 +204,22 @@ public class ODataXmlSerializer implements ODataSerializer {
     if (target != null) {
       writer.writeStartElement("target");
       writer.writeCharacters(target);
-      writer.writeEndElement();        
+      writer.writeEndElement();
     }
   }
-  
+
   @Override
   public SerializerResult entityCollection(final ServiceMetadata metadata,
       final EdmEntityType entityType, final EntityCollection entitySet,
       final EntityCollectionSerializerOptions options) throws SerializerException {
-    
+
     final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
     if (options.onlyReferences()) {
       ReferenceCollectionSerializerOptions rso = ReferenceCollectionSerializerOptions.with()
           .contextURL(contextURL).build();
       return entityReferenceCollection(metadata, entityType, entitySet, rso);
     }
-    
+
     CircleStreamBuffer buffer;
     XMLStreamWriter writer = null;
     try {
@@ -226,11 +230,11 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeNamespace(ATOM, NS_ATOM);
       writer.writeNamespace(METADATA, NS_METADATA);
       writer.writeNamespace(DATA, NS_DATA);
-      
-      writer.writeAttribute(METADATA, NS_METADATA, "context", 
+
+      writer.writeAttribute(METADATA, NS_METADATA, "context",
           ContextURLBuilder.create(contextURL).toASCIIString());
       writeMetadataETag(metadata, writer);
-      
+
       writer.writeStartElement(ATOM, "id", NS_ATOM);
       writer.writeCharacters(options.getId());
       writer.writeEndElement();
@@ -242,7 +246,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       if (entitySet.getNext() != null) {
         writeNextLink(entitySet, writer);
       }
-      
+
       writeEntitySet(metadata, entityType, entitySet,
           options.getExpand(), options.getSelect(), options.onlyReferences(), writer);
 
@@ -261,13 +265,13 @@ public class ODataXmlSerializer implements ODataSerializer {
   public SerializerResult entity(final ServiceMetadata metadata, final EdmEntityType entityType,
       final Entity entity, final EntitySerializerOptions options) throws SerializerException {
     final ContextURL contextURL = checkContextURL(options == null ? null : options.getContextURL());
-    
+
     if (options.onlyReferences()) {
       ReferenceSerializerOptions rso = ReferenceSerializerOptions.with()
           .contextURL(contextURL).build();
       return entityReference(metadata, entityType, entity, rso);
     }
-    
+
     CircleStreamBuffer buffer;
     XMLStreamWriter writer = null;
     try {
@@ -295,12 +299,12 @@ public class ODataXmlSerializer implements ODataSerializer {
     return contextURL;
   }
 
-  private void writeMetadataETag(final ServiceMetadata metadata, XMLStreamWriter writer) 
+  private void writeMetadataETag(final ServiceMetadata metadata, XMLStreamWriter writer)
       throws XMLStreamException {
     if (metadata != null
         && metadata.getServiceMetadataETagSupport() != null
         && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {
-      writer.writeAttribute(METADATA, NS_METADATA, "metadata-etag", 
+      writer.writeAttribute(METADATA, NS_METADATA, "metadata-etag",
           metadata.getServiceMetadataETagSupport().getMetadataETag());
     }
   }
@@ -316,7 +320,7 @@ public class ODataXmlSerializer implements ODataSerializer {
 
   protected void writeEntity(final ServiceMetadata metadata, final EdmEntityType entityType,
       final Entity entity, final ContextURL contextURL, final ExpandOption expand,
-      final SelectOption select, final boolean onlyReference, final XMLStreamWriter writer, 
+      final SelectOption select, final boolean onlyReference, final XMLStreamWriter writer,
       final boolean top) throws XMLStreamException, SerializerException {
 
     writer.writeStartElement(ATOM, "entry", NS_ATOM);
@@ -324,24 +328,24 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeNamespace(ATOM, NS_ATOM);
       writer.writeNamespace(METADATA, NS_METADATA);
       writer.writeNamespace(DATA, NS_DATA);
-      
+
       if (contextURL != null) { // top-level entity
-        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
             ContextURLBuilder.create(contextURL).toASCIIString());
         writeMetadataETag(metadata, writer);
-  
+
       }
     }
     if (entity.getETag() != null) {
       writer.writeAttribute(METADATA, NS_METADATA, "etag", entity.getETag());
     }
-    
+
     writer.writeStartElement(NS_ATOM, "id");
     writer.writeCharacters(entity.getId().toASCIIString());
     writer.writeEndElement();
 
     writerAuthorInfo(entity.getTitle(), writer);
-    
+
     writer.writeStartElement(NS_ATOM, "link");
     writer.writeAttribute("rel", "edit");
     writer.writeAttribute("href", entity.getId().toASCIIString());
@@ -355,41 +359,41 @@ public class ODataXmlSerializer implements ODataSerializer {
       } else {
         String id = entity.getId().toASCIIString();
         if (id.endsWith("/")) {
-          writer.writeAttribute("src", id+"$value");
+          writer.writeAttribute("src", id + "$value");
         } else {
-          writer.writeAttribute("src", id+"/$value");
+          writer.writeAttribute("src", id + "/$value");
         }
       }
       writer.writeEndElement();
     }
-    
+
     // write media links
-    for (Link link:entity.getMediaEditLinks()) {
+    for (Link link : entity.getMediaEditLinks()) {
       writeLink(writer, link);
     }
 
     EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
     writeNavigationProperties(metadata, resolvedType, entity, expand, writer);
-    
+
     writer.writeStartElement(ATOM, "category", NS_ATOM);
     writer.writeAttribute("scheme", NS_SCHEMA);
-    writer.writeAttribute("term", "#"+resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
+    writer.writeAttribute("term", "#" + resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
     writer.writeEndElement();
-    
+
     // In the case media, content is sibiling
     if (!entityType.hasStream()) {
       writer.writeStartElement(NS_ATOM, "content");
       writer.writeAttribute("type", "application/xml");
     }
-    
+
     writer.writeStartElement(METADATA, "properties", NS_METADATA);
     writeProperties(metadata, resolvedType, entity.getProperties(), select, writer);
     writer.writeEndElement(); // properties
-    
+
     if (!entityType.hasStream()) { // content
       writer.writeEndElement();
     }
-    writer.writeEndElement(); //entry
+    writer.writeEndElement(); // entry
   }
 
   private void writerAuthorInfo(final String title, final XMLStreamWriter writer) throws XMLStreamException {
@@ -400,12 +404,12 @@ public class ODataXmlSerializer implements ODataSerializer {
     writer.writeEndElement();
     writer.writeStartElement(NS_ATOM, "summary");
     writer.writeEndElement();
-    
+
     writer.writeStartElement(NS_ATOM, "updated");
     writer.writeCharacters(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
-    .format(new Date(System.currentTimeMillis())));
+        .format(new Date(System.currentTimeMillis())));
     writer.writeEndElement();
-    
+
     writer.writeStartElement(NS_ATOM, "author");
     writer.writeStartElement(NS_ATOM, "name");
     writer.writeEndElement();
@@ -460,9 +464,9 @@ public class ODataXmlSerializer implements ODataSerializer {
             .getFullQualifiedName().getFullQualifiedNameAsString());
   }
 
-  protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type, 
-      final List<Property> properties, final SelectOption select, final XMLStreamWriter writer) 
-          throws XMLStreamException, SerializerException {
+  protected void writeProperties(final ServiceMetadata metadata, final EdmStructuredType type,
+      final List<Property> properties, final SelectOption select, final XMLStreamWriter writer)
+      throws XMLStreamException, SerializerException {
     final boolean all = ExpandSelectHelper.isAll(select);
     final Set<String> selected = all ? null :
         ExpandSelectHelper.getSelectedPropertyNames(select.getSelectItems());
@@ -486,7 +490,7 @@ public class ODataXmlSerializer implements ODataSerializer {
           ExpandSelectHelper.getExpandedPropertyNames(expand.getExpandItems());
       for (final String propertyName : type.getNavigationPropertyNames()) {
         final EdmNavigationProperty property = type.getNavigationProperty(propertyName);
-        final Link navigationLink = getOrCreateLink(linked, propertyName);        
+        final Link navigationLink = getOrCreateLink(linked, propertyName);
         if (expandAll || expanded.contains(propertyName)) {
           final ExpandItem innerOptions = expandAll ? null :
               ExpandSelectHelper.getExpandItem(expand.getExpandItems(), propertyName);
@@ -495,14 +499,14 @@ public class ODataXmlSerializer implements ODataSerializer {
                 SerializerException.MessageKeys.NOT_IMPLEMENTED);
           }
           if (navigationLink != null) {
-            writeLink(writer, navigationLink, false);          
+            writeLink(writer, navigationLink, false);
             writer.writeStartElement(METADATA, "inline", NS_METADATA);
             writeExpandedNavigationProperty(metadata, property, navigationLink,
                 innerOptions == null ? null : innerOptions.getExpandOption(),
-                innerOptions == null ? null : innerOptions.getSelectOption(), 
-                innerOptions == null ? false: innerOptions.isRef(),
+                innerOptions == null ? null : innerOptions.getSelectOption(),
+                innerOptions == null ? false : innerOptions.isRef(),
                 writer);
-            writer.writeEndElement();            
+            writer.writeEndElement();
             writer.writeEndElement();
           }
         } else {
@@ -512,33 +516,34 @@ public class ODataXmlSerializer implements ODataSerializer {
     } else {
       for (final String propertyName : type.getNavigationPropertyNames()) {
         writeLink(writer, getOrCreateLink(linked, propertyName));
-      }      
+      }
     }
-    for (Link link:linked.getAssociationLinks()) {
+    for (Link link : linked.getAssociationLinks()) {
       writeLink(writer, link);
-    }      
+    }
   }
-  
-  protected Link getOrCreateLink(final Linked linked, final String navigationPropertyName) 
+
+  protected Link getOrCreateLink(final Linked linked, final String navigationPropertyName)
       throws XMLStreamException {
     Link link = linked.getNavigationLink(navigationPropertyName);
     if (link == null) {
       link = new Link();
-      link.setRel("http://docs.oasis-open.org/odata/ns/related/"+navigationPropertyName);
+      link.setRel("http://docs.oasis-open.org/odata/ns/related/" + navigationPropertyName);
       link.setType(Constants.ENTITY_SET_NAVIGATION_LINK_TYPE);
       link.setTitle(navigationPropertyName);
       EntityCollection target = new EntityCollection();
       link.setInlineEntitySet(target);
-      link.setHref(linked.getId().toASCIIString()+"/"+navigationPropertyName);
+      link.setHref(linked.getId().toASCIIString() + "/" + navigationPropertyName);
     }
     return link;
-  }  
-  
+  }
+
   private void writeLink(final XMLStreamWriter writer, final Link link) throws XMLStreamException {
     writeLink(writer, link, true);
   }
+
   private void writeLink(final XMLStreamWriter writer, final Link link, final boolean close)
-      throws XMLStreamException {    
+      throws XMLStreamException {
     writer.writeStartElement(ATOM, "link", NS_ATOM);
     writer.writeAttribute("rel", link.getRel());
     if (link.getType() != null) {
@@ -550,12 +555,12 @@ public class ODataXmlSerializer implements ODataSerializer {
     writer.writeAttribute("href", link.getHref());
     if (close) {
       writer.writeEndElement();
-    }    
-  }  
+    }
+  }
 
   protected void writeExpandedNavigationProperty(final ServiceMetadata metadata,
       final EdmNavigationProperty property, final Link navigationLink,
-      final ExpandOption innerExpand, final SelectOption innerSelect, boolean onlyReference, 
+      final ExpandOption innerExpand, final SelectOption innerSelect, boolean onlyReference,
       final XMLStreamWriter writer)
       throws XMLStreamException, SerializerException {
     if (property.isCollection()) {
@@ -577,7 +582,7 @@ public class ODataXmlSerializer implements ODataSerializer {
     }
   }
 
-  protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty, 
+  protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty,
       final Property property,
       final Set<List<String>> selectedPaths, final XMLStreamWriter writer) throws XMLStreamException,
       SerializerException {
@@ -594,25 +599,25 @@ public class ODataXmlSerializer implements ODataSerializer {
     }
     writer.writeEndElement();
   }
-  
+
   private String collectionType(EdmType type) {
-    return "#Collection("+type.getFullQualifiedName().getFullQualifiedNameAsString()+")";
+    return "#Collection(" + type.getFullQualifiedName().getFullQualifiedNameAsString() + ")";
   }
-  
-  private String complexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType) 
+
+  private String complexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType)
       throws SerializerException {
     EdmComplexType type = resolveComplexType(metadata, baseType, definedType);
     return type.getFullQualifiedName().getFullQualifiedNameAsString();
   }
-  
-  private String derivedComplexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType) 
+
+  private String derivedComplexType(ServiceMetadata metadata, EdmComplexType baseType, String definedType)
       throws SerializerException {
     String derived = baseType.getFullQualifiedName().getFullQualifiedNameAsString();
     if (derived.equals(definedType)) {
       return null;
     }
     return definedType;
-  }  
+  }
 
   private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
       final Property property, final Set<List<String>> selectedPaths,
@@ -620,7 +625,7 @@ public class ODataXmlSerializer implements ODataSerializer {
     try {
       if (edmProperty.isPrimitive()) {
         if (edmProperty.isCollection()) {
-          writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection("+edmProperty.getType().getName()+")");
+          writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection(" + edmProperty.getType().getName() + ")");
           writePrimitiveCollection((EdmPrimitiveType) edmProperty.getType(), property,
               edmProperty.isNullable(), edmProperty.getMaxLength(),
               edmProperty.getPrecision(), edmProperty.getScale(), edmProperty.isUnicode(),
@@ -635,8 +640,8 @@ public class ODataXmlSerializer implements ODataSerializer {
         writer.writeAttribute(METADATA, NS_METADATA, "type", collectionType(edmProperty.getType()));
         writeComplexCollection(metadata, (EdmComplexType) edmProperty.getType(), property, selectedPaths, writer);
       } else if (property.isComplex()) {
-        writer.writeAttribute(METADATA, NS_METADATA, "type", 
-            "#"+complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
+        writer.writeAttribute(METADATA, NS_METADATA, "type",
+            "#" + complexType(metadata, (EdmComplexType) edmProperty.getType(), property.getType()));
         writeComplexValue(metadata, (EdmComplexType) edmProperty.getType(), property.asComplex().getValue(),
             selectedPaths, writer);
       } else if (property.isEnum()) {
@@ -677,7 +682,7 @@ public class ODataXmlSerializer implements ODataSerializer {
     }
   }
 
-  private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type, 
+  private void writeComplexCollection(final ServiceMetadata metadata, final EdmComplexType type,
       final Property property, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
       throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
     for (Object value : property.asCollection()) {
@@ -711,7 +716,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       throw new SerializerException("Property type not yet supported!",
           SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
     } else if (property.isEnum()) {
-      writer.writeAttribute(METADATA, NS_METADATA, "type", "#"+type.getName());
+      writer.writeAttribute(METADATA, NS_METADATA, "type", "#" + type.getName());
       writePrimitiveValue(type, property.asEnum(),
           isNullable, maxLength, precision, scale, isUnicode, writer);
     } else {
@@ -728,8 +733,8 @@ public class ODataXmlSerializer implements ODataSerializer {
         isNullable, maxLength, precision, scale, isUnicode);
     if (value == null) {
       writer.writeAttribute(DATA, NS_DATA, "null", "true");
-    } else if(type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
-        writer.writeCharacters(value);
+    } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean)) {
+      writer.writeCharacters(value);
     } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Byte)
         || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Decimal)
         || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double)
@@ -744,7 +749,7 @@ public class ODataXmlSerializer implements ODataSerializer {
     }
   }
 
-  protected void writeComplexValue(final ServiceMetadata metadata, final EdmComplexType type, 
+  protected void writeComplexValue(final ServiceMetadata metadata, final EdmComplexType type,
       final List<Property> properties, final Set<List<String>> selectedPaths, final XMLStreamWriter writer)
       throws XMLStreamException, EdmPrimitiveTypeException, SerializerException {
     for (final String propertyName : type.getPropertyNames()) {
@@ -781,11 +786,11 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeStartElement(METADATA, "value", NS_METADATA);
       writer.writeNamespace(METADATA, NS_METADATA);
       if (contextURL != null) {
-        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
             ContextURLBuilder.create(contextURL).toASCIIString());
       }
       writeMetadataETag(metadata, writer);
-      if(property.isNull()) {
+      if (property.isNull()) {
         writer.writeAttribute(METADATA, NS_METADATA, "null", "true");
       } else {
         writePrimitive(type, property,
@@ -797,7 +802,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeEndDocument();
       writer.flush();
       writer.close();
-  
+
       return SerializerResultImpl.with().content(buffer.getInputStream()).build();
     } catch (final XMLStreamException e) {
       throw new SerializerException("An I/O exception occurred.", e,
@@ -816,7 +821,7 @@ public class ODataXmlSerializer implements ODataSerializer {
               property.getName(), property.getValue().toString());
         }
       }
-    }    
+    }
   }
 
   @Override
@@ -835,7 +840,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeNamespace(DATA, NS_DATA);
       writer.writeAttribute(METADATA, NS_METADATA, "type", "#"
           + resolvedType.getFullQualifiedName().getFullQualifiedNameAsString());
-      writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+      writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
           ContextURLBuilder.create(contextURL).toASCIIString());
       writeMetadataETag(metadata, writer);
       if (property.isNull()) {
@@ -869,11 +874,11 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeStartElement(METADATA, "value", NS_METADATA);
       writer.writeNamespace(METADATA, NS_METADATA);
       if (contextURL != null) {
-        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
             ContextURLBuilder.create(contextURL).toASCIIString());
-      }      
+      }
       writeMetadataETag(metadata, writer);
-      writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection("+type.getName()+")");
+      writer.writeAttribute(METADATA, NS_METADATA, "type", "#Collection(" + type.getName() + ")");
       writePrimitiveCollection(type, property,
           options.isNullable(), options.getMaxLength(), options.getPrecision(), options.getScale(),
           options.isUnicode(),
@@ -882,7 +887,7 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeEndDocument();
       writer.flush();
       writer.close();
-  
+
       return SerializerResultImpl.with().content(buffer.getInputStream()).build();
     } catch (final XMLStreamException e) {
       throw new SerializerException("An I/O exception occurred.", e,
@@ -901,7 +906,7 @@ public class ODataXmlSerializer implements ODataSerializer {
               property.getName(), property.getValue().toString());
         }
       }
-    }     
+    }
   }
 
   @Override
@@ -918,8 +923,8 @@ public class ODataXmlSerializer implements ODataSerializer {
       writer.writeStartElement(METADATA, "value", NS_METADATA);
       writer.writeNamespace(METADATA, NS_METADATA);
       writer.writeNamespace(DATA, NS_DATA);
-      writer.writeAttribute(METADATA, NS_METADATA, "type", collectionType(type));      
-      writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+      writer.writeAttribute(METADATA, NS_METADATA, "type", collectionType(type));
+      writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
           ContextURLBuilder.create(contextURL).toASCIIString());
       writeMetadataETag(metadata, writer);
       writeComplexCollection(metadata, type, property, null, writer);
@@ -939,11 +944,11 @@ public class ODataXmlSerializer implements ODataSerializer {
   }
 
   @Override
-  public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, 
+  public SerializerResult reference(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
       final Entity entity, final ReferenceSerializerOptions options) throws SerializerException {
     return entityReference(metadata, edmEntitySet.getEntityType(), entity, options);
   }
-  
+
   protected SerializerResult entityReference(final ServiceMetadata metadata, final EdmEntityType entityType,
       final Entity entity, ReferenceSerializerOptions options) throws SerializerException {
     CircleStreamBuffer buffer;
@@ -962,14 +967,14 @@ public class ODataXmlSerializer implements ODataSerializer {
           SerializerException.MessageKeys.IO_EXCEPTION);
     }
   }
-  
-  private void writeReference(ServiceMetadata metadata, EdmEntityType entityType, 
+
+  private void writeReference(ServiceMetadata metadata, EdmEntityType entityType,
       Entity entity, ContextURL contextURL, XMLStreamWriter writer, boolean top) throws XMLStreamException {
     writer.writeStartElement(METADATA, "ref", NS_METADATA);
     if (top) {
       writer.writeNamespace(METADATA, NS_METADATA);
       if (contextURL != null) { // top-level entity
-        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT, 
+        writer.writeAttribute(METADATA, NS_METADATA, CONTEXT,
             ContextURLBuilder.create(contextURL).toASCIIString());
       }
     }
@@ -978,12 +983,12 @@ public class ODataXmlSerializer implements ODataSerializer {
   }
 
   @Override
-  public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet, 
-      final EntityCollection entityCollection, ReferenceCollectionSerializerOptions options) 
-          throws SerializerException {
+  public SerializerResult referenceCollection(final ServiceMetadata metadata, final EdmEntitySet edmEntitySet,
+      final EntityCollection entityCollection, ReferenceCollectionSerializerOptions options)
+      throws SerializerException {
     return entityReferenceCollection(metadata, edmEntitySet.getEntityType(), entityCollection, options);
   }
-  
+
   protected SerializerResult entityReferenceCollection(final ServiceMetadata metadata,
       final EdmEntityType entityType, final EntityCollection entitySet,
       ReferenceCollectionSerializerOptions options) throws SerializerException {
@@ -1019,16 +1024,16 @@ public class ODataXmlSerializer implements ODataSerializer {
       throw new SerializerException("An I/O exception occurred.", e,
           SerializerException.MessageKeys.IO_EXCEPTION);
     }
-  }  
-  
-  private void writeCount(final EntityCollection entitySet, XMLStreamWriter writer) 
+  }
+
+  private void writeCount(final EntityCollection entitySet, XMLStreamWriter writer)
       throws XMLStreamException {
     writer.writeStartElement(METADATA, "count", NS_METADATA);
     writer.writeCharacters(String.valueOf(entitySet.getCount()));
     writer.writeEndElement();
   }
 
-  private void writeNextLink(final EntityCollection entitySet, XMLStreamWriter writer) 
+  private void writeNextLink(final EntityCollection entitySet, XMLStreamWriter writer)
       throws XMLStreamException {
     writer.writeStartElement(ATOM, "link", NS_ATOM);
     writer.writeAttribute("rel", "next");