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/10/31 15:03:37 UTC

git commit: correct context URL for server property responses

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 357e8b654 -> 3e1173812


correct context URL for server property responses

Change-Id: Ie262212ab1ec1a0b9067770ff3b13eb14f216e53

Signed-off-by: Michael Bolz <mi...@sap.com>


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

Branch: refs/heads/master
Commit: 3e117381257e3ee0aa66ae94f025f7e3eb9f084c
Parents: 357e8b6
Author: Klaus Straubinger <kl...@sap.com>
Authored: Fri Oct 31 14:11:28 2014 +0100
Committer: Michael Bolz <mi...@sap.com>
Committed: Fri Oct 31 14:19:47 2014 +0100

----------------------------------------------------------------------
 .../olingo/commons/api/data/ContextURL.java     |  30 +-----
 .../server/api/serializer/ODataSerializer.java  |   9 ++
 .../core/serializer/ODataXmlSerializerImpl.java |  17 ++-
 .../serializer/json/ODataJsonSerializer.java    |  49 ++++-----
 .../core/serializer/utils/ContextURLHelper.java |  23 +++++
 .../serializer/utils/ContextURLBuilderTest.java |  23 ++---
 .../tecsvc/processor/TechnicalProcessor.java    |  73 ++++++++-----
 .../json/ODataJsonSerializerTest.java           | 103 +++++++------------
 .../serializer/utils/ContextURLHelperTest.java  |  33 ++++++
 9 files changed, 202 insertions(+), 158 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/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 dcc45f5..af5cc4d 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
@@ -19,7 +19,6 @@
 package org.apache.olingo.commons.api.data;
 
 import java.net.URI;
-import java.util.Map;
 
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
@@ -143,38 +142,17 @@ public class ContextURL {
       return this;
     }
     
-    public Builder keySegment(String value) {
-      if (value != null) {
-        contextURL.keyPath = value;
-      }
+    public Builder keyPath(final String value) {
+      contextURL.keyPath = value;
       return this;
     }  
-    
-    public Builder keySegment(Map<String, String> values) {
-      if (values != null && !values.isEmpty()) {
-        
-        if (values.size() == 1) {
-          return keySegment(values.values().iterator().next());
-        }
-        
-        StringBuilder sb = new StringBuilder();
-        for (String key: values.keySet()) {
-          if (sb.length() > 0) {
-            sb.append(",");
-          }
-          sb.append(key).append("=").append(values.get(key));
-        }
-        contextURL.keyPath = sb.toString();
-      }
-      return this;
-    }      
 
     public Builder entitySetOrSingletonOrType(final String entitySetOrSingletonOrType) {
       contextURL.entitySetOrSingletonOrType = entitySetOrSingletonOrType;
       return this;
     }
-    
-    public Builder propertyType(final EdmType type) {
+
+    public Builder type(final EdmType type) {
       contextURL.entitySetOrSingletonOrType = type.getFullQualifiedName().toString();
       return this;
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/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 1331247..2072798 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
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.api.serializer;
 
 import java.io.InputStream;
+import java.util.List;
 
 import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntitySet;
@@ -28,6 +29,7 @@ import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.server.api.ODataServerError;
 import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 
@@ -93,4 +95,11 @@ public interface ODataSerializer {
    */
   String buildContextURLSelectList(EdmEntitySet edmEntitySet, ExpandOption expand, SelectOption select)
       throws SerializerException;
+
+  /**
+   * Builds the key-predicate part of a {@link org.apache.olingo.commons.api.data.ContextURL ContextURL}.
+   * @param keys the keys as a list of {@link UriParameter} instances
+   * @return a String with the key predicate
+   */
+  String buildContextURLKeyPredicate(List<UriParameter> keys) throws SerializerException;
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
index 8956a6d..5138669 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/ODataXmlSerializerImpl.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.server.core.serializer;
 
 import java.io.InputStream;
+import java.util.List;
 
 import javax.xml.stream.XMLOutputFactory;
 import javax.xml.stream.XMLStreamException;
@@ -35,6 +36,7 @@ import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
+import org.apache.olingo.server.api.uri.UriParameter;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectOption;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
@@ -105,15 +107,20 @@ public class ODataXmlSerializerImpl implements ODataSerializer {
   }
 
   @Override
+  public  InputStream entityProperty(EdmProperty edmProperty, Property property,
+    ODataSerializerOptions options) throws SerializerException{
+    throw new SerializerException("error serialization not implemented for XML format",
+      SerializerException.MessageKeys.NOT_IMPLEMENTED);
+  }
+
+  @Override
   public String buildContextURLSelectList(final EdmEntitySet edmEntitySet,
       final ExpandOption expand, final SelectOption select) throws SerializerException {
     return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
   }
 
   @Override
-  public 	InputStream entityProperty(EdmProperty edmProperty, Property property,
-    ODataSerializerOptions options) throws SerializerException{
-    throw new SerializerException("error serialization not implemented for XML format",
-      SerializerException.MessageKeys.NOT_IMPLEMENTED);
-	}
+  public String buildContextURLKeyPredicate(final List<UriParameter> keys) throws SerializerException {
+    return ContextURLHelper.buildKeyPredicate(keys);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/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 324c5aa..d549ff0 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
@@ -46,6 +46,7 @@ import org.apache.olingo.server.api.ServiceMetadata;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
 import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
+import org.apache.olingo.server.api.uri.UriParameter;
 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;
@@ -176,17 +177,16 @@ public class ODataJsonSerializer implements ODataSerializer {
     return buffer.getInputStream();
   }
 
-  private ContextURL checkContextURL(final ODataSerializerOptions options)
-      throws SerializerException {
-    ContextURL contextURL = options == null ? null : options.getContextURL();
-    if (format != ODataFormat.JSON_NO_METADATA && contextURL == null) {
-      throw new SerializerException("ContextURL null!",
-          SerializerException.MessageKeys.NO_CONTEXT_URL);
-    }
+  private ContextURL checkContextURL(final ODataSerializerOptions options) throws SerializerException {
     if (format == ODataFormat.JSON_NO_METADATA) {
-      contextURL = null;
+      return null;
+    } else {
+      final ContextURL contextURL = options == null ? null : options.getContextURL();
+      if (contextURL == null) {
+        throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
+      }
+      return contextURL;
     }
-    return contextURL;
   }
 
   protected void writeEntitySet(final EdmEntityType entityType, final EntitySet entitySet,
@@ -421,28 +421,18 @@ public class ODataJsonSerializer implements ODataSerializer {
   }
 
   @Override
-  public String buildContextURLSelectList(final EdmEntitySet edmEntitySet,
-      final ExpandOption expand, final SelectOption select) throws SerializerException {
-    return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
-  }
-
-  @Override
-  public InputStream entityProperty(EdmProperty edmProperty,
-      Property property, ODataSerializerOptions options)
-      throws SerializerException {
+  public InputStream entityProperty(final EdmProperty edmProperty, final Property property,
+      final ODataSerializerOptions options) throws SerializerException {
     final ContextURL contextURL = checkContextURL(options);
     CircleStreamBuffer buffer = new CircleStreamBuffer();
     try {
       JsonGenerator json = new JsonFactory().createGenerator(buffer.getOutputStream());
       json.writeStartObject();
-      if (format != ODataFormat.JSON_NO_METADATA) {
-        if (contextURL != null) {
-          json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
-        }
+      if (contextURL != null) {
+        json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
       }
       if (property.isPrimitive() && property.isNull()) {
-        throw new SerializerException("Property value can not be null",
-            SerializerException.MessageKeys.NULL_INPUT);
+        throw new SerializerException("Property value can not be null.", SerializerException.MessageKeys.NULL_INPUT);
       } else if (property.isComplex() && !property.isNull()) {
         writePropertyValues(edmProperty, property.asComplex(), null, json);
       } else if (property.isLinkedComplex() && !property.isNull()) {
@@ -459,4 +449,15 @@ public class ODataJsonSerializer implements ODataSerializer {
     }
     return buffer.getInputStream();
   }
+
+  @Override
+  public String buildContextURLSelectList(final EdmEntitySet edmEntitySet,
+      final ExpandOption expand, final SelectOption select) throws SerializerException {
+    return ContextURLHelper.buildSelectList(edmEntitySet.getEntityType(), expand, select);
+  }
+
+  @Override
+  public String buildContextURLKeyPredicate(final List<UriParameter> keys) throws SerializerException {
+    return ContextURLHelper.buildKeyPredicate(keys);
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/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 099055e..80c13de 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
@@ -28,6 +28,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 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.queryoption.ExpandItem;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
 import org.apache.olingo.server.api.uri.queryoption.SelectItem;
@@ -142,4 +143,26 @@ public final class ContextURLHelper {
     }
     return result;
   }
+
+  /**
+   * Builds a key predicate for the ContextURL.
+   * @param keys the keys as a list of {@link UriParameter} instances
+   * @return a String with the key predicate
+   */
+  public static String buildKeyPredicate(List<UriParameter> keys) throws SerializerException {
+    if (keys == null || keys.isEmpty()) {
+      return null;
+    } else if (keys.size() == 1) {
+      return Encoder.encode(keys.get(0).getText());
+    } else {
+      StringBuilder result = new StringBuilder();
+      for (final UriParameter key : keys) {
+        if (result.length() > 0) {
+          result.append(',');
+        }
+        result.append(Encoder.encode(key.getName())).append('=').append(Encoder.encode(key.getText()));
+      }
+      return result.toString();
+    }
+  }      
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
index 4ce699f..8a7c9c6 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/serializer/utils/ContextURLBuilderTest.java
@@ -25,7 +25,6 @@ import static org.mockito.Mockito.when;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.TreeMap;
 
 import org.apache.olingo.commons.api.data.ContextURL;
 import org.apache.olingo.commons.api.data.ContextURL.Suffix;
@@ -104,47 +103,45 @@ public class ContextURLBuilderTest {
     assertEquals("http://host/service/$metadata#Customers/Model.VipCustomer/$entity",
         ContextURLBuilder.create(contextURL).toASCIIString());
   }
-  
+
   @Test
-  public void buildPropertyValue() {
+  public void buildProperty() {
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn("Customers");
     ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
         .entitySet(entitySet)
-        .keySegment(String.valueOf(1))
+        .keyPath("1")
         .navOrPropertyPath("Name")
         .build();
     assertEquals("http://host/service/$metadata#Customers(1)/Name",
         ContextURLBuilder.create(contextURL).toASCIIString());
-    TreeMap<String, String> keys = new TreeMap<String, String>();
-    keys.put("one", String.valueOf(1));
-    keys.put("two", "'two'");
+
     contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
         .entitySet(entitySet)
-        .keySegment(keys)
+        .keyPath("one=1,two='two'")
         .navOrPropertyPath("Name")
         .build();
     assertEquals("http://host/service/$metadata#Customers(one=1,two='two')/Name",
         ContextURLBuilder.create(contextURL).toASCIIString());
   }  
-  
+
   @Test
   public void buildPrimitiveType() {
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn("Customers");
     ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
-        .propertyType(EdmString.getInstance())
+        .type(EdmString.getInstance())
         .build();
     assertEquals("http://host/service/$metadata#Edm.String",
         ContextURLBuilder.create(contextURL).toASCIIString());
     
     contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
-        .propertyType(EdmString.getInstance()).asCollection()
+        .type(EdmString.getInstance()).asCollection()
         .build();
     assertEquals("http://host/service/$metadata#Collection(Edm.String)",
         ContextURLBuilder.create(contextURL).toString());
   }  
-  
+
   @Test
   public void buildComplexType() throws Exception {
     EdmProvider provider = mock(EdmProvider.class);
@@ -165,7 +162,7 @@ public class ContextURLBuilderTest {
     EdmEntitySet entitySet = Mockito.mock(EdmEntitySet.class);
     Mockito.when(entitySet.getName()).thenReturn("Customers");
     ContextURL contextURL = ContextURL.with().serviceRoot(URI.create("http://host/service/"))
-        .propertyType(baseType)
+        .type(baseType)
         .build();
     assertEquals("http://host/service/$metadata#namespace.BaseTypeName",
         ContextURLBuilder.create(contextURL).toASCIIString());    

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
----------------------------------------------------------------------
diff --git a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
index 383b889..d88a02f 100644
--- a/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
+++ b/lib/server-tecsvc/src/main/java/org/apache/olingo/server/tecsvc/processor/TechnicalProcessor.java
@@ -20,16 +20,16 @@ package org.apache.olingo.server.tecsvc.processor;
 
 import java.io.ByteArrayInputStream;
 import java.io.UnsupportedEncodingException;
-import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 
 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.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
@@ -98,7 +98,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
       response.setContent(serializer.entitySet(edmEntitySet, entitySet,
           ODataSerializerOptions.with()
               .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                  getContextUrl(serializer, edmEntitySet, false, expand, select, null))
+                  getContextUrl(serializer, edmEntitySet, false, expand, select, null, null))
               .count(uriInfo.getCountOption())
               .expand(expand).select(select)
               .build()));
@@ -124,7 +124,7 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
       response.setContent(serializer.entity(edmEntitySet, entity,
           ODataSerializerOptions.with()
               .contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                  getContextUrl(serializer, edmEntitySet, true, expand, select, null))
+                  getContextUrl(serializer, edmEntitySet, true, expand, select, null, null))
               .count(uriInfo.getCountOption())
               .expand(expand).select(select)
               .build()));
@@ -209,40 +209,47 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
 
   private ContextURL getContextUrl(final ODataSerializer serializer,
       final EdmEntitySet entitySet, final boolean isSingleEntity,
-      final ExpandOption expand, final SelectOption select, final String propertyPath)
-    throws SerializerException {
+      final ExpandOption expand, final SelectOption select,
+      final List<UriParameter> keys, final String propertyPath) throws SerializerException {
     return ContextURL.with().entitySet(entitySet)
         .selectList(serializer.buildContextURLSelectList(entitySet, expand, select))
         .suffix(isSingleEntity && propertyPath == null ? Suffix.ENTITY : null)
+        .keyPath(serializer.buildContextURLKeyPredicate(keys))
         .navOrPropertyPath(propertyPath)
         .build();
   }
 
-  private Map<String, String> mapKeys(List<UriParameter> parameters)
-          throws ODataApplicationException {
-    Map<String, String> keys = new LinkedHashMap<String, String>();
-    for (UriParameter param: parameters) {
-      keys.put(param.getName(), param.getText());
-    }
-    return keys;
-  }
-
   @Override
   public void readProperty(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, SerializerException {
     validateOptions(uriInfo.asUriInfoResource());
 
     final EdmEntitySet edmEntitySet = getEdmEntitySet(uriInfo.asUriInfoResource());
-    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) uriInfo.getUriResourceParts().get(0);
+    final List<UriResource> resourceParts = uriInfo.getUriResourceParts();
+    final UriResourceEntitySet resourceEntitySet = (UriResourceEntitySet) resourceParts.get(0);
     final Entity entity = readEntityInternal(uriInfo.asUriInfoResource(), edmEntitySet);
 
     if (entity == null) {
       throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
     } else {
-      final UriResourceProperty uriProperty = (UriResourceProperty) uriInfo
-          .getUriResourceParts().get(uriInfo.getUriResourceParts().size() - 1);
-      final EdmProperty edmProperty = uriProperty.getProperty();
-      final Property property = entity.getProperty(edmProperty.getName());
+      final List<String> path = getPropertyPath(resourceParts);
+      EdmProperty edmProperty = edmEntitySet.getEntityType().getStructuralProperty(path.get(0));
+      Property property = entity.getProperty(path.get(0));
+      for (final String name : path.subList(1, path.size())) {
+        if (property != null && (property.isLinkedComplex() || property.isComplex())) {
+          edmProperty = ((EdmComplexType) edmProperty.getType()).getStructuralProperty(name);
+          final List<Property> complex = property.isLinkedComplex() ?
+              property.asLinkedComplex().getValue() :
+              property.asComplex();
+          property = null;
+          for (final Property innerProperty : complex) {
+            if (innerProperty.getName().equals(name)) {
+              property = innerProperty;
+              break;
+            }
+          }
+        }
+      }
       if (property == null) {
         throw new ODataApplicationException("Nothing found.", HttpStatusCode.NOT_FOUND.getStatusCode(), Locale.ROOT);
       } else {
@@ -252,11 +259,10 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
           final ODataFormat format = ODataFormat.fromContentType(contentType);
           ODataSerializer serializer = odata.createSerializer(format);
           response.setContent(serializer.entityProperty(edmProperty, property,
-                  ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
-                          ContextURL.with().entitySet(edmEntitySet)
-                                  .keySegment(mapKeys(resourceEntitySet.getKeyPredicates()))
-                                  .navOrPropertyPath(edmProperty.getName())
-                                  .build()).build()));
+              ODataSerializerOptions.with().contextURL(format == ODataFormat.JSON_NO_METADATA ? null :
+                  getContextUrl(serializer, edmEntitySet, true, null, null,
+                      resourceEntitySet.getKeyPredicates(), buildPropertyPath(path)))
+                  .build()));
           response.setStatusCode(HttpStatusCode.OK.getStatusCode());
           response.setHeader(HttpHeader.CONTENT_TYPE, contentType.toContentTypeString());
         }
@@ -264,6 +270,23 @@ public class TechnicalProcessor implements EntitySetProcessor, EntityProcessor,
     }
   }
 
+  private List<String> getPropertyPath(final List<UriResource> path) {
+    List<String> result = new LinkedList<String>();
+    int index = path.size();
+    while (path.get(--index) instanceof UriResourceProperty) {
+      result.add(0, ((UriResourceProperty) path.get(index)).getProperty().getName());
+    }
+    return result;
+  }
+
+  private String buildPropertyPath(final List<String> path) {
+    StringBuilder result = new StringBuilder();
+    for (final String segment : path) {
+      result.append(result.length() == 0 ? "" : '/').append(segment);
+    }
+    return result.toString();
+  }
+
   @Override
   public void readPropertyValue(final ODataRequest request, ODataResponse response, final UriInfo uriInfo,
       final ContentType contentType) throws ODataApplicationException, SerializerException {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
----------------------------------------------------------------------
diff --git a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
index 562787d..fc65245 100644
--- a/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
+++ b/lib/server-test/src/test/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializerTest.java
@@ -28,9 +28,9 @@ 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.Property;
 import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.edm.Edm;
-import org.apache.olingo.commons.api.edm.EdmElement;
 import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmProperty;
@@ -40,8 +40,8 @@ import org.apache.olingo.commons.core.data.PropertyImpl;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
 import org.apache.olingo.server.api.serializer.ODataSerializer;
-import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.serializer.ODataSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.ExpandItem;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@@ -52,7 +52,6 @@ import org.apache.olingo.server.tecsvc.data.DataProvider;
 import org.apache.olingo.server.tecsvc.provider.EdmTechProvider;
 import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.mockito.Mockito;
 
@@ -575,96 +574,70 @@ public class ODataJsonSerializerTest {
   }
 
   @Test
-  public void individualPrimitiveProperty() throws Exception {
+  public void primitiveProperty() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
-    final EntitySet entitySet = data.readAll(edmEntitySet);
-
-    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
-    Entity entity = entitySet.getEntities().get(0);
-
-    InputStream result = serializer
-        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"),
+    final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
+    final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
+    final String resultString = IOUtils.toString(serializer
+        .entityProperty(edmProperty, property,
             ODataSerializerOptions.with()
-                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String")
+                .contextURL(ContextURL.with()
+                    .entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
                     .build())
-                .build());
-    final String resultString = IOUtils.toString(result);
+                .build()));
     Assert.assertEquals("{"
-            + "\"@odata.context\":\"$metadata#Edm.String\","
+            + "\"@odata.context\":\"$metadata#ESAllPrim(32767)/PropertyString\","
             + "\"value\":\"First Resource - positive values\"}",
         resultString);
   }
 
   @Test(expected = SerializerException.class)
-  public void individualPrimitivePropertyNull() throws Exception {
-    PropertyImpl property = new PropertyImpl("Edm.String", "PropertyString", ValueType.PRIMITIVE, null);
+  public void primitivePropertyNull() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
-    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
-    serializer.entityProperty((EdmProperty) edmElement, property,
-            ODataSerializerOptions.with()
-                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Edm.String")
-                    .build())
-                .build());
+    final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyString");
+    final Property property = new PropertyImpl("Edm.String", edmProperty.getName(), ValueType.PRIMITIVE, null);
+    serializer.entityProperty(edmProperty, property,
+        ODataSerializerOptions.with()
+            .contextURL(ContextURL.with()
+                .entitySet(edmEntitySet).keyPath("4242").navOrPropertyPath(edmProperty.getName())
+                .build())
+            .build());
   }
 
   @Test
-  public void individualPrimitivePropertyArray() throws Exception {
+  public void primitiveCollectionProperty() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESCollAllPrim");
-    final EntitySet entitySet = data.readAll(edmEntitySet);
+    final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("CollPropertyString");
+    final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty(edmProperty.getName());
 
-    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("CollPropertyString");
-    Entity entity = entitySet.getEntities().get(0);
-
-    InputStream result = serializer
-        .entityProperty((EdmProperty) edmElement, entity.getProperty("CollPropertyString"),
+    final String resultString = IOUtils.toString(serializer
+        .entityProperty(edmProperty, property,
             ODataSerializerOptions.with()
-                .contextURL(ContextURL.with().entitySetOrSingletonOrType("Collection(Edm.String)")
+                .contextURL(ContextURL.with()
+                    .entitySet(edmEntitySet).keyPath("1").navOrPropertyPath(edmProperty.getName())
                     .build())
-                .build());
-    final String resultString = IOUtils.toString(result);
+                .build()));
     Assert.assertEquals("{"
-            + "\"@odata.context\":\"$metadata#Collection%28Edm.String%29\","
+            + "\"@odata.context\":\"$metadata#ESCollAllPrim(1)/CollPropertyString\","
             + "\"value\":[\"Employee1@company.example\",\"Employee2@company.example\",\"Employee3@company.example\"]}",
         resultString);
   }
 
   @Test
-  @Ignore("Serialization of value of primitive property is not done by json serializer")
-  public void individualPrimitivePropertyValue() throws Exception {
-    final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESAllPrim");
-    final EntitySet entitySet = data.readAll(edmEntitySet);
-
-    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyString");
-    Entity entity = entitySet.getEntities().get(0);
-
-    InputStream result = serializer
-        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyString"),
-            ODataSerializerOptions.with()
-                .contextURL(ContextURL.with().entitySetOrSingletonOrType("ESAllPrim(0)")
-                    .navOrPropertyPath("PropertyString")
-                    .build())
-                .build());
-    final String resultString = IOUtils.toString(result);
-    Assert.assertEquals("\"First Resource - positive values\"", resultString);
-  }
-
-  @Test
-  public void individualComplexProperty() throws Exception {
+  public void complexProperty() throws Exception {
     final EdmEntitySet edmEntitySet = entityContainer.getEntitySet("ESMixPrimCollComp");
-    final EntitySet entitySet = data.readAll(edmEntitySet);
-
-    EdmElement edmElement = edmEntitySet.getEntityType().getProperty("PropertyComp");
-    Entity entity = entitySet.getEntities().get(0);
+    final EdmProperty edmProperty = (EdmProperty) edmEntitySet.getEntityType().getProperty("PropertyComp");
+    final Property property = data.readAll(edmEntitySet).getEntities().get(0).getProperty("PropertyComp");
 
-    InputStream result = serializer
-        .entityProperty((EdmProperty) edmElement, entity.getProperty("PropertyComp"),
+    final String resultString = IOUtils.toString(serializer
+        .entityProperty(edmProperty, property,
             ODataSerializerOptions.with()
-                .contextURL(ContextURL.with().entitySetOrSingletonOrType("ESMixPrimCollComp.PropertyComp")
+                .contextURL(ContextURL.with()
+                    .entitySet(edmEntitySet).keyPath("32767").navOrPropertyPath(edmProperty.getName())
                     .build())
-                .build());
-    final String resultString = IOUtils.toString(result);
+                .build()));
     Assert.assertEquals("{"
-            + "\"@odata.context\":\"$metadata#ESMixPrimCollComp.PropertyComp\","
+            + "\"@odata.context\":\"$metadata#ESMixPrimCollComp(32767)/PropertyComp\","
             + "\"PropertyInt16\":111,\"PropertyString\":\"TEST A\"}",
         resultString);
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3e117381/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 a880c60..5397856 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
@@ -27,9 +27,11 @@ import org.apache.olingo.commons.api.data.ContextURL;
 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.EdmProperty;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.server.api.OData;
 import org.apache.olingo.server.api.edmx.EdmxReference;
+import org.apache.olingo.server.api.uri.UriParameter;
 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;
@@ -179,4 +181,35 @@ public class ContextURLHelperTest {
     assertEquals("$metadata#ESTwoPrim(NavPropertyETAllPrimOne(NavPropertyETTwoPrimOne(*)))",
         ContextURLBuilder.create(contextURL).toASCIIString());
   }
+
+  @Test
+  public void buildSingleKey() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoPrim");
+    final EdmProperty edmProperty = entitySet.getEntityType().getStructuralProperty("PropertyInt16");
+    UriParameter key = Mockito.mock(UriParameter.class);
+    Mockito.when(key.getName()).thenReturn(edmProperty.getName());
+    Mockito.when(key.getText()).thenReturn("42");
+    final ContextURL contextURL = ContextURL.with().entitySet(entitySet)
+        .keyPath(ContextURLHelper.buildKeyPredicate(Arrays.asList(key)))
+        .navOrPropertyPath(edmProperty.getName()).build();
+    assertEquals("$metadata#ESTwoPrim(42)/PropertyInt16",
+        ContextURLBuilder.create(contextURL).toASCIIString());
+  }
+
+  @Test
+  public void buildCompoundKey() throws Exception {
+    final EdmEntitySet entitySet = entityContainer.getEntitySet("ESTwoKeyNav");
+    final EdmProperty edmProperty = entitySet.getEntityType().getStructuralProperty("PropertyInt16");
+    UriParameter key1 = Mockito.mock(UriParameter.class);
+    Mockito.when(key1.getName()).thenReturn(edmProperty.getName());
+    Mockito.when(key1.getText()).thenReturn("1");
+    UriParameter key2 = Mockito.mock(UriParameter.class);
+    Mockito.when(key2.getName()).thenReturn("PropertyString");
+    Mockito.when(key2.getText()).thenReturn("'2'");
+    final ContextURL contextURL = ContextURL.with().entitySet(entitySet)
+        .keyPath(ContextURLHelper.buildKeyPredicate(Arrays.asList(key1, key2)))
+        .navOrPropertyPath(edmProperty.getName()).build();
+    assertEquals("$metadata#ESTwoKeyNav(PropertyInt16=1,PropertyString='2')/PropertyInt16",
+        ContextURLBuilder.create(contextURL).toASCIIString());
+  }
 }