You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by mi...@apache.org on 2014/07/23 10:58:27 UTC

[2/2] git commit: [OLINGO-317] Split ContextURL in parser and builder

[OLINGO-317] Split ContextURL in parser and builder


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

Branch: refs/heads/master
Commit: c75c29ce051fbc942e218f50b8d60f09e5c3c346
Parents: 5476bad
Author: Michael Bolz <mi...@sap.com>
Authored: Wed Jul 23 10:43:46 2014 +0200
Committer: Michael Bolz <mi...@sap.com>
Committed: Wed Jul 23 10:52:09 2014 +0200

----------------------------------------------------------------------
 .../olingo/fit/v4/EntitySetTestITCase.java      |   2 +-
 .../fit/v4/JSONFormatConformanceTestITCase.java |   2 +-
 .../core/serialization/AbstractODataBinder.java |  16 +-
 .../core/serialization/v3/ODataBinderImpl.java  |   5 +-
 .../core/serialization/v4/ODataBinderImpl.java  |  21 +-
 .../client/core/v4/ServiceDocumentTest.java     |   2 +-
 .../olingo/commons/api/data/ContextURL.java     | 201 +++---------
 .../apache/olingo/commons/api/data/ResWrap.java |  10 +-
 .../olingo/commons/api/data/ContextURLTest.java | 325 -------------------
 .../core/serialization/AtomSerializer.java      |   8 +-
 .../core/serialization/ContextURLParser.java    | 110 +++++++
 .../serialization/JsonDeltaDeserializer.java    |   4 +-
 .../serialization/JsonEntitySerializer.java     |   2 +-
 .../serialization/JsonEntitySetSerializer.java  |   2 +-
 .../serialization/JsonPropertySerializer.java   |   2 +-
 .../serialization/ContextURLParserTest.java     | 247 ++++++++++++++
 .../server/api/processor/DefaultProcessor.java  |  24 +-
 .../server/api/serializer/ODataSerializer.java  |  14 +-
 .../org/apache/olingo/server/core/Decoder.java  |  90 -----
 .../server/core/ODataExceptionHandler.java      |  10 +-
 .../serializer/json/ODataJsonSerializer.java    |  72 ++--
 .../serializer/utils/ContextURLBuilder.java     |  57 ++++
 .../serializer/utils/ContextURLBuilderTest.java | 123 +++++++
 .../tecsvc/processor/TechnicalProcessor.java    |   7 +-
 .../server/tecsvc/data/DataProviderTest.java    | 170 ++++++++++
 .../tecsvc/data/JsonDataProviderTest.java       | 196 -----------
 .../json/ODataJsonSerializerTest.java           |  41 ++-
 .../serializer/xml/MetadataDocumentTest.java    |  28 +-
 28 files changed, 900 insertions(+), 891 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
index cb4f0c3..73c0307 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/EntitySetTestITCase.java
@@ -56,7 +56,7 @@ public class EntitySetTestITCase extends AbstractTestITCase {
 
     final ResWrap<ODataEntitySet> entitySet = res.getBodyAs(ODataEntitySet.class);
     assertNotNull(entitySet.getPayload());
-    assertTrue(entitySet.getContextURL().getURI().toASCIIString().endsWith("$metadata#People"));
+    assertTrue(entitySet.getContextURL().toASCIIString().endsWith("$metadata#People"));
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/fit/src/test/java/org/apache/olingo/fit/v4/JSONFormatConformanceTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/JSONFormatConformanceTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/JSONFormatConformanceTestITCase.java
index 75e219d..8c4ef30 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/JSONFormatConformanceTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/JSONFormatConformanceTestITCase.java
@@ -221,7 +221,7 @@ public class JSONFormatConformanceTestITCase extends AbstractTestITCase {
     final ResWrap<Entity> entity =
         client.getDeserializer(ODataFormat.JSON).toEntity(IOUtils.toInputStream(fromSection45_1));
 
-    assertEquals("http://host/service/$metadata#Customers/$entity", entity.getContextURL().getURI().toASCIIString());
+    assertEquals("http://host/service/$metadata#Customers/$entity", entity.getContextURL().toASCIIString());
     assertEquals("W/\"A1FF3E230954908F\"", entity.getMetadataETag());
     assertEquals("W/\"A1FF3E230954908G\"", entity.getPayload().getETag());
     assertEquals("Model.VipCustomer", entity.getPayload().getType());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java
index afc32d0..a33a9d4 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AbstractODataBinder.java
@@ -67,6 +67,7 @@ import org.apache.olingo.commons.core.data.EntitySetImpl;
 import org.apache.olingo.commons.core.data.LinkImpl;
 import org.apache.olingo.commons.core.data.PropertyImpl;
 import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.serialization.ContextURLParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -256,8 +257,9 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
       LOG.debug("EntitySet -> ODataEntitySet:\n{}", writer.toString());
     }
 
-    final URI base = resource.getContextURL() == null
-            ? resource.getPayload().getBaseURI() : resource.getContextURL().getServiceRoot();
+    final URI base = resource.getContextURL() == null ?
+        resource.getPayload().getBaseURI() :
+        ContextURLParser.parse(resource.getContextURL()).getServiceRoot();
 
     final URI next = resource.getPayload().getNext();
 
@@ -411,9 +413,11 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
       LOG.debug("EntityResource -> ODataEntity:\n{}", writer.toString());
     }
 
-    final URI base = resource.getContextURL() == null
-            ? resource.getPayload().getBaseURI() : resource.getContextURL().getServiceRoot();
-    final EdmType edmType = findType(resource.getContextURL(), resource.getMetadataETag());
+    final ContextURL contextURL = ContextURLParser.parse(resource.getContextURL());
+    final URI base = resource.getContextURL() == null ?
+        resource.getPayload().getBaseURI() :
+        contextURL.getServiceRoot();
+    final EdmType edmType = findType(contextURL, resource.getMetadataETag());
     FullQualifiedName typeName = null;
     if (resource.getPayload().getType() == null) {
       if (edmType != null) {
@@ -511,7 +515,7 @@ public abstract class AbstractODataBinder implements CommonODataBinder {
   protected abstract CommonODataProperty getODataProperty(EdmType type, Property resource);
 
   protected ODataValue getODataValue(final FullQualifiedName type,
-          final Valuable valuable, final ContextURL contextURL, final String metadataETag) {
+          final Valuable valuable, final URI contextURL, final String metadataETag) {
 
     ODataValue value = null;
     if (valuable.isGeospatial()) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v3/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v3/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v3/ODataBinderImpl.java
index 9410de0..4bd6b08 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v3/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v3/ODataBinderImpl.java
@@ -42,6 +42,7 @@ import org.apache.olingo.commons.api.edm.geo.Geospatial;
 import org.apache.olingo.commons.core.data.PropertyImpl;
 import org.apache.olingo.commons.core.domain.v3.ODataPropertyImpl;
 import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.serialization.ContextURLParser;
 
 public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder {
 
@@ -109,8 +110,8 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
   @Override
   public ODataProperty getODataProperty(final ResWrap<Property> property) {
-    final EdmTypeInfo typeInfo = buildTypeInfo(property.getContextURL(), property.getMetadataETag(),
-            property.getPayload().getName(), property.getPayload().getType());
+    final EdmTypeInfo typeInfo = buildTypeInfo(ContextURLParser.parse(property.getContextURL()),
+        property.getMetadataETag(), property.getPayload().getName(), property.getPayload().getType());
 
     return new ODataPropertyImpl(property.getPayload().getName(),
             getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v4/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v4/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v4/ODataBinderImpl.java
index 538ea23..654764e 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v4/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/v4/ODataBinderImpl.java
@@ -27,7 +27,6 @@ import org.apache.olingo.client.core.serialization.AbstractODataBinder;
 import org.apache.olingo.client.core.uri.URIUtils;
 import org.apache.olingo.commons.api.data.Annotatable;
 import org.apache.olingo.commons.api.data.Annotation;
-import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.DeletedEntity;
 import org.apache.olingo.commons.api.data.Delta;
 import org.apache.olingo.commons.api.data.DeltaLink;
@@ -75,6 +74,7 @@ import org.apache.olingo.commons.core.domain.v4.ODataDeletedEntityImpl;
 import org.apache.olingo.commons.core.domain.v4.ODataDeltaLinkImpl;
 import org.apache.olingo.commons.core.domain.v4.ODataPropertyImpl;
 import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.commons.core.serialization.ContextURLParser;
 
 import java.net.URI;
 import java.util.List;
@@ -273,8 +273,9 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
     final ODataEntitySet entitySet = (ODataEntitySet) super.getODataEntitySet(resource);
 
     if (resource.getPayload().getDeltaLink() != null) {
-      final URI base = resource.getContextURL() == null
-              ? resource.getPayload().getBaseURI() : resource.getContextURL().getServiceRoot();
+      final URI base = resource.getContextURL() == null ?
+          resource.getPayload().getBaseURI() :
+          ContextURLParser.parse(resource.getContextURL()).getServiceRoot();
       entitySet.setDeltaLink(URIUtils.getURI(base, resource.getPayload().getDeltaLink()));
     }
     odataAnnotations(resource.getPayload(), entitySet);
@@ -307,8 +308,8 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
   @Override
   public ODataProperty getODataProperty(final ResWrap<Property> resource) {
     final Property payload = resource.getPayload();
-    final EdmTypeInfo typeInfo = buildTypeInfo(resource.getContextURL(), resource.getMetadataETag(),
-            payload.getName(), payload.getType());
+    final EdmTypeInfo typeInfo = buildTypeInfo(ContextURLParser.parse(resource.getContextURL()),
+        resource.getMetadataETag(), payload.getName(), payload.getType());
 
     final ODataProperty property = new ODataPropertyImpl(payload.getName(),
             getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
@@ -332,7 +333,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
   @Override
   protected ODataValue getODataValue(final FullQualifiedName type,
-          final Valuable valuable, final ContextURL contextURL, final String metadataETag) {
+          final Valuable valuable, final URI contextURL, final String metadataETag) {
 
     // fixes enum values treated as primitive when no type information is available
     if (client instanceof EdmEnabledODataClient && type != null) {
@@ -359,8 +360,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
         edmType = ((EdmEnabledODataClient) client).getEdm(metadataETag).getComplexType(type);
       }
 
-      odataNavigationLinks(edmType, valuable.asLinkedComplex(), lcValue, metadataETag,
-              contextURL == null ? null : contextURL.getURI());
+      odataNavigationLinks(edmType, valuable.asLinkedComplex(), lcValue, metadataETag, contextURL);
       odataAnnotations(valuable.asLinkedComplex(), lcValue);
 
       value = lcValue;
@@ -373,8 +373,9 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
   @Override
   public ODataDelta getODataDelta(final ResWrap<Delta> resource) {
-    final URI base = resource.getContextURL() == null
-            ? resource.getPayload().getBaseURI() : resource.getContextURL().getServiceRoot();
+    final URI base = resource.getContextURL() == null ?
+        resource.getPayload().getBaseURI() :
+        ContextURLParser.parse(resource.getContextURL()).getServiceRoot();
 
     final URI next = resource.getPayload().getNext();
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/ServiceDocumentTest.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/ServiceDocumentTest.java b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/ServiceDocumentTest.java
index 711345a..67154ab 100644
--- a/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/ServiceDocumentTest.java
+++ b/lib/client-core/src/test/java/org/apache/olingo/client/core/v4/ServiceDocumentTest.java
@@ -48,7 +48,7 @@ public class ServiceDocumentTest extends AbstractTest {
     ResWrap<ServiceDocument> service = getClient().getDeserializer(format).toServiceDocument(
             getClass().getResourceAsStream("serviceDocument." + getFileExtension(format)));
 
-    assertEquals(URI.create("http://host/service/$metadata"), service.getContextURL().getURI());
+    assertEquals(URI.create("http://host/service/$metadata"), service.getContextURL());
     assertEquals("W/\"MjAxMy0wNS0xM1QxNDo1NFo=\"", service.getMetadataETag());
 
     final ODataServiceDocument serviceDocument = getClient().getBinder().getODataServiceDocument(service.getPayload());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/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 91ab86f..f8095fb 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
@@ -18,41 +18,29 @@
  */
 package org.apache.olingo.commons.api.data;
 
-import org.apache.commons.lang3.StringUtils;
-import org.apache.olingo.commons.api.Constants;
+import java.net.URI;
+
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 
-import java.net.URI;
-
 /**
- * High-level representation of a context URL, built from the string value returned by a service; provides access to the
- * various components of the context URL, defined in the <a
+ * High-level representation of a context URL,
+ * built from the string value returned by a service;
+ * provides access to the various components of the context URL, defined in the <a
  * href="http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html#_Toc372793655">
  * protocol specification</a>.
  */
 public class ContextURL {
 
-  private URI uri;
-
   private URI serviceRoot;
-
   private String entitySetOrSingletonOrType;
-
   private String derivedEntity;
-
   private String selectList;
-
   private String navOrPropertyPath;
 
   public enum Suffix {
-
-    ENTITY("$entity"),
-    REFERENCE("$ref"),
-    DELTA("$delta"),
-    DELTA_DELETED_ENTITY("$deletedEntity"),
-    DELTA_LINK("$link"),
-    DELTA_DELETED_LINK("$deletedLink");
+    ENTITY("$entity"), REFERENCE("$ref"),
+    DELTA("$delta"), DELTA_DELETED_ENTITY("$deletedEntity"), DELTA_LINK("$link"), DELTA_DELETED_LINK("$deletedLink");
 
     private final String representation;
 
@@ -64,92 +52,12 @@ public class ContextURL {
       return representation;
     }
   }
+
   private Suffix suffix;
 
   private ContextURL() {
   }
 
-  public static ContextURL getInstance(final URI contextURL) {
-    final ContextURL instance = new ContextURL();
-    instance.uri = contextURL;
-
-    String contextURLasString = instance.uri.toASCIIString();
-
-    if (contextURLasString.endsWith("/$entity") || contextURLasString.endsWith("/@Element")) {
-      instance.suffix = Suffix.ENTITY;
-      contextURLasString = contextURLasString.replace("/$entity", StringUtils.EMPTY)
-              .replace("/@Element", StringUtils.EMPTY);
-    } else if (contextURLasString.endsWith("/$ref")) {
-      instance.suffix = Suffix.REFERENCE;
-      contextURLasString = contextURLasString.replace("/$ref", StringUtils.EMPTY);
-    } else if (contextURLasString.endsWith("/$delta")) {
-      instance.suffix = Suffix.DELTA;
-      contextURLasString = contextURLasString.replace("/$delta", StringUtils.EMPTY);
-    } else if (contextURLasString.endsWith("/$deletedEntity")) {
-      instance.suffix = Suffix.DELTA_DELETED_ENTITY;
-      contextURLasString = contextURLasString.replace("/$deletedEntity", StringUtils.EMPTY);
-    } else if (contextURLasString.endsWith("/$link")) {
-      instance.suffix = Suffix.DELTA_LINK;
-      contextURLasString = contextURLasString.replace("/$link", StringUtils.EMPTY);
-    } else if (contextURLasString.endsWith("/$deletedLink")) {
-      instance.suffix = Suffix.DELTA_DELETED_LINK;
-      contextURLasString = contextURLasString.replace("/$deletedLink", StringUtils.EMPTY);
-    }
-
-    instance.serviceRoot = URI.create(StringUtils.substringBefore(contextURLasString, Constants.METADATA));
-
-    final String rest = StringUtils.substringAfter(contextURLasString, Constants.METADATA + "#");
-
-    String firstToken;
-    if (rest.startsWith("Collection(")) {
-      firstToken = rest.substring(0, rest.indexOf(')') + 1);
-      instance.entitySetOrSingletonOrType = firstToken;
-    } else {
-      final int openParIdx = rest.indexOf('(');
-      if (openParIdx == -1) {
-        firstToken = StringUtils.substringBefore(rest, "/");
-
-        instance.entitySetOrSingletonOrType = firstToken;
-      } else {
-        firstToken = StringUtils.substringBeforeLast(rest, ")") + ")";
-
-        instance.entitySetOrSingletonOrType = firstToken.substring(0, openParIdx);
-        final int commaIdx = firstToken.indexOf(',');
-        if (commaIdx != -1) {
-          instance.selectList = firstToken.substring(openParIdx + 1, firstToken.length() - 1);
-        }
-      }
-    }
-
-    final int slashIdx = instance.entitySetOrSingletonOrType.lastIndexOf('/');
-    if (slashIdx != -1 && instance.entitySetOrSingletonOrType.substring(slashIdx + 1).indexOf('.') != -1) {
-      final String clone = instance.entitySetOrSingletonOrType;
-      instance.entitySetOrSingletonOrType = clone.substring(0, slashIdx);
-      instance.derivedEntity = clone.substring(slashIdx + 1);
-    }
-
-    if (!firstToken.equals(rest)) {
-      final String[] pathElems = StringUtils.substringAfter(rest, "/").split("/");
-      if (pathElems.length > 0 && pathElems[0].length() > 0) {
-        if (pathElems[0].indexOf('.') == -1) {
-          instance.navOrPropertyPath = pathElems[0];
-        } else {
-          instance.derivedEntity = pathElems[0];
-        }
-
-        if (pathElems.length > 1) {
-          instance.navOrPropertyPath = pathElems[1];
-        }
-      }
-    }
-
-    return instance;
-  }
-
-  public URI getURI() {
-    return uri;
-  }
-
   public URI getServiceRoot() {
     return serviceRoot;
   }
@@ -170,6 +78,10 @@ public class ContextURL {
     return navOrPropertyPath;
   }
 
+  public Suffix getSuffix() {
+    return suffix;
+  }
+
   public boolean isEntity() {
     return suffix == Suffix.ENTITY;
   }
@@ -194,90 +106,59 @@ public class ContextURL {
     return suffix == Suffix.DELTA_DELETED_LINK;
   }
 
-  public static final class ContextURLBuilder {
+  public static final class Builder {
 
     private ContextURL contextURL = new ContextURL();
 
-    private ContextURLBuilder() {
+    private Builder() {
+    }
+
+    public static final Builder create() {
+      return new Builder();
     }
 
-    public ContextURLBuilder serviceRoot(final URI serviceRoot) {
+    public Builder serviceRoot(final URI serviceRoot) {
       contextURL.serviceRoot = serviceRoot;
       return this;
     }
 
-    public ContextURLBuilder entitySet(final EdmEntitySet entitySet) {
+    public Builder entitySet(final EdmEntitySet entitySet) {
       contextURL.entitySetOrSingletonOrType = entitySet.getName();
       return this;
     }
 
-    public ContextURLBuilder derived(final EdmEntityType derivedType) {
-      contextURL.derivedEntity = derivedType.getFullQualifiedName().getFullQualifiedNameAsString();
+    public Builder entitySetOrSingletonOrType(final String entitySetOrSingletonOrType) {
+      contextURL.entitySetOrSingletonOrType = entitySetOrSingletonOrType;
       return this;
     }
 
-    public ContextURLBuilder suffix(final Suffix suffix) {
-      contextURL.suffix = suffix;
+    public Builder derived(final EdmEntityType derivedType) {
+      contextURL.derivedEntity = derivedType.getFullQualifiedName().getFullQualifiedNameAsString();
       return this;
     }
 
-    public ContextURL build() {
-      final StringBuilder result = new StringBuilder();
-      if (contextURL.serviceRoot != null) {
-        result.append(contextURL.serviceRoot);
-      }
-      result.append(Constants.METADATA);
-      if (contextURL.entitySetOrSingletonOrType != null) {
-        result.append('#').append(contextURL.entitySetOrSingletonOrType);
-      }
-      if (contextURL.derivedEntity != null) {
-        if (contextURL.entitySetOrSingletonOrType == null) {
-          throw new IllegalArgumentException("ContextURL: Derived Type without anything to derive from!");
-        }
-        result.append('/').append(contextURL.derivedEntity);
-      }
-      if (contextURL.suffix == Suffix.REFERENCE) {
-        if (contextURL.entitySetOrSingletonOrType != null) {
-          throw new IllegalArgumentException("ContextURL: $ref with Entity Set");
-        }
-        result.append('#').append(contextURL.suffix.getRepresentation());
-      } else if (contextURL.suffix != null) {
-        if (contextURL.entitySetOrSingletonOrType == null) {
-          throw new IllegalArgumentException("ContextURL: Suffix without preceding Entity Set!");
-        }
-        result.append('/').append(contextURL.suffix.getRepresentation());
-      }
-      contextURL.uri = URI.create(result.toString());
-      return contextURL;
+    public Builder derivedEntity(final String derivedEntity) {
+      contextURL.derivedEntity = derivedEntity;
+      return this;
     }
-  }
-
-  public static final ContextURLBuilder create() {
-    return new ContextURLBuilder();
-  }
 
-  @Override
-  public boolean equals(final Object obj) {
-    if (obj == null) {
-      return false;
-    }
-    if (getClass() != obj.getClass()) {
-      return false;
+    public Builder navOrPropertyPath(final String navOrPropertyPath) {
+      contextURL.navOrPropertyPath = navOrPropertyPath;
+      return this;
     }
-    final ContextURL other = (ContextURL) obj;
-    if (uri != other.uri && (uri == null || !uri.equals(other.uri))) {
-      return false;
+
+    public Builder selectList(final String selectList) {
+      contextURL.selectList = selectList;
+      return this;
     }
-    return true;
-  }
 
-  @Override
-  public int hashCode() {
-    return uri.hashCode();
-  }
+    public Builder suffix(final Suffix suffix) {
+      contextURL.suffix = suffix;
+      return this;
+    }
 
-  @Override
-  public String toString() {
-    return uri.toString();
+    public ContextURL build() {
+      return contextURL;
+    }
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ResWrap.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ResWrap.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ResWrap.java
index 1bd1a38..06e889f 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ResWrap.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/ResWrap.java
@@ -27,17 +27,11 @@ import java.net.URI;
  */
 public class ResWrap<T> {
 
-  private final ContextURL contextURL;
-
+  private final URI contextURL;
   private final String metadataETag;
-
   private final T payload;
 
   public ResWrap(final URI contextURL, final String metadataETag, final T payload) {
-    this(contextURL == null ? null : ContextURL.getInstance(contextURL), metadataETag, payload);
-  }
-
-  public ResWrap(final ContextURL contextURL, final String metadataETag, final T payload) {
     this.contextURL = contextURL;
     this.metadataETag = metadataETag;
     this.payload = payload;
@@ -55,7 +49,7 @@ public class ResWrap<T> {
    * 
    * @return context URL.
    */
-  public ContextURL getContextURL() {
+  public URI getContextURL() {
     return contextURL;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java b/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java
deleted file mode 100644
index abef744..0000000
--- a/lib/commons-api/src/test/java/org/apache/olingo/commons/api/data/ContextURLTest.java
+++ /dev/null
@@ -1,325 +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.commons.api.data;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-
-import org.apache.olingo.commons.api.data.ContextURL.Suffix;
-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.junit.Test;
-import org.mockito.Mockito;
-
-import java.net.URI;
-
-public class ContextURLTest {
-
-  @Test
-  public void collectionOfEntities() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers"));
-
-    assertEquals(URI.create("http://host/service/"), contextURL.getServiceRoot());
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Orders(4711)/Items"));
-
-    assertEquals("Orders", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertEquals("Items", contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Me/Folders('Inbox')/Messages"));
-
-    assertEquals("Me/Folders", contextURL.getEntitySetOrSingletonOrType());
-    assertEquals("Messages", contextURL.getNavOrPropertyPath());
-  }
-
-  @Test
-  public void entity() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$entity"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertTrue(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Orders(4711)/Items/$entity"));
-
-    assertEquals("Orders", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertEquals("Items", contextURL.getNavOrPropertyPath());
-    assertTrue(contextURL.isEntity());
-
-    // v3
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Products/@Element"));
-
-    assertEquals("Products", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertTrue(contextURL.isEntity());
-  }
-
-  @Test
-  public void singleton() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Contoso"));
-
-    assertEquals("Contoso", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void collectionOfDerivedEntities() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers/Model.VipCustomer"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertEquals("Model.VipCustomer", contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void derivedEntity() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers/Model.VipCustomer/$entity"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertEquals("Model.VipCustomer", contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertTrue(contextURL.isEntity());
-  }
-
-  @Test
-  public void collectionOfProjectedEntities() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers(Address,Orders)"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertEquals("Address,Orders", contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void projectedEntity() {
-    ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers(Name,Rating)/$entity"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertEquals("Name,Rating", contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertTrue(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers(Name,Address/Country)"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertEquals("Name,Address/Country", contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void collectionOfProjectedExpandedEntities() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Employees/"
-                    + "Sales.Manager(DirectReports,DirectReports+(FirstName,LastName))"));
-
-    assertEquals("Employees", contextURL.getEntitySetOrSingletonOrType());
-    assertEquals("Sales.Manager", contextURL.getDerivedEntity());
-    assertEquals("DirectReports,DirectReports+(FirstName,LastName)", contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void propertyValue() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Customers(1)/Addresses"));
-
-    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertEquals("Addresses", contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void CollectionOfComplexOrPrimitiveTypes() {
-    final ContextURL contextURL = ContextURL.getInstance(
-            URI.create("http://host/service/$metadata#Collection(Edm.String)"));
-
-    assertEquals("Collection(Edm.String)", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void complexOrPrimitiveType() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Edm.String"));
-
-    assertEquals("Edm.String", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#ODataDemo.Address"));
-
-    assertEquals("ODataDemo.Address", contextURL.getEntitySetOrSingletonOrType());
-    assertNull(contextURL.getDerivedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void reference() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$ref"));
-    assertTrue(contextURL.isReference());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-    assertFalse(contextURL.isDelta());
-  }
-
-  @Test
-  public void delta() {
-    ContextURL contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$delta"));
-    assertTrue(contextURL.isDelta());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$deletedLink"));
-    assertTrue(contextURL.isDeltaDeletedLink());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$link"));
-    assertTrue(contextURL.isDeltaLink());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-
-    contextURL = ContextURL.getInstance(URI.create("http://host/service/$metadata#Customers/$deletedEntity"));
-    assertTrue(contextURL.isDeltaDeletedEntity());
-    assertNull(contextURL.getSelectList());
-    assertNull(contextURL.getNavOrPropertyPath());
-    assertFalse(contextURL.isEntity());
-  }
-
-  @Test
-  public void buildServiceDocument() {
-    ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/")).build();
-    assertEquals("http://host/service/$metadata", contextURL.getURI().toASCIIString());
-  }
-
-  @Test
-  public void buildRelative() {
-    ContextURL contextURL = ContextURL.create().build();
-    assertEquals("$metadata", contextURL.getURI().toASCIIString());
-  }
-
-  @Test
-  public void buildEntitySet() {
-    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
-    Mockito.when(entitySet.getName()).thenReturn("Customers");
-    ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/"))
-            .entitySet(entitySet)
-            .build();
-    assertEquals("http://host/service/$metadata#Customers", contextURL.getURI().toASCIIString());
-  }
-
-  @Test
-  public void buildDerivedEntitySet() {
-    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
-    Mockito.when(entitySet.getName()).thenReturn("Customers");
-    EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
-    Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/"))
-            .entitySet(entitySet)
-            .derived(derivedType)
-            .build();
-    assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer", contextURL.getURI().toASCIIString());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void buildDerivedEntitySetWithoutEntitySet() {
-    EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
-    Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURL.create().derived(derivedType).build();
-  }
-
-  @Test
-  public void buildDerivedEntity() {
-    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
-    Mockito.when(entitySet.getName()).thenReturn("Customers");
-    EdmEntityType derivedType = Mockito.mock(EdmEntityType.class);
-    Mockito.when(derivedType.getFullQualifiedName()).thenReturn(new FullQualifiedName("Model", "VipCustomer"));
-    ContextURL contextURL = ContextURL.create().serviceRoot(URI.create("http://host/service/"))
-            .entitySet(entitySet)
-            .derived(derivedType)
-            .suffix(Suffix.ENTITY)
-            .build();
-    assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer/$entity",
-            contextURL.getURI().toASCIIString());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void buildSuffixWithoutEntitySet() {
-    ContextURL.create().suffix(Suffix.ENTITY).build();
-  }
-
-  @Test
-  public void buildReference() {
-    ContextURL contextURL = ContextURL.create().suffix(Suffix.REFERENCE).build();
-    assertEquals("$metadata#$ref", contextURL.getURI().toASCIIString());
-  }
-
-  @Test(expected = IllegalArgumentException.class)
-  public void buildReferenceWithEntitySet() {
-    EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
-    Mockito.when(entitySet.getName()).thenReturn("Customers");
-    ContextURL.create().entitySet(entitySet).suffix(Suffix.REFERENCE).build();
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
index 79ffd13..5475064 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/AtomSerializer.java
@@ -19,9 +19,11 @@
 package org.apache.olingo.commons.core.serialization;
 
 import com.fasterxml.aalto.stax.OutputFactoryImpl;
+
 import org.apache.commons.lang3.StringUtils;
 import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.data.Link;
@@ -49,6 +51,7 @@ import javax.xml.XMLConstants;
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamWriter;
+
 import java.io.Writer;
 import java.util.Collections;
 import java.util.List;
@@ -549,7 +552,8 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
       final XMLStreamWriter writer, final ResWrap<T> container) throws XMLStreamException {
 
     if (container.getContextURL() != null) {
-      String base = container.getContextURL().getServiceRoot().toASCIIString();
+      final ContextURL contextURL = ContextURLParser.parse(container.getContextURL());
+      String base = contextURL.getServiceRoot().toASCIIString();
       if (container.getPayload() instanceof EntitySet) {
         ((EntitySetImpl) container.getPayload()).setBaseURI(base);
       }
@@ -558,7 +562,7 @@ public class AtomSerializer extends AbstractAtomDealer implements ODataSerialize
       }
 
       writer.writeAttribute(namespaceMetadata, Constants.CONTEXT,
-          container.getContextURL().getURI().toASCIIString());
+          container.getContextURL().toASCIIString());
     }
 
     if (StringUtils.isNotBlank(container.getMetadataETag())) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
new file mode 100644
index 0000000..3598af7
--- /dev/null
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/ContextURLParser.java
@@ -0,0 +1,110 @@
+/*
+ * 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.commons.core.serialization;
+
+import java.net.URI;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.ContextURL.Suffix;
+
+public class ContextURLParser {
+  public static ContextURL parse(final URI contextURL) {
+    if (contextURL == null) {
+      return null;
+    }
+
+    ContextURL.Builder builder = ContextURL.Builder.create();
+
+    String contextURLasString = contextURL.toASCIIString();
+
+    if (contextURLasString.endsWith("/$entity") || contextURLasString.endsWith("/@Element")) {
+      builder.suffix(Suffix.ENTITY);
+      contextURLasString = contextURLasString.replace("/$entity", StringUtils.EMPTY)
+              .replace("/@Element", StringUtils.EMPTY);
+    } else if (contextURLasString.endsWith("/$ref")) {
+      builder.suffix(Suffix.REFERENCE);
+      contextURLasString = contextURLasString.replace("/$ref", StringUtils.EMPTY);
+    } else if (contextURLasString.endsWith("/$delta")) {
+      builder.suffix(Suffix.DELTA);
+      contextURLasString = contextURLasString.replace("/$delta", StringUtils.EMPTY);
+    } else if (contextURLasString.endsWith("/$deletedEntity")) {
+      builder.suffix(Suffix.DELTA_DELETED_ENTITY);
+      contextURLasString = contextURLasString.replace("/$deletedEntity", StringUtils.EMPTY);
+    } else if (contextURLasString.endsWith("/$link")) {
+      builder.suffix(Suffix.DELTA_LINK);
+      contextURLasString = contextURLasString.replace("/$link", StringUtils.EMPTY);
+    } else if (contextURLasString.endsWith("/$deletedLink")) {
+      builder.suffix(Suffix.DELTA_DELETED_LINK);
+      contextURLasString = contextURLasString.replace("/$deletedLink", StringUtils.EMPTY);
+    }
+
+    builder.serviceRoot(URI.create(StringUtils.substringBefore(contextURLasString, Constants.METADATA)));
+
+    final String rest = StringUtils.substringAfter(contextURLasString, Constants.METADATA + "#");
+
+    String firstToken;
+    String entitySetOrSingletonOrType = null;
+    if (rest.startsWith("Collection(")) {
+      firstToken = rest.substring(0, rest.indexOf(')') + 1);
+      entitySetOrSingletonOrType = firstToken;
+    } else {
+      final int openParIdx = rest.indexOf('(');
+      if (openParIdx == -1) {
+        firstToken = StringUtils.substringBefore(rest, "/");
+
+        entitySetOrSingletonOrType = firstToken;
+      } else {
+        firstToken = StringUtils.substringBeforeLast(rest, ")") + ")";
+
+        entitySetOrSingletonOrType = firstToken.substring(0, openParIdx);
+        final int commaIdx = firstToken.indexOf(',');
+        if (commaIdx != -1) {
+          builder.selectList(firstToken.substring(openParIdx + 1, firstToken.length() - 1));
+        }
+      }
+    }
+    builder.entitySetOrSingletonOrType(entitySetOrSingletonOrType);
+
+    final int slashIdx = entitySetOrSingletonOrType.lastIndexOf('/');
+    if (slashIdx != -1 && entitySetOrSingletonOrType.substring(slashIdx + 1).indexOf('.') != -1) {
+      final String clone = entitySetOrSingletonOrType;
+      builder.entitySetOrSingletonOrType(clone.substring(0, slashIdx));
+      builder.derivedEntity(clone.substring(slashIdx + 1));
+    }
+
+    if (!firstToken.equals(rest)) {
+      final String[] pathElems = StringUtils.substringAfter(rest, "/").split("/");
+      if (pathElems.length > 0 && pathElems[0].length() > 0) {
+        if (pathElems[0].indexOf('.') == -1) {
+          builder.navOrPropertyPath(pathElems[0]);
+        } else {
+          builder.derivedEntity(pathElems[0]);
+        }
+
+        if (pathElems.length > 1) {
+          builder.navOrPropertyPath(pathElems[1]);
+        }
+      }
+    }
+
+    return builder.build();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonDeltaDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonDeltaDeserializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonDeltaDeserializer.java
index 3505df9..a9d4fb4 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonDeltaDeserializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonDeltaDeserializer.java
@@ -70,8 +70,8 @@ public class JsonDeltaDeserializer extends JsonDeserializer {
       JsonEntityDeserializer entityDeserializer = new JsonEntityDeserializer(version, serverMode);
       for (JsonNode jsonNode : tree.get(Constants.VALUE)) {
         final ObjectNode item = (ObjectNode) jsonNode;
-        final ContextURL itemContextURL = item.hasNonNull(Constants.JSON_CONTEXT)
-            ? ContextURL.getInstance(URI.create(item.get(Constants.JSON_CONTEXT).textValue())) : null;
+        final ContextURL itemContextURL = item.hasNonNull(Constants.JSON_CONTEXT) ?
+            ContextURLParser.parse(URI.create(item.get(Constants.JSON_CONTEXT).textValue())) : null;
         item.remove(Constants.JSON_CONTEXT);
 
         if (itemContextURL == null || itemContextURL.isEntity()) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySerializer.java
index 65fb28e..9396b77 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySerializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySerializer.java
@@ -59,7 +59,7 @@ public class JsonEntitySerializer extends JsonSerializer {
       if (container.getContextURL() != null) {
         jgen.writeStringField(version.compareTo(ODataServiceVersion.V40) >= 0
             ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
-            container.getContextURL().getURI().toASCIIString());
+            container.getContextURL().toASCIIString());
       }
       if (version.compareTo(ODataServiceVersion.V40) >= 0 && StringUtils.isNotBlank(container.getMetadataETag())) {
         jgen.writeStringField(Constants.JSON_METADATA_ETAG, container.getMetadataETag());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySetSerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySetSerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySetSerializer.java
index fb21520..256376c 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySetSerializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonEntitySetSerializer.java
@@ -53,7 +53,7 @@ public class JsonEntitySetSerializer extends JsonSerializer {
       if (container.getContextURL() != null) {
         jgen.writeStringField(version.compareTo(ODataServiceVersion.V40) >= 0
             ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
-            container.getContextURL().getURI().toASCIIString());
+            container.getContextURL().toASCIIString());
       }
 
       if (version.compareTo(ODataServiceVersion.V40) >= 0 && StringUtils.isNotBlank(container.getMetadataETag())) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonPropertySerializer.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonPropertySerializer.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonPropertySerializer.java
index feda16b..5b00a6a 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonPropertySerializer.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/serialization/JsonPropertySerializer.java
@@ -55,7 +55,7 @@ public class JsonPropertySerializer extends JsonSerializer {
     if (serverMode && container.getContextURL() != null) {
       jgen.writeStringField(version.compareTo(ODataServiceVersion.V40) >= 0
           ? Constants.JSON_CONTEXT : Constants.JSON_METADATA,
-          container.getContextURL().getURI().toASCIIString());
+          container.getContextURL().toASCIIString());
     }
 
     if (StringUtils.isNotBlank(property.getType())) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/commons-core/src/test/java/org/apache/olingo/commons/core/serialization/ContextURLParserTest.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/test/java/org/apache/olingo/commons/core/serialization/ContextURLParserTest.java b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/serialization/ContextURLParserTest.java
new file mode 100644
index 0000000..5a16da2
--- /dev/null
+++ b/lib/commons-core/src/test/java/org/apache/olingo/commons/core/serialization/ContextURLParserTest.java
@@ -0,0 +1,247 @@
+/*
+ * 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.commons.core.serialization;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.core.serialization.ContextURLParser;
+import org.junit.Test;
+
+import java.net.URI;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+public class ContextURLParserTest {
+
+  @Test
+  public void collectionOfEntities() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers"));
+
+    assertEquals(URI.create("http://host/service/"), contextURL.getServiceRoot());
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Orders(4711)/Items"));
+
+    assertEquals("Orders", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertEquals("Items", contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Me/Folders('Inbox')/Messages"));
+
+    assertEquals("Me/Folders", contextURL.getEntitySetOrSingletonOrType());
+    assertEquals("Messages", contextURL.getNavOrPropertyPath());
+  }
+
+  @Test
+  public void entity() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$entity"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertTrue(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Orders(4711)/Items/$entity"));
+
+    assertEquals("Orders", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertEquals("Items", contextURL.getNavOrPropertyPath());
+    assertTrue(contextURL.isEntity());
+
+    // v3
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Products/@Element"));
+
+    assertEquals("Products", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertTrue(contextURL.isEntity());
+  }
+
+  @Test
+  public void singleton() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Contoso"));
+
+    assertEquals("Contoso", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void collectionOfDerivedEntities() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers/Model.VipCustomer"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertEquals("Model.VipCustomer", contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void derivedEntity() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers/Model.VipCustomer/$entity"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertEquals("Model.VipCustomer", contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertTrue(contextURL.isEntity());
+  }
+
+  @Test
+  public void collectionOfProjectedEntities() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers(Address,Orders)"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertEquals("Address,Orders", contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void projectedEntity() {
+    ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers(Name,Rating)/$entity"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertEquals("Name,Rating", contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertTrue(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers(Name,Address/Country)"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertEquals("Name,Address/Country", contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void collectionOfProjectedExpandedEntities() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Employees/"
+            + "Sales.Manager(DirectReports,DirectReports+(FirstName,LastName))"));
+
+    assertEquals("Employees", contextURL.getEntitySetOrSingletonOrType());
+    assertEquals("Sales.Manager", contextURL.getDerivedEntity());
+    assertEquals("DirectReports,DirectReports+(FirstName,LastName)", contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void propertyValue() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Customers(1)/Addresses"));
+
+    assertEquals("Customers", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertEquals("Addresses", contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void CollectionOfComplexOrPrimitiveTypes() {
+    final ContextURL contextURL = ContextURLParser.parse(
+        URI.create("http://host/service/$metadata#Collection(Edm.String)"));
+
+    assertEquals("Collection(Edm.String)", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void complexOrPrimitiveType() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Edm.String"));
+
+    assertEquals("Edm.String", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#ODataDemo.Address"));
+
+    assertEquals("ODataDemo.Address", contextURL.getEntitySetOrSingletonOrType());
+    assertNull(contextURL.getDerivedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+
+  @Test
+  public void reference() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$ref"));
+    assertTrue(contextURL.isReference());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+    assertFalse(contextURL.isDelta());
+  }
+
+  @Test
+  public void delta() {
+    ContextURL contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$delta"));
+    assertTrue(contextURL.isDelta());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$deletedLink"));
+    assertTrue(contextURL.isDeltaDeletedLink());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$link"));
+    assertTrue(contextURL.isDeltaLink());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+
+    contextURL = ContextURLParser.parse(URI.create("http://host/service/$metadata#Customers/$deletedEntity"));
+    assertTrue(contextURL.isDeltaDeletedEntity());
+    assertNull(contextURL.getSelectList());
+    assertNull(contextURL.getNavOrPropertyPath());
+    assertFalse(contextURL.isEntity());
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
index 548c902..462a803 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/processor/DefaultProcessor.java
@@ -26,6 +26,7 @@ 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.commons.api.serialization.ODataSerializerException;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataRequest;
 import org.apache.olingo.server.api.ODataResponse;
@@ -52,22 +53,27 @@ public class DefaultProcessor implements MetadataProcessor, ServiceDocumentProce
   public void readServiceDocument(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
       final ContentType requestedContentType) {
     ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-    InputStream responseEntity = serializer.serviceDocument(edm, request.getRawBaseUri());
-
-    response.setStatusCode(200);
-    response.setContent(responseEntity);
-    response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
 
+    try {
+      response.setContent(serializer.serviceDocument(edm, request.getRawBaseUri()));
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
+    } catch (final ODataSerializerException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    }
   }
 
   @Override
   public void readMetadata(final ODataRequest request, final ODataResponse response, final UriInfo uriInfo,
       final ContentType requestedContentType) {
     ODataSerializer serializer = odata.createSerializer(ODataFormat.fromContentType(requestedContentType));
-    InputStream responseEntity = serializer.metadataDocument(edm);
-    response.setStatusCode(200);
-    response.setContent(responseEntity);
-    response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
+    try {
+      response.setContent(serializer.metadataDocument(edm));
+      response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
+    } catch (final ODataSerializerException e) {
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+    }
   }
 
   @Override

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
index 9206b4f..4ec5197 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/serializer/ODataSerializer.java
@@ -25,24 +25,28 @@ import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
 import org.apache.olingo.commons.api.edm.Edm;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.serialization.ODataSerializerException;
 import org.apache.olingo.server.api.ODataServerError;
 
 public interface ODataSerializer {
 
   public static final String DEFAULT_CHARSET = "UTF-8";
 
-  InputStream serviceDocument(Edm edm, String serviceRoot);
+  InputStream serviceDocument(Edm edm, String serviceRoot) throws ODataSerializerException;
 
-  InputStream metadataDocument(Edm edm);
+  InputStream metadataDocument(Edm edm) throws ODataSerializerException;
 
-  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL contextURL);
+  InputStream entity(EdmEntitySet edmEntitySet, Entity entity, ContextURL contextURL)
+      throws ODataSerializerException;
 
-  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ContextURL contextURL);
+  InputStream entitySet(EdmEntitySet edmEntitySet, EntitySet entitySet, ContextURL contextURL)
+      throws ODataSerializerException;
 
   /**
    * Writes an ODataError into an InputStream.
    * @param error the main error
    * @return inputStream containing the OData formatted error
+   * @throws ODataSerializerException 
    */
-  InputStream error(ODataServerError error);
+  InputStream error(ODataServerError error) throws ODataSerializerException;
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java
deleted file mode 100644
index e3eb5e9..0000000
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/Decoder.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*******************************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- * 
- * http://www.apache.org/licenses/LICENSE-2.0
- * 
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- ******************************************************************************/
-package org.apache.olingo.server.core;
-
-import java.io.UnsupportedEncodingException;
-
-/**
- * Decodes a Java String containing a percent-encoded UTF-8 String value
- * into a Java String (in its internal UTF-16 encoding).
- * 
- */
-public class Decoder {
-
-  /**
-   * Decodes a percent-encoded UTF-8 String value into a Java String
-   * (in its internal UTF-16 encoding).
-   * @param value the encoded String
-   * @return the Java String
-   * @throws IllegalArgumentException if value contains characters not representing UTF-8 bytes
-   * or ends with an unfinished percent-encoded character
-   * @throws NumberFormatException if the two characters after a percent character
-   * are not hexadecimal digits
-   */
-  public static String decode(final String value) throws IllegalArgumentException, NumberFormatException {
-    if (value == null) {
-      return value;
-    }
-
-    // Use a tiny finite-state machine to handle decoding on byte level.
-    // There are only three states:
-    // -2: normal bytes
-    // -1: a byte representing the percent character has been read
-    // >= 0: a byte representing the first half-byte of a percent-encoded byte has been read
-    // The variable holding the state is also used to store the value of the first half-byte.
-    byte[] result = new byte[value.length()];
-    int position = 0;
-    byte encodedPart = -2;
-    for (final char c : value.toCharArray()) {
-      if (c <= Byte.MAX_VALUE) {
-        if (c == '%') {
-          if (encodedPart == -2) {
-            encodedPart = -1;
-          } else {
-            throw new IllegalArgumentException();
-          }
-        } else if (encodedPart == -1) {
-          encodedPart = (byte) c;
-        } else if (encodedPart >= 0) {
-          final int i = Integer.parseInt(String.valueOf(new char[] { (char) encodedPart, c }), 16);
-          if (i >= 0) {
-            result[position++] = (byte) i;
-          } else {
-            throw new NumberFormatException();
-          }
-          encodedPart = -2;
-        } else {
-          result[position++] = (byte) c;
-        }
-      } else {
-        throw new IllegalArgumentException();
-      }
-    }
-
-    if (encodedPart >= 0) {
-      throw new IllegalArgumentException();
-    }
-
-    try {
-      return new String(result, 0, position, "UTF-8");
-    } catch (UnsupportedEncodingException e) {
-      throw new IllegalArgumentException(e);
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java
index cb2d183..20fffe4 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataExceptionHandler.java
@@ -18,10 +18,11 @@
  */
 package org.apache.olingo.server.core;
 
-import java.io.InputStream;
 import java.util.Locale;
 
 import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.api.serialization.ODataSerializerException;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataServerError;
@@ -35,7 +36,7 @@ public class ODataExceptionHandler {
 
   public void handle(ODataResponse resp, Exception e) {
     if (resp.getStatusCode() == 0) {
-      resp.setStatusCode(500);
+      resp.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
     }
     ODataServerError error = new ODataServerError();
     if (e instanceof ODataTranslatedException) {
@@ -45,8 +46,9 @@ public class ODataExceptionHandler {
     }
 
     ODataSerializer serializer = OData.newInstance().createSerializer(requestedFormat);
-    InputStream errorStream = serializer.error(error);
-    resp.setContent(errorStream);
+    try {
+      resp.setContent(serializer.error(error));
+    } catch (final ODataSerializerException e1) {}
     // Set header
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/c75c29ce/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index bc4cbc9..d8128a8 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -23,9 +23,7 @@ import java.io.InputStream;
 import java.util.List;
 
 import org.apache.olingo.commons.api.Constants;
-import org.apache.olingo.commons.api.ODataRuntimeException;
 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.EntitySet;
 import org.apache.olingo.commons.api.data.LinkedComplexValue;
@@ -39,10 +37,12 @@ import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.serialization.ODataSerializerException;
 import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
+import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,7 +61,7 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   @Override
-  public InputStream serviceDocument(final Edm edm, final String serviceRoot) {
+  public InputStream serviceDocument(final Edm edm, final String serviceRoot) throws ODataSerializerException {
     CircleStreamBuffer buffer;
     JsonGenerator gen = null;
 
@@ -83,48 +83,49 @@ public class ODataJsonSerializer implements ODataSerializer {
 
     } catch (Exception e) {
       log.error(e.getMessage(), e);
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     } finally {
       if (gen != null) {
         try {
           gen.close();
         } catch (IOException e) {
-          throw new ODataRuntimeException(e);
+          throw new ODataSerializerException(e);
         }
       }
     }
   }
 
   @Override
-  public InputStream metadataDocument(final Edm edm) {
-    throw new ODataRuntimeException("Metadata in JSON format not supported!");
+  public InputStream metadataDocument(final Edm edm) throws ODataSerializerException {
+    throw new ODataSerializerException("Metadata in JSON format not supported!");
   }
 
   @Override
-  public InputStream error(final ODataServerError error) {
+  public InputStream error(final ODataServerError error) throws ODataSerializerException {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
       new ODataErrorSerializer().writeErrorDocument(json, error);
       json.close();
     } catch (final IOException e) {
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     }
     return buffer.getInputStream();
   }
 
   @Override
   public InputStream entitySet(final EdmEntitySet edmEntitySet, final EntitySet entitySet,
-      final ContextURL contextURL) {
-    final ContextURL entitySetContextURL = contextURL == null ?
-        ContextURL.create().entitySet(edmEntitySet).build() :
-        contextURL;
+      final ContextURL contextURL) throws ODataSerializerException {
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
       json.writeStartObject();
       if (format != ODataFormat.JSON_NO_METADATA) {
-        json.writeStringField(Constants.JSON_CONTEXT, entitySetContextURL.getURI().toASCIIString());
+        if (contextURL == null) {
+          throw new ODataSerializerException("ContextURL null!");
+        } else {
+          json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
+        }
       }
       if (entitySet.getCount() != null) {
         json.writeNumberField(Constants.JSON_COUNT, entitySet.getCount());
@@ -140,38 +141,39 @@ public class ODataJsonSerializer implements ODataSerializer {
       }
       json.close();
     } catch (final IOException e) {
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     } catch (final EdmPrimitiveTypeException e) {
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     }
     return buffer.getInputStream();
   }
 
   @Override
-  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL) {
-    final ContextURL entityContextURL = contextURL == null ?
-        ContextURL.create().entitySet(edmEntitySet).suffix(Suffix.ENTITY).build() :
-        contextURL;
+  public InputStream entity(final EdmEntitySet edmEntitySet, final Entity entity, final ContextURL contextURL)
+      throws ODataSerializerException {
+    if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
+      throw new ODataSerializerException("ContextURL null!");
+    }
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
-      writeEntity(edmEntitySet, entity, entityContextURL, json);
+      writeEntity(edmEntitySet, entity, contextURL, json);
       json.close();
     } catch (final IOException e) {
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     } catch (final EdmPrimitiveTypeException e) {
-      throw new ODataRuntimeException(e);
+      throw new ODataSerializerException(e);
     }
     return buffer.getInputStream();
   }
 
   protected void writeEntity(final EdmEntitySet entitySet, final Entity entity, final ContextURL contextURL,
-      final JsonGenerator json) throws IOException, EdmPrimitiveTypeException {
+      final JsonGenerator json) throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     final EdmEntityType entityType = entitySet.getEntityType();
     json.writeStartObject();
     if (format != ODataFormat.JSON_NO_METADATA) {
       if (contextURL != null) {
-        json.writeStringField(Constants.JSON_CONTEXT, contextURL.getURI().toASCIIString());
+        json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
       }
       if (entity.getETag() != null) {
         json.writeStringField(Constants.JSON_ETAG, entity.getETag());
@@ -194,11 +196,11 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   protected void writeProperty(final EdmProperty edmProperty, final Property property, final JsonGenerator json)
-      throws IOException, EdmPrimitiveTypeException {
+      throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     json.writeFieldName(edmProperty.getName());
     if (property == null || property.isNull()) {
       if (edmProperty.isNullable() == Boolean.FALSE) {
-        throw new ODataRuntimeException("Non-nullable property not present!");
+        throw new ODataSerializerException("Non-nullable property not present!");
       } else {
         json.writeNull();
       }
@@ -212,13 +214,13 @@ public class ODataJsonSerializer implements ODataSerializer {
       } else if (property.isComplex()) {
         writeComplexValue(edmProperty, property.asComplex(), json);
       } else {
-        throw new ODataRuntimeException("Property type not yet supported!");
+        throw new ODataSerializerException("Property type not yet supported!");
       }
     }
   }
 
   private void writeCollection(EdmProperty edmProperty, Property property, JsonGenerator json)
-          throws IOException, EdmPrimitiveTypeException {
+          throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     json.writeStartArray();
     for (Object value : property.asCollection()) {
       switch (property.getValueType()) {
@@ -226,7 +228,7 @@ public class ODataJsonSerializer implements ODataSerializer {
         writePrimitiveValue(edmProperty, value, json);
         break;
       case COLLECTION_GEOSPATIAL:
-        throw new ODataRuntimeException("Property type not yet supported!");
+        throw new ODataSerializerException("Property type not yet supported!");
       case COLLECTION_ENUM:
         json.writeString(value.toString());
         break;
@@ -237,22 +239,22 @@ public class ODataJsonSerializer implements ODataSerializer {
         writeComplexValue(edmProperty, property.asComplex(), json);
         break;
       default:
-        throw new ODataRuntimeException("Property type not yet supported!");
+        throw new ODataSerializerException("Property type not yet supported!");
       }
     }
     json.writeEndArray();
   }
 
   private void writePrimitive(EdmProperty edmProperty, Property property, JsonGenerator json)
-          throws EdmPrimitiveTypeException, IOException {
+          throws EdmPrimitiveTypeException, IOException, ODataSerializerException {
     if (property.isPrimitive()) {
       writePrimitiveValue(edmProperty, property.asPrimitive(), json);
     } else if (property.isGeospatial()) {
-      throw new ODataRuntimeException("Property type not yet supported!");
+      throw new ODataSerializerException("Property type not yet supported!");
     } else if (property.isEnum()) {
       writePrimitiveValue(edmProperty, property.asEnum(), json);
     } else {
-      throw new ODataRuntimeException("Inconsistent property type!");
+      throw new ODataSerializerException("Inconsistent property type!");
     }
   }
 
@@ -280,7 +282,7 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   private void writeComplexValue(final EdmProperty edmProperty, final List<Property> properties,
-      JsonGenerator json) throws IOException, EdmPrimitiveTypeException {
+      JsonGenerator json) throws IOException, EdmPrimitiveTypeException, ODataSerializerException {
     final EdmComplexType type = (EdmComplexType) edmProperty.getType();
     json.writeStartObject();
     for (final String propertyName : type.getPropertyNames()) {