You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ra...@apache.org on 2015/02/11 17:45:50 UTC

[4/4] olingo-odata4 git commit: A new service dispatcher mechanism for handling server side requests

A new service dispatcher mechanism for handling server side requests


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

Branch: refs/heads/olingo-server-extension
Commit: b25fc8c2148fa6433dc50b9aba96cfb32457a82f
Parents: 200981d
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Tue Feb 3 15:20:39 2015 -0600
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Wed Feb 11 10:44:35 2015 -0600

----------------------------------------------------------------------
 lib/pom.xml                                     |   1 +
 .../api/deserializer/ODataDeserializer.java     |  29 +-
 lib/server-core-ext/pom.xml                     | 117 ++++
 .../olingo/server/core/ActionRequest.java       | 114 ++++
 .../apache/olingo/server/core/BatchRequest.java | 192 ++++++
 .../olingo/server/core/CountResponse.java       |  54 ++
 .../apache/olingo/server/core/DataRequest.java  | 560 +++++++++++++++
 .../olingo/server/core/EntityResponse.java      | 156 +++++
 .../olingo/server/core/EntitySetResponse.java   |  95 +++
 .../apache/olingo/server/core/ErrorHandler.java | 126 ++++
 .../olingo/server/core/FunctionRequest.java     | 117 ++++
 .../olingo/server/core/LiteralParser.java       | 177 +++++
 .../apache/olingo/server/core/MediaRequest.java |  77 +++
 .../olingo/server/core/MetadataParser.java      | 674 +++++++++++++++++++
 .../olingo/server/core/MetadataRequest.java     |  57 ++
 .../olingo/server/core/MetadataResponse.java    |  56 ++
 .../olingo/server/core/NoContentResponse.java   |  97 +++
 .../olingo/server/core/OData4HttpHandler.java   | 111 +++
 .../apache/olingo/server/core/OData4Impl.java   |  45 ++
 .../olingo/server/core/ODataServiceHandler.java |  38 ++
 .../olingo/server/core/OperationRequest.java    | 117 ++++
 .../server/core/PrimitiveValueResponse.java     |  99 +++
 .../olingo/server/core/PropertyResponse.java    | 133 ++++
 .../server/core/RequestURLHierarchyVisitor.java | 332 +++++++++
 .../olingo/server/core/RequestURLVisitor.java   | 126 ++++
 .../server/core/SchemaBasedEdmProvider.java     | 301 +++++++++
 .../olingo/server/core/ServiceDispatcher.java   | 179 +++++
 .../server/core/ServiceDocumentRequest.java     |  52 ++
 .../server/core/ServiceDocumentResponse.java    |  58 ++
 .../olingo/server/core/ServiceHandler.java      | 105 +++
 .../olingo/server/core/ServiceRequest.java      | 254 +++++++
 .../olingo/server/core/ServiceResponse.java     |  89 +++
 .../server/core/ServiceResponseVisior.java      |  71 ++
 .../olingo/server/core/StreamResponse.java      |  52 ++
 .../org/apache/olingo/server/core/Target.java   |  48 ++
 .../olingo/server/core/MetadataParserTest.java  | 190 ++++++
 .../server/core/ServiceDispatcherTest.java      | 316 +++++++++
 .../olingo/server/core/TripPinHandler.java      | 426 ++++++++++++
 .../olingo/server/core/TripPinServiceTest.java  | 298 ++++++++
 .../olingo/server/core/TripPinServlet.java      | 112 +++
 .../src/test/resources/OlingoOrangeTM.png       | Bin 0 -> 93316 bytes
 .../src/test/resources/airlines.json            |  64 ++
 .../src/test/resources/airports.json            | 394 +++++++++++
 .../src/test/resources/people.json              | 323 +++++++++
 .../src/test/resources/photos.json              |  64 ++
 .../src/test/resources/trippin.xml              | 355 ++++++++++
 .../json/ODataJsonDeserializer.java             |  78 ++-
 .../serializer/json/ODataJsonSerializer.java    |  11 +-
 .../server/core/uri/UriResourceActionImpl.java  |  14 +-
 .../server/core/uri/validator/UriValidator.java |  16 +-
 .../json/ODataJsonDeserializerBasicTest.java    |  20 +-
 .../json/ODataJsonDeserializerEntityTest.java   |  17 +-
 52 files changed, 7571 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/pom.xml
----------------------------------------------------------------------
diff --git a/lib/pom.xml b/lib/pom.xml
index 6843ff3..d1e8864 100644
--- a/lib/pom.xml
+++ b/lib/pom.xml
@@ -42,6 +42,7 @@
     <module>client-core</module>
     <module>server-api</module>
     <module>server-core</module>
+    <module>server-core-ext</module>
     <module>server-tecsvc</module>
     <module>server-test</module>
   </modules>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
index 46567ae..9cd55a3 100644
--- a/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
+++ b/lib/server-api/src/main/java/org/apache/olingo/server/api/deserializer/ODataDeserializer.java
@@ -6,9 +6,9 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License. You may obtain a copy of the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing,
  * software distributed under the License is distributed on an
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,10 +19,13 @@
 package org.apache.olingo.server.api.deserializer;
 
 import java.io.InputStream;
+import java.util.Map;
 
 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.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
 
 /**
  * Deserializer on OData server side.
@@ -31,7 +34,7 @@ public interface ODataDeserializer {
 
   /**
    * Deserializes an entity stream into an {@link Entity} object.
-   * Validates: property types, no double properties, correct json types 
+   * Validates: property types, no double properties, correct json types
    * @param stream
    * @param edmEntityType
    * @return deserialized {@link Entity} object
@@ -47,7 +50,23 @@ public interface ODataDeserializer {
    * @throws DeserializerException
    */
   EntitySet entityCollection(InputStream stream, EdmEntityType edmEntityType) throws DeserializerException;
-  
-  
 
+
+  /**
+   * Deserializes the Property or collections of properties (primitive & complex)
+   * @param stream
+   * @param edmProperty
+   * @return deserialized {@link Property}
+   * @throws DeserializerException
+   */
+  Property property(InputStream stream, EdmProperty edmProperty) throws DeserializerException;
+
+  /**
+   * Reads a simple key properties from document
+   * @param stream
+   * @param keys
+   * @return
+   * @throws DeserializerException
+   */
+  Map<String, String> read(InputStream stream, String... keys) throws DeserializerException;
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/pom.xml
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/pom.xml b/lib/server-core-ext/pom.xml
new file mode 100644
index 0000000..a5730c0
--- /dev/null
+++ b/lib/server-core-ext/pom.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements. See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership. The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License. You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied. See the License for the
+  specific language governing permissions and limitations
+  under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>odata-server-core-ext</artifactId>
+  <packaging>jar</packaging>
+  <name>${project.artifactId}</name>
+
+  <parent>
+    <groupId>org.apache.olingo</groupId>
+    <artifactId>odata-lib</artifactId>
+    <version>4.0.0-beta-03-SNAPSHOT</version>
+    <relativePath>..</relativePath>
+  </parent>
+  <properties>
+    <jetty-version>9.2.7.v20150116</jetty-version>
+  </properties>
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-server-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-server-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.olingo</groupId>
+      <artifactId>odata-commons-core</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.antlr</groupId>
+      <artifactId>antlr4-runtime</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+        <groupId>javax.xml.stream</groupId>
+        <artifactId>stax-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-simple</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+      <scope>test</scope>
+    </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-server</artifactId>
+            <scope>test</scope>
+            <version>${jetty-version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-servlet</artifactId>
+            <version>${jetty-version}</version>
+            <scope>test</scope>
+            <exclusions>
+              <exclusion>
+                <groupId>javax.servlet</groupId>
+                <artifactId>javax.servlet-api</artifactId>
+              </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-http</artifactId>
+            <version>${jetty-version}</version>
+            <scope>test</scope>
+        </dependency>    
+        <dependency>
+            <groupId>org.eclipse.jetty</groupId>
+            <artifactId>jetty-client</artifactId>
+            <scope>test</scope>
+            <version>${jetty-version}</version>
+        </dependency>        
+  </dependencies>
+
+</project>

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ActionRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ActionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ActionRequest.java
new file mode 100644
index 0000000..c29a45d
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ActionRequest.java
@@ -0,0 +1,114 @@
+/*
+ * 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 org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.uri.UriResourceAction;
+
+public class ActionRequest extends OperationRequest {
+  private UriResourceAction uriResourceAction;
+
+  public ActionRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+    // Actions MAY return data but MUST NOT be further composed with additional
+    // path segments.
+    // On success, the response is 201 Created for actions that create entities,
+    // 200 OK for actions
+    // that return results or 204 No Content for action without a return type.
+    // The client can request
+    // whether any results from the action be returned using the Prefer header.
+
+    if (!hasReturnType()) {
+      handler.invoke(this, getETag(), new NoContentResponse(response));
+    } else {
+      if (isReturnTypePrimitive()) {
+        handler.invoke(this, getETag(),
+            PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType()));
+      } else if (isReturnTypeComplex()) {
+        handler.invoke(this, getETag(), PropertyResponse.getInstance(this, response,
+            getReturnType().getType(), getContextURL(this.odata), isCollection()));
+      } else {
+        // EdmTypeKind.ENTITY
+        if (isCollection()) {
+          handler.invoke(this, getETag(),
+              EntitySetResponse.getInstance(this, getContextURL(odata), response));
+        } else {
+          handler.invoke(this, getETag(),
+              EntityResponse.getInstance(this, getContextURL(odata), response));
+        }
+      }
+    }
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    // 11.5.4.1 Invoking an Action - only allows POST
+    return (isPOST());
+  }
+
+  public UriResourceAction getUriResourceAction() {
+    return uriResourceAction;
+  }
+
+  protected void setUriResourceAction(UriResourceAction uriResourceAction) {
+    this.uriResourceAction = uriResourceAction;
+  }
+
+  @Override
+  public boolean isBound() {
+    return this.uriResourceAction.getActionImport() != null;
+  }
+
+  public EdmAction getAction() {
+    return this.uriResourceAction.getAction();
+  }
+
+  @Override
+  public boolean isCollection() {
+    assert (hasReturnType());
+    return getAction().getReturnType().isCollection();
+  }
+
+  @Override
+  public EdmReturnType getReturnType() {
+    assert (hasReturnType());
+    return getAction().getReturnType();
+  }
+
+  @Override
+  public boolean hasReturnType() {
+    return getAction().getReturnType() != null;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/BatchRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/BatchRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/BatchRequest.java
new file mode 100644
index 0000000..828d186
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/BatchRequest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.UUID;
+
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
+import org.apache.olingo.server.api.deserializer.batch.BatchOptions;
+import org.apache.olingo.server.api.deserializer.batch.BatchRequestPart;
+import org.apache.olingo.server.api.deserializer.batch.ODataResponsePart;
+import org.apache.olingo.server.core.batchhandler.referenceRewriting.BatchReferenceRewriter;
+import org.apache.olingo.server.core.deserializer.batch.BatchParserCommon;
+
+public class BatchRequest extends ServiceRequest {
+  private static final String PREFERENCE_CONTINUE_ON_ERROR = "odata.continue-on-error";
+  private final BatchReferenceRewriter rewriter;
+
+  public BatchRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+    this.rewriter = new BatchReferenceRewriter();
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+
+    validateContentType();
+    boolean continueOnError = isContinueOnError();
+    final String boundary = extractBoundary(getRequestContentType());
+
+    final BatchOptions options = BatchOptions.with().rawBaseUri(request.getRawBaseUri())
+        .rawServiceResolutionUri(this.request.getRawServiceResolutionUri()).build();
+
+    final List<BatchRequestPart> parts = this.odata.createFixedFormatDeserializer()
+        .parseBatchRequest(request.getBody(), boundary, options);
+
+    ODataResponsePart partResponse = null;
+    final List<ODataResponsePart> responseParts = new ArrayList<ODataResponsePart>();
+
+    for (BatchRequestPart part : parts) {
+      if (part.isChangeSet()) {
+        String txnId = handler.startTransaction();
+        partResponse = processChangeSet(part, handler);
+        if (partResponse.getResponses().get(0).getStatusCode() > 400) {
+          handler.rollback(txnId);
+        }
+        handler.commit(txnId);
+      } else {
+        // single request, a static request
+        ODataRequest partRequest = part.getRequests().get(0);
+        partResponse = process(partRequest, handler);
+      }
+      responseParts.add(partResponse);
+
+      // on error, should we continue?
+      final int statusCode = partResponse.getResponses().get(0).getStatusCode();
+      if ((statusCode >= 400 && statusCode <= 600) && !continueOnError) {
+        break;
+      }
+    }
+
+    // send response
+    final String responseBoundary = "batch_" + UUID.randomUUID().toString();
+    ;
+    final InputStream responseContent = odata.createFixedFormatSerializer().batchResponse(
+        responseParts, responseBoundary);
+    response.setHeader(HttpHeader.CONTENT_TYPE, ContentType.MULTIPART_MIXED + ";boundary="
+        + responseBoundary);
+    response.setContent(responseContent);
+    response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
+  }
+
+  ODataResponsePart process(ODataRequest partRequest, ServiceHandler serviceHandler) {
+    ODataResponse partResponse = executeSingleRequest(partRequest, serviceHandler);
+    addContentID(partRequest, partResponse);
+    return new ODataResponsePart(partResponse, false);
+  }
+
+  ODataResponsePart processChangeSet(BatchRequestPart partRequest, ServiceHandler serviceHandler)
+      throws BatchDeserializerException {
+    List<ODataResponse> changeSetResponses = new ArrayList<ODataResponse>();
+    // change set need to be a in a atomic operation
+    for (ODataRequest changeSetPartRequest : partRequest.getRequests()) {
+
+      this.rewriter.replaceReference(changeSetPartRequest);
+
+      ODataResponse partResponse = executeSingleRequest(changeSetPartRequest, serviceHandler);
+
+      this.rewriter.addMapping(changeSetPartRequest, partResponse);
+      addContentID(changeSetPartRequest, partResponse);
+
+      if (partResponse.getStatusCode() < 400) {
+        changeSetResponses.add(partResponse);
+      } else {
+        // 11.7.4 Responding to a Batch Request
+        return new ODataResponsePart(partResponse, false);
+      }
+    }
+    return new ODataResponsePart(changeSetResponses, true);
+  }
+
+  ODataResponse executeSingleRequest(ODataRequest singleRequest, ServiceHandler handler) {
+    ServiceDispatcher dispatcher = new ServiceDispatcher(this.odata, this.serviceMetadata, handler,
+        this.customContentType);
+    ODataResponse res = new ODataResponse();
+    try {
+      dispatcher.execute(singleRequest, res);
+    } catch (Exception e) {
+      ErrorHandler ehandler = new ErrorHandler(this.odata, this.serviceMetadata,
+          getCustomContentTypeSupport());
+      ehandler.handleException(e, singleRequest, res);
+    }
+    return res;
+  }
+
+  private void addContentID(ODataRequest batchPartRequest, ODataResponse batchPartResponse) {
+    final String contentId = batchPartRequest.getHeader(BatchParserCommon.HTTP_CONTENT_ID);
+    if (contentId != null) {
+      batchPartResponse.setHeader(BatchParserCommon.HTTP_CONTENT_ID, contentId);
+    }
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    return isPOST();
+  }
+
+  private void validateContentType() throws ODataApplicationException {
+    final String contentType = getRequestContentType().toContentTypeString();
+
+    if (contentType == null
+        || !BatchParserCommon.PATTERN_MULTIPART_BOUNDARY.matcher(contentType).matches()) {
+      throw new ODataApplicationException("Invalid content type",
+          HttpStatusCode.PRECONDITION_FAILED.getStatusCode(), Locale.getDefault());
+    }
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return null;
+  }
+
+  private boolean isContinueOnError() {
+    final List<String> preferValues = this.request.getHeaders(HttpHeader.PREFER);
+
+    if (preferValues != null) {
+      for (final String preference : preferValues) {
+        if (PREFERENCE_CONTINUE_ON_ERROR.equals(preference)) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+  private String extractBoundary(ContentType contentType) throws BatchDeserializerException {
+    return BatchParserCommon.getBoundary(contentType.toContentTypeString(), 0);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/CountResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/CountResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/CountResponse.java
new file mode 100644
index 0000000..bd85f0c
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/CountResponse.java
@@ -0,0 +1,54 @@
+/*
+ * 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 org.apache.olingo.commons.api.http.HttpContentType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class CountResponse extends ServiceResponse {
+  private final FixedFormatSerializer serializer;
+
+  public static CountResponse getInstance(ServiceRequest request, ODataResponse response) {
+    FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
+    return new CountResponse(serializer, response);
+  }
+
+  private CountResponse(FixedFormatSerializer serializer, ODataResponse response) {
+    super(response);
+    this.serializer = serializer;
+  }
+
+  public void writeCount(int count) throws SerializerException {
+    assert (!isClosed());
+
+    this.response.setContent(this.serializer.count(count));
+    writeOK(HttpContentType.TEXT_PLAIN);
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/DataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/DataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/DataRequest.java
new file mode 100644
index 0000000..a96bd1c
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/DataRequest.java
@@ -0,0 +1,560 @@
+/*
+ * 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.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.List;
+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.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.core.data.PropertyImpl;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmPrimitiveTypeFactory;
+import org.apache.olingo.commons.core.edm.primitivetype.EdmStream;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerException.MessageKeys;
+import org.apache.olingo.server.api.deserializer.ODataDeserializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.RepresentationType;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.uri.UriHelper;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResourceComplexProperty;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.api.uri.UriResourceNavigation;
+import org.apache.olingo.server.api.uri.UriResourcePrimitiveProperty;
+import org.apache.olingo.server.api.uri.UriResourceProperty;
+import org.apache.olingo.server.api.uri.UriResourceSingleton;
+
+public class DataRequest extends ServiceRequest {
+  protected UriResourceEntitySet uriResourceEntitySet;
+  private boolean countRequest;
+  private UriResourceProperty uriResourceProperty;
+  private boolean valueRequest;
+  private UriResourceNavigation uriResourceNavigation;
+  private boolean references;
+
+  private RequestType type;
+  private UriResourceSingleton uriResourceSingleton;
+
+  /**
+   * This sub-categorizes the request so that code can be simplified
+   */
+  interface RequestType {
+    public boolean allowedMethod();
+
+    public ContentType getResponseContentType() throws ContentNegotiatorException;
+
+    public ContextURL getContextURL(OData odata) throws SerializerException;
+
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException;
+  }
+
+  public DataRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  public UriResourceEntitySet getUriResourceEntitySet() {
+    return uriResourceEntitySet;
+  }
+
+  protected void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
+    this.uriResourceEntitySet = uriResourceEntitySet;
+    this.type = new EntityRequest();
+  }
+
+  public boolean isSingleton() {
+    return this.uriResourceSingleton != null;
+  }
+
+  public boolean isCollection() {
+    return this.uriResourceEntitySet != null && this.uriResourceEntitySet.isCollection();
+  }
+
+  public EdmEntitySet getEntitySet() {
+    return this.uriResourceEntitySet.getEntitySet();
+  }
+
+  public boolean isCountRequest() {
+    return countRequest;
+  }
+
+  protected void setCountRequest(boolean countRequest) {
+    this.countRequest = countRequest;
+    this.type = new CountRequest();
+  }
+
+  public boolean isPropertyRequest() {
+    return this.uriResourceProperty != null;
+  }
+
+  public boolean isPropertyComplex() {
+    return (this.uriResourceProperty instanceof UriResourceComplexProperty);
+  }
+
+  public boolean isPropertyStream() {
+    if (isPropertyComplex()) {
+      return false;
+    }
+    EdmProperty property = ((UriResourcePrimitiveProperty)this.uriResourceProperty).getProperty();
+    return (property.getType() instanceof EdmStream);
+  }
+
+  public UriResourceProperty getUriResourceProperty() {
+    return uriResourceProperty;
+  }
+
+  protected void setUriResourceProperty(UriResourceProperty uriResourceProperty) {
+    this.uriResourceProperty = uriResourceProperty;
+    this.type = new PropertyRequest();
+  }
+
+  public UriResourceNavigation getUriResourceNavigation() {
+    return uriResourceNavigation;
+  }
+
+  protected void setUriResourceNavigation(UriResourceNavigation uriResourceNavigation) {
+    this.uriResourceNavigation = uriResourceNavigation;
+  }
+
+  public UriResourceSingleton getUriResourceSingleton() {
+    return this.uriResourceSingleton;
+  }
+
+  protected void setUriResourceSingleton(UriResourceSingleton info) {
+    this.uriResourceSingleton = info;
+    this.type = new SingletonRequest();
+  }
+
+  protected List<UriParameter> getKeyPredicates() {
+    if (this.uriResourceEntitySet != null) {
+      return this.uriResourceEntitySet.getKeyPredicates();
+    }
+    return null;
+  }
+
+  public boolean isReferenceRequest() {
+    return this.references;
+  }
+
+  protected void setReferenceRequest(boolean ref) {
+    this.references = ref;
+    this.type = new ReferenceRequest();
+  }
+
+  public boolean isValueRequest() {
+    return valueRequest;
+  }
+
+  private boolean hasMediaStream() {
+    return this.uriResourceEntitySet != null && this.uriResourceEntitySet.getEntityType().hasStream();
+  }
+
+  private InputStream getMediaStream() {
+    return this.request.getBody();
+  }
+
+  protected void setValueRequest(boolean valueRequest) {
+    this.valueRequest = valueRequest;
+    this.type = new ValueRequest();
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    return this.type.allowedMethod();
+  }
+
+  public ContextURL getContextURL(OData odata) throws SerializerException {
+    return type.getContextURL(odata);
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!this.type.allowedMethod()) {
+      methodNotAllowed();
+    }
+
+    this.type.execute(handler, response);
+  }
+
+  @Override
+  public <T> T getSerializerOptions(Class<T> serilizerOptions, ContextURL contextUrl)
+      throws ContentNegotiatorException {
+    if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
+      return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
+          .facetsFrom(getUriResourceProperty().getProperty()).build();
+    }
+    return super.getSerializerOptions(serilizerOptions, contextUrl);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return type.getResponseContentType();
+  }
+
+  class EntityRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      return true;
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
+              : RepresentationType.ENTITY);
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+
+      EntityResponse entityResponse = EntityResponse.getInstance(DataRequest.this,
+          getContextURL(odata), response);
+
+      if (isGET()) {
+        if (isCollection()) {
+          handler.read(DataRequest.this,
+              EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), response));
+        } else {
+          handler.read(DataRequest.this,entityResponse);
+        }
+      } else if (isPUT() || isPATCH()) {
+        // RFC 2616: he result of a request having both an If-Match header field and either
+        // an If-None-Match or an If-Modified-Since header fields is undefined
+        // by this specification.
+        boolean ifMatch = getHeader(HttpHeader.IF_MATCH) != null;
+        boolean ifNoneMatch = getHeader(HttpHeader.IF_NONE_MATCH).equals("*");
+        if(ifMatch) {
+          handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
+              entityResponse);
+        } else if (ifNoneMatch) {
+          // 11.4.4
+          handler.createEntity(DataRequest.this, getEntityFromClient(),
+              entityResponse.setReturnRepresentation(getReturnRepresentation()));
+        } else {
+          handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
+              entityResponse);
+        }
+      } else if (isPOST()) {
+        if (hasMediaStream()) {
+          handler.createMediaEntity(DataRequest.this, getEntityFromClient(), getMediaStream(),
+              entityResponse.setReturnRepresentation(getReturnRepresentation()));
+        } else {
+          handler.createEntity(DataRequest.this, getEntityFromClient(),
+              entityResponse.setReturnRepresentation(getReturnRepresentation()));
+        }
+      } else if (isDELETE()) {
+        handler.deleteEntity(DataRequest.this, getETag(), entityResponse);
+      }
+    }
+
+    private Entity getEntityFromClient() throws DeserializerException {
+      ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
+          .fromContentType(getRequestContentType()));
+      return deserializer.entity(getODataRequest().getBody(), getEntitySet().getEntityType());
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      // EntitySet based return
+      final UriHelper helper = odata.createUriHelper();
+      ContextURL.Builder builder = buildEntitySetContextURL(helper, getEntitySet(), getUriInfo(),
+          isCollection(), false);
+      return builder.build();
+    }
+  }
+
+  class CountRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      return isGET();
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      return ContentType.TEXT_PLAIN;
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+      handler.read(DataRequest.this, CountResponse.getInstance(DataRequest.this, response));
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      return null;
+    }
+  }
+
+  class ReferenceRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      if (isPATCH()) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_REFERENCE
+              : RepresentationType.REFERENCE);
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+      if (isGET()) {
+        if (isCollection()) {
+          handler.read(DataRequest.this,
+              EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), response)
+                  .sendReferences(true));
+        } else {
+          handler.read(DataRequest.this,EntityResponse.getInstance(DataRequest.this,
+              getContextURL(odata), response).sendReferences(true));
+        }
+      } else if (isDELETE()) {
+        handler.deleteReference(DataRequest.this, getETag(), new NoContentResponse(response));
+      } else if (isPUT()) {
+        handler.updateReference(DataRequest.this, getETag(), getPayload(), new NoContentResponse(response));
+      } else if (isPOST()) {
+        // this needs to be against collection of references
+        handler.addReference(DataRequest.this, getETag(), getPayload(), new NoContentResponse(response));
+      }
+    }
+
+    // the payload will be like
+    // {
+    // "@odata.id": "serviceRoot/People('vincentcalabrese')"
+    // }
+    // The below code reads as proeprty and converts to an URI
+    private URI getPayload() throws DeserializerException {
+
+      ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
+          .fromContentType(getRequestContentType()));
+      Map<String, String> values = deserializer.read(getODataRequest().getBody(), "@odata.id");
+      try {
+        return new URI(values.get("@odata.id"));
+      } catch (URISyntaxException e) {
+        throw new DeserializerException("failed to read @odata.id", e, MessageKeys.UNKOWN_CONTENT);
+      }
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      ContextURL.Builder builder = ContextURL.with().suffix(Suffix.REFERENCE);
+      if (isCollection()) {
+        builder.asCollection();
+      }
+      return builder.build();
+    }
+  }
+
+  class PropertyRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      // create of properties is not allowed,
+      // only read, update, delete. Note that delete is
+      // same as update with null
+      if (isPOST()) {
+        return false;
+      }
+
+      // 11.4.9.4, collection properties are not supported with merge
+      if (isPATCH() && (isCollection() || isPropertyStream())) {
+        return false;
+      }
+      return true;
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      if (isPropertyComplex()) {
+        return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
+            getODataRequest(), getCustomContentTypeSupport(),
+            isCollection() ? RepresentationType.COLLECTION_COMPLEX : RepresentationType.COMPLEX);
+      } else if (isPropertyStream()) {
+        return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request,
+            getCustomContentTypeSupport(), RepresentationType.BINARY);
+      }
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_PRIMITIVE
+              : RepresentationType.PRIMITIVE);
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+
+      EdmProperty edmProperty = getUriResourceProperty().getProperty();
+
+      PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
+          edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
+
+      if (isGET()) {
+        handler.read(DataRequest.this, propertyResponse);
+      } else if (isPATCH()) {
+        handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), true,
+            getETag(), propertyResponse);
+      } else if (isPUT()) {
+        if (isPropertyStream()) {
+          handler.updateStreamProperty(DataRequest.this, request.getBody(), getETag(),
+              new StreamResponse(response));
+        } else {
+          handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false,
+              getETag(), propertyResponse);
+        }
+      } else if (isDELETE()) {
+        Property property = new PropertyImpl();
+        property.setName(edmProperty.getName());
+        property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
+        handler.updateProperty(DataRequest.this, property, false, getETag(), propertyResponse);
+      }
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      final UriHelper helper = odata.createUriHelper();
+      EdmProperty edmProperty = getUriResourceProperty().getProperty();
+
+      ContextURL.Builder builder = ContextURL.with().entitySet(getEntitySet());
+      builder = ContextURL.with().entitySet(getEntitySet());
+      builder.keyPath(helper.buildContextURLKeyPredicate(getUriResourceEntitySet()
+          .getKeyPredicates()));
+      builder.navOrPropertyPath(edmProperty.getName());
+      if (isPropertyComplex()) {
+        EdmComplexType type = ((UriResourceComplexProperty) uriResourceProperty).getComplexType();
+        String select = helper.buildContextURLSelectList(type, getUriInfo().getExpandOption(),
+            getUriInfo().getSelectOption());
+        builder.selectList(select);
+      }
+      return builder.build();
+    }
+  }
+
+  class ValueRequest extends PropertyRequest {
+
+    @Override
+    public boolean allowedMethod() {
+      return isGET() || isDELETE() || isPUT();
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      RepresentationType valueRepresentationType = uriResourceProperty.getType() == EdmPrimitiveTypeFactory
+          .getInstance(EdmPrimitiveTypeKind.Binary) ? RepresentationType.BINARY
+          : RepresentationType.VALUE;
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), request,
+          getCustomContentTypeSupport(), valueRepresentationType);
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+      EdmProperty edmProperty = getUriResourceProperty().getProperty();
+      if (isGET()) {
+        handler.read(DataRequest.this, PrimitiveValueResponse.getInstance(DataRequest.this,
+            response, isCollection(), getUriResourceProperty().getProperty()));
+      } else if (isDELETE()) {
+        Property property = new PropertyImpl();
+        property.setName(edmProperty.getName());
+        property.setType(edmProperty.getType().getFullQualifiedName().getFullQualifiedNameAsString());
+
+        PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
+            edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
+        handler.updateProperty(DataRequest.this, property, false, getETag(), propertyResponse);
+      } else if (isPUT()) {
+        PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
+            edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
+        handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false,
+            getETag(), propertyResponse);
+      }
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      return null;
+    }
+  }
+
+  class SingletonRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      return isGET();
+    }
+
+    @Override
+    public ContentType getResponseContentType() throws ContentNegotiatorException {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), getODataRequest(),
+          getCustomContentTypeSupport(), RepresentationType.ENTITY);
+    }
+
+    @Override
+    public ContextURL getContextURL(OData odata) throws SerializerException {
+      final UriHelper helper = odata.createUriHelper();
+      ContextURL.Builder builder = buildEntitySetContextURL(helper,
+          uriResourceSingleton.getSingleton(), getUriInfo(), isCollection(), true);
+      return builder.build();
+    }
+
+    @Override
+    public void execute(ServiceHandler handler, ODataResponse response)
+        throws ODataTranslatedException, ODataApplicationException {
+      handler.read(DataRequest.this,
+          EntityResponse.getInstance(DataRequest.this, getContextURL(odata), response));
+    }
+  }
+
+  private org.apache.olingo.commons.api.data.Property getPropertyValueFromClient(
+      EdmProperty edmProperty) throws DeserializerException {
+    // TODO:this is not right, we should be deserializing the property
+    // (primitive, complex, collection of)
+    // for now it is responsibility of the user
+    ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
+        .fromContentType(getRequestContentType()));
+    return deserializer.property(getODataRequest().getBody(), edmProperty);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntityResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntityResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntityResponse.java
new file mode 100644
index 0000000..b52090b
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntityResponse.java
@@ -0,0 +1,156 @@
+/*
+ * 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 org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Entity;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.serializer.EntitySerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ServiceRequest.ReturnRepresentation;
+
+public class EntityResponse extends ServiceResponse {
+  private boolean referencesOnly;
+  private ReturnRepresentation returnRepresentation;
+  private boolean hasMediaStream;
+  private final ODataSerializer serializer;
+  private final EntitySerializerOptions options;
+  private final ContentType responseContentType;
+
+  private EntityResponse(ODataResponse response, ODataSerializer serializer,
+      EntitySerializerOptions options, ContentType responseContentType) {
+    super(response);
+    this.serializer = serializer;
+    this.options = options;
+    this.responseContentType = responseContentType;
+  }
+
+  public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
+      ODataResponse response) throws ContentNegotiatorException, SerializerException {
+    EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
+        contextURL);
+    return new EntityResponse(response, request.getSerializer(), options,
+        request.getResponseContentType());
+  }
+
+  // write single entity
+  public void writeReadEntity(EdmEntityType entityType, Entity entity) throws SerializerException {
+
+    assert (!isClosed());
+
+    if (entity == null) {
+      writeNotFound(true);
+      return;
+    }
+
+    if (this.referencesOnly) {
+      // TODO: need to write serializer routine to write only references,
+      // i.e URL with ID
+      writeServerError(true);
+      return;
+    }
+
+    // write the entity to response
+    this.response.setContent(this.serializer.entity(entityType, entity, this.options));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  public void writeCreatedEntity(EdmEntityType entityType, Entity entity, String locationHeader)
+      throws SerializerException {
+    // upsert/insert must created a entity, otherwise should have throw an
+    // exception
+    assert (entity != null);
+
+    if (this.hasMediaStream) {
+      // TODO: need to write serializer routine to write media context
+      writeServerError(true);
+      return;
+    }
+
+    // 8.2.8.7
+    if (this.returnRepresentation == ReturnRepresentation.MINIMAL) {
+      writeNoContent(false);
+      writeHeader(HttpHeader.LOCATION, locationHeader);
+      writeHeader("Preference-Applied", "return=minimal"); //$NON-NLS-1$ //$NON-NLS-2$
+      // 8.3.3
+      writeHeader("OData-EntityId", entity.getId().toASCIIString()); //$NON-NLS-1$
+      close();
+      return;
+    }
+
+    // return the content of the created entity
+    this.response.setContent(this.serializer.entity(entityType, entity, this.options));
+    writeCreated(false);
+    writeHeader(HttpHeader.LOCATION, locationHeader);
+    writeHeader("Preference-Applied", "return=representation"); //$NON-NLS-1$ //$NON-NLS-2$
+    writeHeader(HttpHeader.CONTENT_TYPE, this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  public void writeUpdatedEntity() {
+    // spec says just success response; so either 200 or 204. 200 typically has
+    // payload
+    writeNoContent(true);
+  }
+
+  public void writeDeletedEntityOrReference() {
+    writeNoContent(true);
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+
+  public void writeCreated(boolean closeResponse) {
+    this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+    if (closeResponse) {
+      close();
+    }
+  }
+
+  protected EntityResponse sendReferences(boolean ref) {
+    this.referencesOnly = ref;
+    return this;
+  }
+
+  protected EntityResponse setReturnRepresentation(ReturnRepresentation returnRepresentation) {
+    this.returnRepresentation = returnRepresentation;
+    return this;
+  }
+
+  protected EntityResponse setReferencesOnly(boolean referencesOnly) {
+    this.referencesOnly = referencesOnly;
+    return this;
+  }
+
+  protected EntityResponse setHasMediaStream(boolean stream) {
+    this.hasMediaStream = stream;
+    return this;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntitySetResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntitySetResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntitySetResponse.java
new file mode 100644
index 0000000..29e5b10
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/EntitySetResponse.java
@@ -0,0 +1,95 @@
+/*
+ * 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 org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.EntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+
+public class EntitySetResponse extends ServiceResponse {
+  private boolean referencesOnly;
+  private final ODataSerializer serializer;
+  private final EntityCollectionSerializerOptions options;
+  private final ContentType responseContentType;
+
+  private EntitySetResponse(ODataResponse response, ODataSerializer serializer,
+      EntityCollectionSerializerOptions options,
+      ContentType responseContentType) {
+    super(response);
+    this.serializer = serializer;
+    this.options = options;
+    this.responseContentType = responseContentType;
+  }
+
+  public static EntitySetResponse getInstance(ServiceRequest request, ContextURL contextURL,
+      ODataResponse response) throws ContentNegotiatorException, SerializerException {
+    EntityCollectionSerializerOptions options = request.getSerializerOptions(
+        EntityCollectionSerializerOptions.class, contextURL);
+    return new EntitySetResponse(response, request.getSerializer(), options,
+        request.getResponseContentType());
+  }
+
+  // write collection of entities
+  // TODO: server paging needs to be implemented.
+  public void writeReadEntitySet(EdmEntityType entityType, EntitySet entitySet)
+      throws SerializerException {
+
+    assert (!isClosed());
+
+    if (entitySet == null) {
+      writeNotFound(true);
+      return;
+    }
+
+    if (this.referencesOnly) {
+      // TODO: need to write serializer routine to write only references,
+      // i.e URL with ID
+      writeServerError(true);
+      return;
+    }
+
+    // write the whole collection to response
+    this.response.setContent(this.serializer.entityCollection(entityType, entitySet, this.options));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+
+  protected EntitySetResponse sendReferences(boolean ref) {
+    this.referencesOnly = ref;
+    return this;
+  }
+
+  protected EntitySetResponse setReferencesOnly(boolean referencesOnly) {
+    this.referencesOnly = referencesOnly;
+    return this;
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
new file mode 100644
index 0000000..ed662f4
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ErrorHandler.java
@@ -0,0 +1,126 @@
+/*
+ * 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.ByteArrayInputStream;
+
+import org.apache.olingo.commons.api.edm.constants.ODataServiceVersion;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.format.ODataFormat;
+import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataRequest;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataServerError;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.batch.exception.BatchDeserializerException;
+import org.apache.olingo.server.api.deserializer.DeserializerException;
+import org.apache.olingo.server.api.serializer.CustomContentTypeSupport;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.RepresentationType;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.api.uri.UriInfo;
+import org.apache.olingo.server.core.uri.parser.Parser;
+import org.apache.olingo.server.core.uri.parser.UriParserException;
+import org.apache.olingo.server.core.uri.parser.UriParserSemanticException;
+import org.apache.olingo.server.core.uri.parser.UriParserSyntaxException;
+import org.apache.olingo.server.core.uri.validator.UriValidationException;
+
+public class ErrorHandler {
+  private final OData odata;
+  private final ServiceMetadata metadata;
+  private final CustomContentTypeSupport customContent;
+
+  public ErrorHandler(OData odata, ServiceMetadata metadata, CustomContentTypeSupport customContent) {
+    this.odata = odata;
+    this.metadata = metadata;
+    this.customContent = customContent;
+  }
+
+  public void handleException(Exception e, ODataRequest request, ODataResponse response) {
+    if (e instanceof UriValidationException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriValidationException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof UriParserSemanticException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserSemanticException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof  UriParserSyntaxException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserSyntaxException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof  UriParserException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((UriParserException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof ContentNegotiatorException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((ContentNegotiatorException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof SerializerException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((SerializerException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof BatchDeserializerException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((BatchDeserializerException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof DeserializerException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((DeserializerException)e, null);
+      handleServerError(request, response, serverError);
+    } else if(e instanceof ODataHandlerException) {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject((ODataHandlerException)e, null);
+      handleServerError(request, response, serverError);
+    } else {
+      ODataServerError serverError = ODataExceptionHelper.createServerErrorObject(e);
+      handleServerError(request, response, serverError);
+    }
+  }
+
+  void handleServerError(final ODataRequest request, final ODataResponse response,
+      final ODataServerError serverError) {
+    ContentType requestedContentType;
+    try {
+      UriInfo uriInfo = new Parser().parseUri(request.getRawODataPath(), request.getRawQueryPath(),
+          null, this.metadata.getEdm());
+      requestedContentType = ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(),
+          request, this.customContent, RepresentationType.ERROR);
+    } catch (final ContentNegotiatorException e) {
+      requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
+    } catch (UriParserException e) {
+      requestedContentType = ODataFormat.JSON.getContentType(ODataServiceVersion.V40);
+    }
+    processError(response, serverError, requestedContentType);
+  }
+
+  void processError(ODataResponse response, ODataServerError serverError,
+      ContentType requestedContentType) {
+    try {
+      ODataSerializer serializer = this.odata.createSerializer(ODataFormat
+          .fromContentType(requestedContentType));
+      response.setContent(serializer.error(serverError));
+      response.setStatusCode(serverError.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE, requestedContentType.toContentTypeString());
+    } catch (Exception e) {
+      // This should never happen but to be sure we have this catch here
+      // to prevent sending a stacktrace to a client.
+      String responseContent = "{\"error\":{\"code\":null,\"message\":\"An unexpected exception occurred during "
+          + "error processing with message: " + e.getMessage() + "\"}}"; //$NON-NLS-1$ //$NON-NLS-2$
+      response.setContent(new ByteArrayInputStream(responseContent.getBytes()));
+      response.setStatusCode(HttpStatusCode.INTERNAL_SERVER_ERROR.getStatusCode());
+      response.setHeader(HttpHeader.CONTENT_TYPE,
+          ContentType.APPLICATION_JSON.toContentTypeString());
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/FunctionRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/FunctionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/FunctionRequest.java
new file mode 100644
index 0000000..be7b2bd
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/FunctionRequest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.util.List;
+
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResourceFunction;
+
+public class FunctionRequest extends OperationRequest {
+  private UriResourceFunction uriResourceFunction;
+
+  public FunctionRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+
+    // Functions always have return per 11.5.3
+    if (isReturnTypePrimitive()) {
+      // functions can not return a typed property in the context of entity, so
+      // it must be treated
+      // as value based response
+      handler.invoke(this, getODataRequest().getMethod(),
+          PrimitiveValueResponse.getInstance(this, response, isCollection(), getReturnType()));
+    } else if (isReturnTypeComplex()) {
+      handler.invoke(this, getODataRequest().getMethod(), PropertyResponse.getInstance(this, response,
+          getReturnType().getType(), getContextURL(this.odata), isCollection()));
+    } else {
+      // returnType.getType().getKind() == EdmTypeKind.ENTITY
+      if (isCollection()) {
+        handler.invoke(this, getODataRequest().getMethod(),
+            EntitySetResponse.getInstance(this, getContextURL(odata), response));
+      } else {
+        handler.invoke(this, getODataRequest().getMethod(),
+            EntityResponse.getInstance(this, getContextURL(odata), response));
+      }
+    }
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    // look for discussion about composable functions in odata-discussion
+    // group with thread "Clarification on "Function" invocations"
+    if (getFunction().isComposable()) {
+      return (isGET() || isPATCH() || isDELETE() || isPOST() || isPUT());
+    }
+    return isGET();
+  }
+
+  public UriResourceFunction getUriResourceFunction() {
+    return uriResourceFunction;
+  }
+
+  protected void setUriResourceFunction(UriResourceFunction uriResourceFunction) {
+    this.uriResourceFunction = uriResourceFunction;
+  }
+
+  @Override
+  public boolean isBound() {
+    return this.uriResourceFunction.getFunctionImport() != null;
+  }
+
+  public EdmFunction getFunction() {
+    return this.uriResourceFunction.getFunction();
+  }
+
+  public List<UriParameter> getParameters() {
+    return this.uriResourceFunction.getParameters();
+  }
+
+  @Override
+  public boolean isCollection() {
+    return getFunction().getReturnType().isCollection();
+  }
+
+  @Override
+  public EdmReturnType getReturnType() {
+    return getFunction().getReturnType();
+  }
+
+  @Override
+  public boolean hasReturnType() {
+    // Part3 {12.1} says must have return type
+    return true;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/LiteralParser.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/LiteralParser.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/LiteralParser.java
new file mode 100644
index 0000000..4c5f596
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/LiteralParser.java
@@ -0,0 +1,177 @@
+/*
+ * 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.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.codec.DecoderException;
+
+@SuppressWarnings("nls")
+/**
+ * TODO: this needs to be folded into ODataDeSeriliazer, to deserialize a primitive type
+ */
+public class LiteralParser {
+
+    private static final Pattern INT_PATTERN = Pattern.compile("[\\+|-]?\\d+");
+    private static final Pattern DOUBLE_PATTERN = Pattern.compile("[\\+|-]?\\d+\\.\\d+((e|E) [\\+|-]? \\d+)?");
+    private static final Pattern BOOLEAN_PATTERN = Pattern.compile("true|false|TRUE|FALSE");
+    private static final Pattern BINARY_PATTERN = Pattern.compile("^binary\\s'([a-fA-f0-9]*)'$");
+    private static final Pattern DATE_PATTERN = Pattern.compile("^(\\d{4})-(\\d{2})-(\\d{2})$");
+    private static final Pattern TIME_PATTERN = Pattern.compile("^(\\d{2}):(\\d{2}):(\\d{2})$");
+
+    // dateTimeOffsetValue = year "-" month "-" day "T" hour ":" minute [ ":"
+    // second [ "." fractionalSeconds ] ] ( "Z" / sign hour ":" minute )
+    private static final Pattern DATETIME_PATTERN = Pattern.compile("" + "^"
+            + "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2})" + // group 1 (datetime)
+            "(:\\d{2})?" + // group 2 (seconds)
+            "(\\.\\d{1,7})?" + // group 3 (nanoseconds)
+            "((Z)|([\\+|-]?\\d{2}:\\d{2}))?" + // group 4 (tz, ignored - handles
+                                               // bad services)
+            "$");
+
+    private static final Pattern DATETIMEOFFSET_PATTERN = Pattern.compile(""
+            + "^" + "(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2})" + // group 1
+                                                                    // (datetime)
+            "(\\.\\d{1,7})?" + // group 2 (nanoSeconds)
+            "(((\\+|-)\\d{2}:\\d{2})|(Z))" + // group 3 (offset) / group 6 (utc)
+            "$");
+
+    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
+    private static final SimpleDateFormat DATETIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
+    private static final SimpleDateFormat DATETIME_WITH_SECONDS_FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+    private static final SimpleDateFormat DATETIME_WITH_MILLIS_FORMAT = new SimpleDateFormat(
+            "yyyy-MM-dd'T'HH:mm:ss.SSS");
+    private static final SimpleDateFormat DATETIMEOFFSET_XML = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZ");
+    private static final SimpleDateFormat DATETIMEOFFSET_WITH_MILLIS_FORMAT = new SimpleDateFormat(
+            "yyyy-MM-dd'T'HH:mm:ss.SSSZZ");
+    private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
+
+    public static Object parseLiteral(String text) {
+        if (text.equals("null")) {
+            return null;
+        }
+
+        text = text.trim();
+
+        if (INT_PATTERN.matcher(text).matches()) {
+            try {
+                return Integer.parseInt(text);
+            } catch (NumberFormatException e) {
+                return Long.parseLong(text);
+            }
+        } else if (DOUBLE_PATTERN.matcher(text).matches()) {
+            return Double.parseDouble(text);
+        } else if (BOOLEAN_PATTERN.matcher(text).matches()) {
+            return Boolean.parseBoolean(text);
+        } else if (BINARY_PATTERN.matcher(text).matches()) {
+            try {
+                return org.apache.commons.codec.binary.Hex.decodeHex(text.toCharArray());
+            } catch (DecoderException e) {
+                // fall through and returned as text
+            }
+        } else if (DATE_PATTERN.matcher(text).matches()) {
+            try {
+                return new Date(DATE_FORMAT.parse(text).getTime());
+            } catch (ParseException e) {
+                // fall through and returned as text
+            }
+        } else if (DATETIME_PATTERN.matcher(text).matches()) {
+            try {
+                return parseDateTime(text);
+            } catch (ParseException e) {
+            }
+        } else if (TIME_PATTERN.matcher(text).matches()) {
+            try {
+                return parseTime(text);
+            } catch (ParseException e) {
+            }
+        }
+
+        return unquote(text);
+    }
+
+    private static String unquote(String str) {
+        if (str.startsWith("'") && str.endsWith("'")) {
+            return str.substring(1, str.length() - 1).replace("''", "'");
+        }
+        return str;
+    }
+
+    private static Timestamp parseDateTime(String value) throws ParseException {
+        Matcher matcher = DATETIME_PATTERN.matcher(value);
+        if (!matcher.matches()) {
+            return null;
+        }
+        String dateTime = matcher.group(1);
+        String seconds = matcher.group(2);
+        String nanoSeconds = matcher.group(3);
+        String offset = matcher.group(6);
+        String utc = matcher.group(5);
+
+        if (utc != null && utc.equals("Z")) {
+            offset = "+00:00";
+        }
+
+        if (seconds == null) {
+            return new Timestamp(DATETIME_FORMAT.parse(dateTime).getTime());
+        }
+
+        if (nanoSeconds == null) {
+            return new Timestamp(DATETIME_WITH_SECONDS_FORMAT.parse(
+                    dateTime + seconds).getTime());
+        }
+
+        if (nanoSeconds.length() <= 4) {
+            if (offset == null) {
+                return new Timestamp(DATETIME_WITH_MILLIS_FORMAT.parse(dateTime + seconds + nanoSeconds).getTime());
+            }
+            return new Timestamp(DATETIMEOFFSET_WITH_MILLIS_FORMAT.parse(dateTime + seconds + nanoSeconds + offset)
+                    .getTime());
+        }
+        if (offset == null) {
+            return new Timestamp(adjustMillis(DATETIME_WITH_MILLIS_FORMAT
+                    .parse(dateTime + seconds + nanoSeconds.substring(0, 4))
+                    .getTime(), nanoSeconds));
+        }
+        return new Timestamp(adjustMillis(
+                DATETIME_WITH_MILLIS_FORMAT.parse(dateTime + seconds + nanoSeconds.substring(0, 4)
+                                + offset).getTime(), nanoSeconds));
+    }
+
+    private static long adjustMillis(long dateTime, final String nanoSeconds) {
+        return Math.round(Double.parseDouble("0." + nanoSeconds.substring(4))) == 0 ? dateTime : dateTime + 1;
+    }
+
+    private static Time parseTime(String value) throws ParseException {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(TIME_FORMAT.parse(value));
+        StringBuilder sb = new StringBuilder();
+        sb.append(calendar.get(Calendar.HOUR_OF_DAY)).append(":") //$NON-NLS-1$
+                .append(calendar.get(Calendar.MINUTE)).append(":") //$NON-NLS-1$
+                .append(calendar.get(Calendar.SECOND));
+        return java.sql.Time.valueOf(sb.toString());
+    }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/b25fc8c2/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MediaRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MediaRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MediaRequest.java
new file mode 100644
index 0000000..4d11260
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/MediaRequest.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ODataApplicationException;
+import org.apache.olingo.server.api.ODataResponse;
+import org.apache.olingo.server.api.ODataTranslatedException;
+import org.apache.olingo.server.api.ServiceMetadata;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+
+public class MediaRequest extends ServiceRequest {
+  private UriResourceEntitySet uriResourceEntitySet;
+
+  public MediaRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+    // POST will not be here, because the media is created as part of media
+    // entity creation
+    if (isGET()) {
+      handler.readMediaStream(this, new StreamResponse(response));
+    } else if (isPUT()) {
+      handler.updateMediaStream(this, getETag(), new StreamResponse(response));
+    } else if (isDELETE()) {
+      handler.deleteMediaStream(this, getETag(), new NoContentResponse(response));
+    }
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    // the request must specify the content type requested.
+    return getRequestContentType();
+  }
+
+  public EdmEntitySet getEntitySet() {
+    return this.uriResourceEntitySet.getEntitySet();
+  }
+
+  public EdmEntityType getEntityType() {
+    return this.uriResourceEntitySet.getEntitySet().getEntityType();
+  }
+
+  protected void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
+    this.uriResourceEntitySet = uriResourceEntitySet;
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    return isGET() || isPUT() || isDELETE();
+  }
+}