Merge branch 'olingojava8' of https://git-wip-us.apache.org/repos/asf/olingo-odata4
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ApplyOption.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ApplyOption.java
index e5b10b5..90f89e4 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ApplyOption.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/uri/queryoption/ApplyOption.java
@@ -20,6 +20,8 @@
 
 import java.util.List;
 
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
+
 /**
  * Represents the system query option $apply, defined in the data aggregation extension.
  */
@@ -29,4 +31,9 @@
    * @return a list of transformations
    */
   List<ApplyItem> getApplyItems();
+
+  /**
+   * @return the structured type associated with this apply option
+   */
+  EdmStructuredType getEdmStructuredType();
 }
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
index 96be8a4..9b053f1 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLHierarchyVisitor.java
@@ -46,6 +46,7 @@
 import org.apache.olingo.server.api.uri.UriResourceRoot;
 import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.api.uri.UriResourceValue;
+import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@@ -219,6 +220,11 @@
         break;
       }
     }
+    
+    if (info.getApplyOption() != null) {
+        //per the docs, apply is first
+        visit(info.getApplyOption());
+    }
 
     // http://docs.oasis-open.org/odata/odata/v4.0/os/part1-protocol/odata-v4.0-os-part1-protocol.html#_Toc372793682
     if (info.getSearchOption() != null) {
@@ -265,6 +271,10 @@
       visit(info.getDeltaTokenOption());
     }
   }
+  
+  @Override
+  public void visit(ApplyOption option) {
+  }
 
   @Override
   public void visit(ExpandOption option) {
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
index 5fda0e4..9fa2802 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/RequestURLVisitor.java
@@ -42,6 +42,7 @@
 import org.apache.olingo.server.api.uri.UriResourceRoot;
 import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.api.uri.UriResourceValue;
+import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
 import org.apache.olingo.server.api.uri.queryoption.CountOption;
 import org.apache.olingo.server.api.uri.queryoption.DeltaTokenOption;
 import org.apache.olingo.server.api.uri.queryoption.ExpandOption;
@@ -127,4 +128,6 @@
   void visit(UriResourceComplexProperty info);
 
   void visit(UriResourcePrimitiveProperty info);
+
+  void visit(ApplyOption option);
 }
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
index 7f06e95..bb311d3 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceDispatcher.java
@@ -51,6 +51,7 @@
 import org.apache.olingo.server.api.uri.UriResourceRef;
 import org.apache.olingo.server.api.uri.UriResourceSingleton;
 import org.apache.olingo.server.api.uri.UriResourceValue;
+import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
 import org.apache.olingo.server.api.uri.queryoption.FormatOption;
 import org.apache.olingo.server.core.requests.ActionRequest;
 import org.apache.olingo.server.core.requests.BatchRequest;
@@ -272,6 +273,11 @@
     this.request = dataRequest;
   }
   
+  @Override
+  public void visit(ApplyOption option) {
+    ((DataRequest)this.request).setApply(option);
+  }
+  
   private void executeIdOption(String query, ODataRequest odRequest,
       ODataResponse odResponse) throws ODataLibraryException,
       ODataApplicationException {
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
index 77e1cfe..836334b 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceHandler.java
@@ -279,7 +279,7 @@
   void rollback(String txnId) throws ODataLibraryException, ODataApplicationException;;
 
   /**
-   * This is not complete, more URL parsing changes required. Cross join between two entities.
+   * Cross join between two entities.
    * @param dataRequest
    * @param entitySetNames
    * @param response
@@ -311,4 +311,14 @@
    * @param response
    */
   void processError(ODataServerError error, ErrorResponse response);
+
+  /**
+   * Apply request
+   * 
+   * @param dataRequest
+   * @param response
+   * @throws ODataLibraryException
+   * @throws ODataApplicationException
+   */
+  void apply(DataRequest dataRequest, ODataResponse response) throws ODataLibraryException, ODataApplicationException;
 }
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
index de5843c..bd4a55e 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/legacy/ProcessorServiceHandler.java
@@ -439,6 +439,12 @@
     throw new ODataHandlerException("not implemented",
         ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
   }
+  
+  @Override
+  public void apply(DataRequest dataRequest, ODataResponse response)
+      throws ODataLibraryException, ODataApplicationException {
+    throw new ODataHandlerException("not implemented", ODataHandlerException.MessageKeys.FUNCTIONALITY_NOT_IMPLEMENTED);
+  }
 
   @Override
   public boolean supportsDataIsolation() {
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
index 5f39f9b..4572c3e 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/BatchRequest.java
@@ -80,7 +80,7 @@
         try {
           txnId = handler.startTransaction();
           partResponse = processChangeSet(part, handler);
-          if (partResponse.getResponses().get(0).getStatusCode() > 400) {
+          if (partResponse.getResponses().get(0).getStatusCode() >= 400) {
             handler.rollback(txnId);
           } else {
             handler.commit(txnId);
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index 11a092f..69603df 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -71,6 +71,7 @@
 import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
 import org.apache.olingo.server.api.uri.UriResourceProperty;
 import org.apache.olingo.server.api.uri.UriResourceSingleton;
+import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
 import org.apache.olingo.server.core.ContentNegotiator;
 import org.apache.olingo.server.core.ContentNegotiatorException;
 import org.apache.olingo.server.core.ODataHandlerException;
@@ -277,10 +278,20 @@
     public boolean assertHttpMethod(ODataResponse response) throws ODataHandlerException {
       // the create/update/delete to navigation property is done through references
       // see # 11.4.6
-      if (!getNavigations().isEmpty() && !isGET()) {
-        return methodNotAllowed(response, httpMethod(), 
-            "create/update/delete to navigation property is done through references", 
-            allowedMethods());
+      if (!getNavigations().isEmpty()) {
+        if (isPOST()) {
+          UriResourceNavigation last = getNavigations().getLast();
+          if (!(getEntitySet().getRelatedBindingTarget(last.getProperty().getName()) 
+              instanceof EdmEntitySet)) {
+            return methodNotAllowed(response, httpMethod(), 
+                "navigation updates must be to an entity contained in an entity set", 
+                allowedMethods());
+          }
+        } else if (!isGET()) {
+          return methodNotAllowed(response, httpMethod(), 
+              "update/delete to navigation property is done through references", 
+              allowedMethods());
+        }
       }
       
       if ((isGET() || isDELETE()) && getReturnRepresentation() != ReturnRepresentation.NONE) {
@@ -315,13 +326,14 @@
     public void execute(ServiceHandler handler, ODataResponse response)
         throws ODataLibraryException, ODataApplicationException {
 
+      ContextURL contextURL = getContextURL(odata);
       EntityResponse entityResponse = EntityResponse.getInstance(DataRequest.this,
-          getContextURL(odata), false, response);
+          contextURL, false, response);
 
       if (isGET()) {
         if (isCollection()) {
           handler.read(DataRequest.this,
-              EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), false, response));
+              EntitySetResponse.getInstance(DataRequest.this, contextURL, false, response));
         } else {
           handler.read(DataRequest.this,entityResponse);
         }
@@ -338,24 +350,37 @@
         } else if (ifNoneMatch) {
           // 11.4.4
           entityResponse = EntityResponse.getInstance(DataRequest.this,
-              getContextURL(odata), false, response, getReturnRepresentation());
+              contextURL, false, response, getReturnRepresentation());
           handler.createEntity(DataRequest.this, getEntityFromClient(), entityResponse);
         } else {
           handler.upsertEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
               entityResponse);
         }
       } else if (isPOST()) {
-        entityResponse = EntityResponse.getInstance(DataRequest.this,
-            getContextURL(odata), false, response, getReturnRepresentation());
-        handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
+        if (!getNavigations().isEmpty()) {
+          entityResponse = EntityResponse.getInstance(DataRequest.this,
+              contextURL, false, response, getReturnRepresentation());
+          UriResourceNavigation last = getNavigations().getLast();
+          EdmEntityType navigationType = last.getProperty().getType();
+          Entity entity = getEntityFromClient(navigationType);
+          handler.createEntity(DataRequest.this, entity,entityResponse);
+        } else {
+          entityResponse = EntityResponse.getInstance(DataRequest.this,
+              contextURL, false, response, getReturnRepresentation());
+          handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
+        }
       } else if (isDELETE()) {
         handler.deleteEntity(DataRequest.this, getETag(), entityResponse);
       }
     }
 
     private Entity getEntityFromClient() throws DeserializerException {
+      return getEntityFromClient(getEntitySet().getEntityType());
+    }
+    
+    private Entity getEntityFromClient(EdmEntityType entityType) throws DeserializerException {
       ODataDeserializer deserializer = odata.createDeserializer(getRequestContentType(), getServiceMetaData());
-      return deserializer.entity(getODataRequest().getBody(), getEntitySet().getEntityType()).getEntity();
+      return deserializer.entity(getODataRequest().getBody(), entityType).getEntity();
     }
 
     @Override
@@ -763,7 +788,39 @@
       return builder.build();
     }
   }
+  
+  class ApplyRequest implements RequestType {
 
+    @Override
+    public boolean assertHttpMethod(ODataResponse response)
+        throws ODataHandlerException {
+      return ServiceRequest.assertHttpMethod(httpMethod(), allowedMethods(), response);
+    }
+    
+    @Override
+    public HttpMethod[] allowedMethods() {
+      return new HttpMethod[] {HttpMethod.GET};
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
+          getODataRequest(), getCustomContentTypeSupport(), RepresentationType.COLLECTION_COMPLEX);
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataLibraryException, ODataApplicationException {
+      handler.apply(DataRequest.this, response);
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      ContextURL.Builder builder = ContextURL.with().asCollection();
+      return builder.build();
+    }
+  }
+  
   private org.apache.olingo.commons.api.data.Property getPropertyValueFromClient(
       EdmProperty edmProperty) throws DeserializerException {
     ODataDeserializer deserializer = odata.createDeserializer(getRequestContentType(), getServiceMetaData());
@@ -930,4 +987,8 @@
     }
     return sb.toString();
   }
+
+  public void setApply(ApplyOption apply) {
+    this.type = new ApplyRequest();
+  }
 }
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
index 562eac0..cde9b74 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinDataModel.java
@@ -493,7 +493,7 @@
         map = new HashMap<String, Object>();
         this.peopleLinks.put((String) parentEntity.getProperty(key).getValue(), map);
       }
-      map.put("Photo", childEntity.getProperty(key).getValue());
+      map.put("Photo", ((Long)childEntity.getProperty("Id").getValue()).intValue());
       setLink(parentEntity, navigation, childEntity);
     } else if (type.getName().equals("Trip") && navigation.equals("PlanItems")) {
       Map<String, Object> map = this.tripLinks.get(parentEntity.getProperty(key).getValue());
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
index 4a92198..f594a64 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
@@ -37,6 +37,7 @@
 import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.edm.EdmProperty;
 import org.apache.olingo.commons.api.edm.EdmSingleton;
+import org.apache.olingo.commons.api.ex.ODataNotSupportedException;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpMethod;
 import org.apache.olingo.server.api.OData;
@@ -238,7 +239,12 @@
   public void createEntity(DataRequest request, Entity entity, EntityResponse response)
       throws ODataLibraryException, ODataApplicationException {
     EdmEntitySet edmEntitySet = request.getEntitySet();
-
+    
+    if (!request.getNavigations().isEmpty()) {
+      UriResourceNavigation lastNavigation = request.getNavigations().getLast();
+      edmEntitySet = (EdmEntitySet)edmEntitySet.getRelatedBindingTarget(lastNavigation.getProperty().getName());
+    }
+    
     Entity created = this.dataModel.createEntity(edmEntitySet, entity, request.getODataRequest().getRawBaseUri());
 
     try {
@@ -271,6 +277,25 @@
     } catch (URISyntaxException e) {
       throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
     }
+    
+    if (!request.getNavigations().isEmpty()) {
+      UriResourceNavigation lastNavigation = request.getNavigations().getLast();
+      
+      String parentRequest = request.getODataRequest().getRawRequestUri();
+      parentRequest = parentRequest.substring(0, parentRequest.lastIndexOf('/'));
+      
+      DataRequest bindingRequest;
+      try {
+        bindingRequest = request.parseLink(new URI(parentRequest));
+      } catch (URISyntaxException e) {
+        throw new ODataApplicationException(e.getMessage(), 500, Locale.getDefault());
+      }
+
+      Entity reference = this.dataModel.getEntity(bindingRequest.getEntitySet().getName(),
+          bindingRequest.getKeyPredicates());
+
+      this.dataModel.addNavigationLink(lastNavigation.getProperty().getName(), reference, created);
+    }
 
     response.writeCreatedEntity(edmEntitySet, created);
   }
@@ -539,7 +564,13 @@
 
   @Override
   public void crossJoin(DataRequest dataRequest, List<String> entitySetNames, ODataResponse response) {
-    response.setStatusCode(200);
+    response.setStatusCode(501);
+  }
+  
+  @Override
+  public void apply(DataRequest dataRequest, ODataResponse response)
+      throws ODataLibraryException, ODataApplicationException {
+    response.setStatusCode(501);
   }
 
   @Override
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index fa32eef..5d2a13d 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -552,6 +552,46 @@
     assertTrue(node.get("value").isArray());
     assertEquals("scottketchum", ((ArrayNode)node.get("value")).get(1).get("UserName").asText());
   }
+  
+  @Ignore("4.01 style binding not supported")
+  @Test
+  public void testCreateEntityWithLinkToRelatedEntitiesIds() throws Exception {
+    String payload = "{\n" +
+        "         \"UserName\":\"olingo\",\n" +
+        "         \"FirstName\":\"Olingo\",\n" +
+        "         \"LastName\":\"Apache\",\n" +
+        "         \"Emails\":[\n" +
+        "            \"olingo@apache.org\"\n" +
+        "         ],\n" +
+        "         \"AddressInfo\":[\n" +
+        "            {\n" +
+        "               \"Address\":\"100 apache Ln.\",\n" +
+        "               \"City\":{\n" +
+        "                  \"CountryRegion\":\"United States\",\n" +
+        "                  \"Name\":\"Boise\",\n" +
+        "                  \"Region\":\"ID\"\n" +
+        "               }\n" +
+        "            }\n" +
+        "         ],\n" +
+        "         \"Gender\":\"0\",\n" +
+        "         \"Concurrency\":635585295719432047,\n" +
+        "\"Friends\":[" +
+        "{\"@id\": \"People('russellwhyte')\"},\n" + 
+        "{\"@id\": \"People('scottketchum')\"}\n" +
+        "]"+
+        "}";
+    HttpPost postRequest = new HttpPost(baseURL + "/People");
+    postRequest.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));
+    postRequest.setHeader("Prefer", "return=minimal");
+    HttpResponse response = httpSend(postRequest, 204);
+    EntityUtils.consumeQuietly(response.getEntity());
+    
+    response = httpGET(baseURL+"/People('olingo')/Friends", 200);
+    JsonNode node = getJSONNode(response);
+    assertEquals(baseURL+"/$metadata#People", node.get("@odata.context").asText());
+    assertTrue(node.get("value").isArray());
+    assertEquals("scottketchum", ((ArrayNode)node.get("value")).get(1).get("UserName").asText());
+  }
 
   @Test
   public void testUpdatePrimitiveProperty() throws Exception {
@@ -779,6 +819,80 @@
     node = getJSONNode(response);
     assertNull("/People('russellwhyte')", ((ArrayNode) node.get("value")).get(2));
   }
+  
+  @Test
+  public void testAddEntityToNavigationFailsNotEntitySet() throws Exception {
+    // adding to an entity that is not part of an entity set
+    // goes against a few assumptions in downstream code, so 
+    // not handling for now
+    String msg = "{\n" +
+        "\"TripId\": 1010,\n" +
+        "\"Description\": \"The trip of a lifetime.\",\n" +
+        "\"Name\": \"Grand Prize\",\n" +
+        "\"Budget\": 100000\n" +
+        "}";
+    String editUrl = baseURL + "/People('vincentcalabrese')/Trips";
+    HttpPost postRequest = new HttpPost(editUrl);
+    postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+    postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+    HttpResponse response = httpSend(postRequest, 405);
+    EntityUtils.consumeQuietly(response.getEntity());
+  }
+  
+  @Test
+  public void testAddEntityToNavigation() throws Exception {
+    String msg = "{\n" +
+        "\"Id\": 1010,\n" +
+        "\"Name\": \"Grand Prize\"\n" +
+        "}";
+    String editUrl = baseURL + "/People('vincentcalabrese')/Photo";
+    HttpPost postRequest = new HttpPost(editUrl);
+    postRequest.setEntity(new StringEntity(msg, ContentType.APPLICATION_JSON));
+    postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+    HttpResponse response = httpSend(postRequest, 201);
+    EntityUtils.consumeQuietly(response.getEntity());
+    
+    response = httpGET(baseURL+"/People('vincentcalabrese')/Photo", 200);
+    JsonNode node = getJSONNode(response);
+    assertEquals(baseURL+"/$metadata#Photos/$entity", node.get("@odata.context").asText());
+    assertEquals("Grand Prize", node.get("Name").asText());
+  }
+  
+  @Test
+  public void testAddEntityToNavigationSelf() throws Exception {
+    String payload = "{\n" +
+        "         \"UserName\":\"olingo\",\n" +
+        "         \"FirstName\":\"Olingo\",\n" +
+        "         \"LastName\":\"Apache\",\n" +
+        "         \"Emails\":[\n" +
+        "            \"olingo@apache.org\"\n" +
+        "         ],\n" +
+        "         \"AddressInfo\":[\n" +
+        "            {\n" +
+        "               \"Address\":\"100 apache Ln.\",\n" +
+        "               \"City\":{\n" +
+        "                  \"CountryRegion\":\"United States\",\n" +
+        "                  \"Name\":\"Boise\",\n" +
+        "                  \"Region\":\"ID\"\n" +
+        "               }\n" +
+        "            }\n" +
+        "         ],\n" +
+        "         \"Gender\":\"0\",\n" +
+        "         \"Concurrency\":635585295719432047\n" +
+        "}";
+    String editUrl = baseURL + "/People('vincentcalabrese')/Friends";
+    HttpPost postRequest = new HttpPost(editUrl);
+    postRequest.setEntity(new StringEntity(payload, ContentType.APPLICATION_JSON));
+    postRequest.addHeader("Content-Type", "application/json;odata.metadata=minimal");
+    HttpResponse response = httpSend(postRequest, 201);
+    EntityUtils.consumeQuietly(response.getEntity());
+    
+    response = httpGET(baseURL+"/People('vincentcalabrese')/Friends", 200);
+    JsonNode node = getJSONNode(response);
+    assertEquals(baseURL+"/$metadata#People", node.get("@odata.context").asText());
+    assertTrue(node.get("value").isArray());
+    assertEquals("olingo", ((ArrayNode)node.get("value")).get(2).get("UserName").asText());
+  }
 
   @Test
   public void testDeleteReference() throws Exception {
@@ -798,7 +912,7 @@
   public void crossJoin() throws Exception {
     String editUrl = baseURL + "/$crossjoin(People,Airlines)?$filter="
         + "People/UserName%20eq%20Airlines/AirlineCode";
-    HttpResponse response = httpGET(editUrl, 200);
+    HttpResponse response = httpGET(editUrl, 501);
     EntityUtils.consumeQuietly(response.getEntity());
   }
   
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
index bbd94e5..7a632b1 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataHttpHandlerImpl.java
@@ -267,11 +267,13 @@
   static void fillUriInformation(final ODataRequest odRequest, 
 		  final HttpServletRequest httpRequest, final int split) {
     String rawRequestUri = httpRequest.getRequestURL().toString();
-
+    
+    String rawServiceResolutionUri = null;
     String rawODataPath;
     //Application need to set the request mapping attribute if the request is coming from a spring based application
     if(httpRequest.getAttribute(REQUESTMAPPING)!=null){
       String requestMapping = httpRequest.getAttribute(REQUESTMAPPING).toString();
+      rawServiceResolutionUri = requestMapping;
       int beginIndex = rawRequestUri.indexOf(requestMapping) + requestMapping.length();
       rawODataPath = rawRequestUri.substring(beginIndex);
     }else if(!"".equals(httpRequest.getServletPath())) {
@@ -286,7 +288,6 @@
       rawODataPath = httpRequest.getRequestURI();
     }
 
-    String rawServiceResolutionUri = null;
     if (split > 0) {
       rawServiceResolutionUri = rawODataPath;
       for (int i = 0; i < split; i++) {
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
index 66beb49..27f64fc 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/ApplyParser.java
@@ -135,6 +135,7 @@
   private ApplyOption parseApply(EdmStructuredType referencedType)
       throws UriParserException, UriValidationException {
     ApplyOptionImpl option = new ApplyOptionImpl();
+    option.setEdmStructuredType(referencedType);
     do {
       option.add(parseTrafo(referencedType));
     } while (tokenizer.next(TokenKind.SLASH));
@@ -253,11 +254,18 @@
       }
       final String alias = parseAsAlias(referencedType, true);
       aggregateExpression.setAlias(alias);
+      DynamicProperty dynamicProperty = createDynamicProperty(alias,
+          // Determine the type for standard methods; there is no way to do this for custom methods.
+          getTypeForAggregateMethod(aggregateExpression.getStandardMethod(),
+              ExpressionParser.getType(expression)));
+      if (aggregateExpression.getStandardMethod() == StandardMethod.SUM
+          || aggregateExpression.getStandardMethod() == StandardMethod.AVERAGE) {
+        //by default a property with no precision/scale defaults to a 0 scale
+        //this does not work for sum/average in general
+        dynamicProperty.setScale(Integer.MAX_VALUE);
+      }
       ((DynamicStructuredType) referencedType).addProperty(
-          createDynamicProperty(alias,
-              // Determine the type for standard methods; there is no way to do this for custom methods.
-              getTypeForAggregateMethod(aggregateExpression.getStandardMethod(),
-                  ExpressionParser.getType(expression))));
+          dynamicProperty);
       parseAggregateFrom(aggregateExpression, referencedType);
     }
 
@@ -319,7 +327,7 @@
     }
   }
 
-  private EdmProperty createDynamicProperty(final String name, final EdmType type) {
+  private DynamicProperty createDynamicProperty(final String name, final EdmType type) {
     return name == null ? null : new DynamicProperty(name, type);
   }
 
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
index 470b9f8..3c78152 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/parser/Parser.java
@@ -481,6 +481,7 @@
       for (final ApplyItem item : option.getApplyItems()) {
         ((ApplyOptionImpl) applyOption).add(item);
       }
+      ((ApplyOptionImpl) applyOption).setEdmStructuredType(option.getEdmStructuredType());
     }
   }
 
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/ApplyOptionImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/ApplyOptionImpl.java
index 066352d..8aa83bf 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/ApplyOptionImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/ApplyOptionImpl.java
@@ -22,6 +22,7 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.apache.olingo.commons.api.edm.EdmStructuredType;
 import org.apache.olingo.server.api.uri.queryoption.ApplyItem;
 import org.apache.olingo.server.api.uri.queryoption.ApplyOption;
 import org.apache.olingo.server.api.uri.queryoption.SystemQueryOptionKind;
@@ -29,6 +30,7 @@
 public class ApplyOptionImpl extends SystemQueryOptionImpl implements ApplyOption {
 
   private List<ApplyItem> transformations = new ArrayList<ApplyItem>();
+  private EdmStructuredType edmStructuredType;
 
   public ApplyOptionImpl() {
     setKind(SystemQueryOptionKind.APPLY);
@@ -43,4 +45,13 @@
     transformations.add(transformation);
     return this;
   }
+
+  public void setEdmStructuredType(EdmStructuredType referencedType) {
+    this.edmStructuredType = referencedType;
+  }
+  
+  @Override
+  public EdmStructuredType getEdmStructuredType() {
+    return edmStructuredType;
+  }
 }
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/DynamicProperty.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/DynamicProperty.java
index 2cfe063..7cfde33 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/DynamicProperty.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/uri/queryoption/apply/DynamicProperty.java
@@ -34,6 +34,8 @@
 
   private final String name;
   private final EdmType propertyType;
+  private Integer precision;
+  private Integer scale;
 
   /** Creates a dynamic property with a mandatory name and an optional type. */
   public DynamicProperty(final String name, final EdmType type) {
@@ -78,12 +80,12 @@
 
   @Override
   public Integer getPrecision() {
-    return null;
+    return precision;
   }
 
   @Override
   public Integer getScale() {
-    return null;
+    return scale;
   }
 
   @Override
@@ -120,4 +122,14 @@
   public EdmType getTypeWithAnnotations() {
     return propertyType;
   }
+  
+  public DynamicProperty setPrecision(Integer precision) {
+    this.precision = precision;
+    return this;
+  }
+  
+  public DynamicProperty setScale(Integer scale) {
+    this.scale = scale;
+    return this;
+  }
 }
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
index 0645423..158cae6 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataHttpHandlerImplTest.java
@@ -212,7 +212,7 @@
       String rawODataPath = p[4];
       String rawQueryPath = "".equals(p[5]) ? null : p[5];
       String rawRequestUri = requestUrl + (queryString == null ? "" : "?" + queryString);
-      String rawServiceResolutionUri = "".equals(p[3]) ? null : p[3];
+      String rawServiceResolutionUri = ("0".equals(p[6])) ? p[2] : p[3];
 
       when(hr.getAttribute("requestMapping")).thenReturn(p[2]);
       ODataHttpHandlerImpl.fillUriInformation(odr, hr, Integer.parseInt(p[6]));