OLINGO-1383
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/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
index a52e178..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;
@@ -787,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());
@@ -954,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/TripPinHandler.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinHandler.java
index 19b2898..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;
@@ -563,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 53a21e6..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
@@ -912,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/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;
+  }
 }