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/03/31 18:35:54 UTC

[08/11] olingo-odata4 git commit: OLINGO-573: New processing framework on server side with single interface with TripPin as example

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
----------------------------------------------------------------------
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
new file mode 100644
index 0000000..32bf26a
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/DataRequest.java
@@ -0,0 +1,769 @@
+/*
+ * 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.requests;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.LinkedList;
+import java.util.List;
+
+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.EdmBindingTarget;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmEntitySet;
+import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmNavigationProperty;
+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.UriInfo;
+import org.apache.olingo.server.api.uri.UriInfoCrossjoin;
+import org.apache.olingo.server.api.uri.UriInfoResource;
+import org.apache.olingo.server.api.uri.UriParameter;
+import org.apache.olingo.server.api.uri.UriResource;
+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;
+import org.apache.olingo.server.core.ContentNegotiator;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.ServiceRequest;
+import org.apache.olingo.server.core.responses.CountResponse;
+import org.apache.olingo.server.core.responses.EntityResponse;
+import org.apache.olingo.server.core.responses.EntitySetResponse;
+import org.apache.olingo.server.core.responses.NoContentResponse;
+import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
+import org.apache.olingo.server.core.responses.PropertyResponse;
+import org.apache.olingo.server.core.responses.StreamResponse;
+
+public class DataRequest extends ServiceRequest {
+  protected UriResourceEntitySet uriResourceEntitySet;
+  private boolean countRequest;
+  private UriResourceProperty uriResourceProperty;
+  private boolean valueRequest;
+  private final LinkedList<UriResourceNavigation> uriNavigations = new LinkedList<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;
+  }
+
+  public void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
+    this.uriResourceEntitySet = uriResourceEntitySet;
+    this.type = new EntityRequest();
+  }
+
+  public void setCrossJoin(UriInfoCrossjoin info) {
+    this.type = new CrossJoinRequest(info.getEntitySetNames());
+  }
+
+  public boolean isSingleton() {
+    return this.uriResourceSingleton != null;
+  }
+
+  public boolean isCollection() {
+    if (!this.uriNavigations.isEmpty()) {
+      return this.uriNavigations.getLast().isCollection();
+    }
+    return this.uriResourceEntitySet != null && this.uriResourceEntitySet.isCollection();
+  }
+
+  public EdmEntitySet getEntitySet() {
+    return this.uriResourceEntitySet.getEntitySet();
+  }
+
+  public boolean isCountRequest() {
+    return countRequest;
+  }
+
+  public 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;
+  }
+
+  public void setUriResourceProperty(UriResourceProperty uriResourceProperty) {
+    this.uriResourceProperty = uriResourceProperty;
+    this.type = new PropertyRequest();
+  }
+
+  public LinkedList<UriResourceNavigation> getNavigations() {
+    return this.uriNavigations;
+  }
+
+  public void addUriResourceNavigation(UriResourceNavigation uriResourceNavigation) {
+    this.uriNavigations.add(uriResourceNavigation);
+  }
+
+  public UriResourceSingleton getUriResourceSingleton() {
+    return this.uriResourceSingleton;
+  }
+
+  public void setUriResourceSingleton(UriResourceSingleton info) {
+    this.uriResourceSingleton = info;
+    this.type = new SingletonRequest();
+  }
+
+  public List<UriParameter> getKeyPredicates() {
+    if (this.uriResourceEntitySet != null) {
+      return this.uriResourceEntitySet.getKeyPredicates();
+    }
+    return null;
+  }
+
+  public boolean isReferenceRequest() {
+    return this.references;
+  }
+
+  public 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();
+  }
+
+  public 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, boolean references)
+      throws ContentNegotiatorException {
+    if (serilizerOptions.isAssignableFrom(PrimitiveSerializerOptions.class)) {
+      return (T) PrimitiveSerializerOptions.with().contextURL(contextUrl)
+          .facetsFrom(getUriResourceProperty().getProperty()).build();
+    }
+    return super.getSerializerOptions(serilizerOptions, contextUrl, references);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return type.getResponseContentType();
+  }
+
+  class EntityRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      // the create/update/delete to navigation property is done through references
+      // see # 11.4.6
+      if (!getNavigations().isEmpty() && !isGET()) {
+        return false;
+      }
+      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), false, response);
+
+      if (isGET()) {
+        if (isCollection()) {
+          handler.read(DataRequest.this,
+              EntitySetResponse.getInstance(DataRequest.this, getContextURL(odata), false, 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
+          entityResponse = EntityResponse.getInstance(DataRequest.this,
+              getContextURL(odata), false, response, getReturnRepresentation());
+          handler.createEntity(DataRequest.this, getEntityFromClient(), entityResponse);
+        } else {
+          handler.updateEntity(DataRequest.this, getEntityFromClient(), isPATCH(), getETag(),
+              entityResponse);
+        }
+      } else if (isPOST()) {
+        entityResponse = EntityResponse.getInstance(DataRequest.this,
+            getContextURL(odata), false, response, getReturnRepresentation());
+        handler.createEntity(DataRequest.this, getEntityFromClient(),entityResponse);
+      } 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(),
+          getKeyPredicates(), getUriInfo(), getNavigations(), 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;
+    }
+  }
+
+  /**
+   * Is NavigationProperty Reference.
+   */
+  class ReferenceRequest implements RequestType {
+
+    @Override
+    public boolean allowedMethod() {
+      // references are only allowed on the navigation properties
+      if (getNavigations().isEmpty()) {
+        return false;
+      }
+
+      // 11.4.6.1 - post allowed on only collection valued navigation
+      if (isPOST() && !getNavigations().getLast().isCollection()) {
+        return false;
+      }
+
+      // 11.4.6.3 - PUT allowed on single valued navigation
+      if (isPUT() && getNavigations().getLast().isCollection()) {
+        return false;
+      }
+
+      // No defined behavior in spec
+      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), true, response));
+        } else {
+          handler.read(DataRequest.this,
+              EntityResponse.getInstance(DataRequest.this, getContextURL(odata), true, response));
+        }
+      } else if (isDELETE()) {
+        // if this against the collection, user need to look at $id param for entity ref #11.4.6.2
+        String id = getQueryParameter("$id");
+        if (id == null) {
+          handler.deleteReference(DataRequest.this, null, getETag(), new NoContentResponse(
+              getServiceMetaData(), response));
+        } else {
+          try {
+            handler.deleteReference(DataRequest.this, new URI(id), getETag(), new NoContentResponse(
+                getServiceMetaData(), response));
+          } catch (URISyntaxException e) {
+            throw new DeserializerException("failed to read $id", e, MessageKeys.UNKOWN_CONTENT);
+          }
+        }
+      } else if (isPUT()) {
+        // note this is always against single reference
+        handler.updateReference(DataRequest.this, getETag(), getPayload().get(0), new NoContentResponse(
+            getServiceMetaData(), response));
+      } else if (isPOST()) {
+        // this needs to be against collection of references
+        handler.addReference(DataRequest.this, getETag(), getPayload(), new NoContentResponse(
+            getServiceMetaData(), response));
+      }
+    }
+
+    // http://docs.oasis-open.org/odata/odata-json-format/v4.0/errata02/os
+    // /odata-json-format-v4.0-errata02-os-complete.html#_Toc403940643
+    // The below code reads as property and converts to an URI
+    private List<URI> getPayload() throws DeserializerException {
+      ODataDeserializer deserializer = odata.createDeserializer(ODataFormat
+          .fromContentType(getRequestContentType()));
+      return deserializer.entityReferences(getODataRequest().getBody());
+    }
+
+    @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();
+
+      if (isGET()) {
+        if (isPropertyStream()) {
+          handler.read(DataRequest.this, new StreamResponse(getServiceMetaData(), response));
+        } else {
+          handler.read(DataRequest.this, buildResponse(response, edmProperty));
+        }
+      } else if (isPATCH()) {
+        handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), true,
+            getETag(), buildResponse(response, edmProperty));
+      } else if (isPUT()) {
+        if (isPropertyStream()) {
+          handler.upsertStreamProperty(DataRequest.this, getETag(), request.getBody(),
+              new NoContentResponse(getServiceMetaData(), response));
+        } else {
+          handler.updateProperty(DataRequest.this, getPropertyValueFromClient(edmProperty), false,
+              getETag(), buildResponse(response, edmProperty));
+        }
+      } else if (isDELETE()) {
+        if (isPropertyStream()) {
+          handler.upsertStreamProperty(DataRequest.this, getETag(), request.getBody(),
+              new NoContentResponse(getServiceMetaData(), response));
+        } else {
+          Property property = new PropertyImpl();
+          property.setName(edmProperty.getName());
+          property.setType(edmProperty.getType().getFullQualifiedName()
+              .getFullQualifiedNameAsString());
+          handler.updateProperty(DataRequest.this, property, false, getETag(),
+              buildResponse(response, edmProperty));
+        }
+      }
+    }
+
+    private PropertyResponse buildResponse(ODataResponse response, EdmProperty edmProperty)
+        throws ContentNegotiatorException, SerializerException {
+      PropertyResponse propertyResponse = PropertyResponse.getInstance(DataRequest.this, response,
+          edmProperty.getType(), getContextURL(odata), edmProperty.isCollection());
+      return 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()));
+      String navPath = buildNavPath(helper, getEntitySet().getEntityType(), getNavigations(), true);
+      if (navPath != null && !navPath.isEmpty()) {
+        builder.navOrPropertyPath(navPath+"/"+edmProperty.getName());
+      } else {
+        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() {
+      //part2-url-conventions # 4.2
+      if (isPropertyStream() && isGET()) {
+        return false;
+      }
+
+      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(), null, getUriInfo(), getNavigations(), 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), false, response));
+    }
+  }
+
+  class CrossJoinRequest implements RequestType {
+    private final List<String> entitySetNames;
+
+    public CrossJoinRequest(List<String> entitySetNames) {
+      this.entitySetNames = entitySetNames;
+    }
+
+    @Override
+    public boolean allowedMethod() {
+      return isGET();
+    }
+
+    @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 ODataTranslatedException, ODataApplicationException {
+      handler.crossJoin(DataRequest.this, this.entitySetNames, 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 {
+    // 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);
+  }
+
+  static ContextURL.Builder buildEntitySetContextURL(UriHelper helper,
+      EdmBindingTarget edmEntitySet, List<UriParameter> keyPredicates, UriInfo uriInfo,
+      LinkedList<UriResourceNavigation> navigations, boolean collectionReturn, boolean singleton)
+      throws SerializerException {
+
+    ContextURL.Builder builder = ContextURL.with().entitySetOrSingletonOrType(edmEntitySet.getName());
+    String select = helper.buildContextURLSelectList(edmEntitySet.getEntityType(),
+        uriInfo.getExpandOption(), uriInfo.getSelectOption());
+    if (!singleton) {
+      builder.suffix(collectionReturn ? null : Suffix.ENTITY);
+    }
+
+    builder.selectList(select);
+
+    final UriInfoResource resource = uriInfo.asUriInfoResource();
+    final List<UriResource> resourceParts = resource.getUriResourceParts();
+    final List<String> path = getPropertyPath(resourceParts);
+    String propertyPath = buildPropertyPath(path);
+    final String navPath = buildNavPath(helper, edmEntitySet.getEntityType(), navigations, collectionReturn);
+    if (navPath != null && !navPath.isEmpty()) {
+      if (keyPredicates != null) {
+        builder.keyPath(helper.buildContextURLKeyPredicate(keyPredicates));
+      }
+      if (propertyPath != null) {
+        propertyPath = navPath+"/"+propertyPath;
+      } else {
+        propertyPath = navPath;
+      }
+    }
+    builder.navOrPropertyPath(propertyPath);
+    return builder;
+  }
+
+  private static List<String> getPropertyPath(final List<UriResource> path) {
+    List<String> result = new LinkedList<String>();
+    int index = 1;
+    while (index < path.size() && path.get(index) instanceof UriResourceProperty) {
+      result.add(((UriResourceProperty) path.get(index)).getProperty().getName());
+      index++;
+    }
+    return result;
+  }
+
+  private static String buildPropertyPath(final List<String> path) {
+    StringBuilder result = new StringBuilder();
+    for (final String segment : path) {
+      result.append(result.length() == 0 ? "" : '/').append(segment); //$NON-NLS-1$
+    }
+    return result.length() == 0?null:result.toString();
+  }
+
+  static String buildNavPath(UriHelper helper, EdmEntityType rootType,
+      LinkedList<UriResourceNavigation> navigations, boolean includeLastPredicates)
+      throws SerializerException {
+    if (navigations.isEmpty()) {
+      return null;
+    }
+    StringBuilder sb = new StringBuilder();
+    boolean containsTarget = false;
+    EdmEntityType type = rootType;
+    for (UriResourceNavigation nav:navigations) {
+      String name = nav.getProperty().getName();
+      EdmNavigationProperty property = type.getNavigationProperty(name);
+      if (property.containsTarget()) {
+        containsTarget = true;
+      }
+      type = nav.getProperty().getType();
+    }
+
+    if (containsTarget) {
+      for (int i = 0; i < navigations.size(); i++) {
+        UriResourceNavigation nav = navigations.get(i);
+        if (i > 0) {
+          sb.append("/");
+        }
+        sb.append(nav.getProperty().getName());
+
+        boolean skipKeys = false;
+        if (navigations.size() == i+1 && !includeLastPredicates ) {
+          skipKeys = true;
+        }
+
+        if (!skipKeys && !nav.getKeyPredicates().isEmpty()) {
+          sb.append("(");
+          sb.append(helper.buildContextURLKeyPredicate(nav.getKeyPredicates()));
+          sb.append(")");
+        }
+
+        if (nav.getTypeFilterOnCollection() != null) {
+          sb.append("/")
+            .append(nav.getTypeFilterOnCollection().getFullQualifiedName().getFullQualifiedNameAsString());
+        } else if (nav.getTypeFilterOnEntry() != null) {
+          sb.append("/")
+            .append(nav.getTypeFilterOnEntry().getFullQualifiedName().getFullQualifiedNameAsString());
+        }
+      }
+    }
+    return sb.toString();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
new file mode 100644
index 0000000..a9f9341
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/FunctionRequest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.requests;
+
+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;
+import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.responses.EntityResponse;
+import org.apache.olingo.server.core.responses.EntitySetResponse;
+import org.apache.olingo.server.core.responses.PrimitiveValueResponse;
+import org.apache.olingo.server.core.responses.PropertyResponse;
+
+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), false, response));
+      } else {
+        handler.invoke(this, getODataRequest().getMethod(),
+            EntityResponse.getInstance(this, getContextURL(odata), false, 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;
+  }
+
+  public 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/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
new file mode 100644
index 0000000..a4a333a
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MediaRequest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.requests;
+
+import java.io.InputStream;
+import java.util.List;
+
+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.UriParameter;
+import org.apache.olingo.server.api.uri.UriResourceEntitySet;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.ServiceRequest;
+import org.apache.olingo.server.core.responses.NoContentResponse;
+import org.apache.olingo.server.core.responses.StreamResponse;
+
+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(getServiceMetaData(), response));
+    } else if (isPUT()) {
+      handler.upsertMediaStream(this, getETag(), getMediaStream(), new NoContentResponse(
+          getServiceMetaData(), response));
+    } else if (isDELETE()) {
+      handler.upsertMediaStream(this, getETag(), null, new NoContentResponse(getServiceMetaData(),
+          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();
+  }
+
+  public void setUriResourceEntitySet(UriResourceEntitySet uriResourceEntitySet) {
+    this.uriResourceEntitySet = uriResourceEntitySet;
+  }
+
+  public List<UriParameter> getKeyPredicates() {
+    if (this.uriResourceEntitySet != null) {
+      return this.uriResourceEntitySet.getKeyPredicates();
+    }
+    return null;
+  }
+
+  private InputStream getMediaStream() {
+    return this.request.getBody();
+  }
+
+  @Override
+  public boolean allowedMethod() {
+    return isGET() || isPUT() || isDELETE();
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
new file mode 100644
index 0000000..e2c5c54
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/MetadataRequest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.requests;
+
+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.serializer.RepresentationType;
+import org.apache.olingo.server.api.uri.UriInfoMetadata;
+import org.apache.olingo.server.core.ContentNegotiator;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.ServiceRequest;
+import org.apache.olingo.server.core.responses.MetadataResponse;
+
+public class MetadataRequest extends ServiceRequest {
+
+  public MetadataRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return ContentNegotiator.doContentNegotiation(this.uriInfo.getFormatOption(), this.request,
+        this.customContentType, RepresentationType.METADATA);
+  }
+
+  public UriInfoMetadata getUriInfoMetadata() {
+    return uriInfo.asUriInfoMetadata();
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+
+    handler.readMetadata(this, MetadataResponse.getInstance(this, response));
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/OperationRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/OperationRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/OperationRequest.java
new file mode 100644
index 0000000..1f1b194
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/OperationRequest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.requests;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.server.api.OData;
+import org.apache.olingo.server.api.ServiceMetadata;
+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.core.ContentNegotiator;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public abstract class OperationRequest extends ServiceRequest {
+
+  public OperationRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    if (!hasReturnType()) {
+      // this default content type
+      return ContentType.APPLICATION_OCTET_STREAM;
+    }
+
+    if (isReturnTypePrimitive()) {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_PRIMITIVE
+              : RepresentationType.PRIMITIVE);
+    } else if (isReturnTypeComplex()) {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_COMPLEX
+              : RepresentationType.COMPLEX);
+    } else {
+      return ContentNegotiator.doContentNegotiation(uriInfo.getFormatOption(), this.request,
+          getCustomContentTypeSupport(), isCollection() ? RepresentationType.COLLECTION_ENTITY
+              : RepresentationType.ENTITY);
+    }
+  }
+
+  public abstract boolean isBound();
+
+  public abstract boolean isCollection();
+
+  public abstract EdmReturnType getReturnType();
+
+  public abstract boolean hasReturnType();
+
+  public ContextURL getContextURL(OData odata) throws SerializerException {
+    if (!hasReturnType()) {
+      return null;
+    }
+
+    final UriHelper helper = odata.createUriHelper();
+
+    if (isReturnTypePrimitive() || isReturnTypeComplex()) {
+      // Part 1 {10.14, 10.14} since the function return properties does not
+      // represent a Entity property
+      ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
+      if (isCollection()) {
+        builder.asCollection();
+      }
+      return builder.build();
+    }
+
+    /*
+    // EdmTypeKind.ENTITY;
+    if (isBound()) {
+      // Bound means, we know the EnitySet of the return type. Part 1 {10.2,
+      // 10.3}
+      EdmEntitySet entitySet = this.uriResourceFunction.getFunctionImport().getReturnedEntitySet();
+      ContextURL.Builder builder = DataRequest.buildEntitySetContextURL(helper, entitySet,
+          this.uriInfo, isCollection(), false);
+      return builder.build();
+    }
+    */
+
+    // EdmTypeKind.ENTITY; Not Bound
+    // Here we do not know the EntitySet, then follow directions from
+    // Part-1{10.2. 10.3} to use
+    // {context-url}#{type-name}
+    ContextURL.Builder builder = ContextURL.with().type(getReturnType().getType());
+    if (isCollection()) {
+      builder.asCollection();
+    }
+    return builder.build();
+  }
+
+  public boolean isReturnTypePrimitive() {
+    return getReturnType().getType().getKind() == EdmTypeKind.PRIMITIVE;
+  }
+
+  public boolean isReturnTypeComplex() {
+    return getReturnType().getType().getKind() == EdmTypeKind.COMPLEX;
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
new file mode 100644
index 0000000..f99aaf5
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/requests/ServiceDocumentRequest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.requests;
+
+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.serializer.RepresentationType;
+import org.apache.olingo.server.core.ContentNegotiator;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceHandler;
+import org.apache.olingo.server.core.ServiceRequest;
+import org.apache.olingo.server.core.responses.ServiceDocumentResponse;
+
+public class ServiceDocumentRequest extends ServiceRequest {
+
+  public ServiceDocumentRequest(OData odata, ServiceMetadata serviceMetadata) {
+    super(odata, serviceMetadata);
+  }
+
+  @Override
+  public ContentType getResponseContentType() throws ContentNegotiatorException {
+    return ContentNegotiator.doContentNegotiation(getUriInfo().getFormatOption(),
+        getODataRequest(), getCustomContentTypeSupport(), RepresentationType.SERVICE);
+  }
+
+  @Override
+  public void execute(ServiceHandler handler, ODataResponse response)
+      throws ODataTranslatedException, ODataApplicationException {
+
+    if (!allowedMethod()) {
+      methodNotAllowed();
+    }
+    handler.readServiceDocument(this,
+        ServiceDocumentResponse.getInstace(this, response, getResponseContentType()));
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/CountResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/CountResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/CountResponse.java
new file mode 100644
index 0000000..f7cde33
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/CountResponse.java
@@ -0,0 +1,60 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+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(request.getServiceMetaData(), serializer, response,
+        request.getPreferences());
+  }
+
+  private CountResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
+      ODataResponse response, Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    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/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java
new file mode 100644
index 0000000..fd29bbd
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntityResponse.java
@@ -0,0 +1,140 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+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.ServiceMetadata;
+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.ContentNegotiatorException;
+import org.apache.olingo.server.core.ReturnRepresentation;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class EntityResponse extends ServiceResponse {
+  private final ReturnRepresentation returnRepresentation;
+  private final ODataSerializer serializer;
+  private final EntitySerializerOptions options;
+  private final ContentType responseContentType;
+
+  private EntityResponse(ServiceMetadata metadata, ODataResponse response,
+      ODataSerializer serializer, EntitySerializerOptions options, ContentType responseContentType,
+      Map<String, String> preferences, ReturnRepresentation returnRepresentation) {
+    super(metadata, response, preferences);
+    this.serializer = serializer;
+    this.options = options;
+    this.responseContentType = responseContentType;
+    this.returnRepresentation = returnRepresentation;
+  }
+
+  public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
+      boolean references, ODataResponse response, ReturnRepresentation returnRepresentation)
+      throws ContentNegotiatorException, SerializerException {
+    EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
+        contextURL, references);
+    return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
+        options, request.getResponseContentType(), request.getPreferences(), returnRepresentation);
+  }
+
+  public static EntityResponse getInstance(ServiceRequest request, ContextURL contextURL,
+      boolean references, ODataResponse response)
+      throws ContentNegotiatorException, SerializerException {
+    EntitySerializerOptions options = request.getSerializerOptions(EntitySerializerOptions.class,
+        contextURL, references);
+    return new EntityResponse(request.getServiceMetaData(), response, request.getSerializer(),
+        options, request.getResponseContentType(), request.getPreferences(), null);
+  }
+
+  // write single entity
+  public void writeReadEntity(EdmEntityType entityType, Entity entity) throws SerializerException {
+
+    assert (!isClosed());
+
+    if (entity == null) {
+      writeNotFound(true);
+      return;
+    }
+
+    // write the entity to response
+    this.response.setContent(this.serializer.entity(this.metadata, 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);
+
+    // Note that if media written just like Stream, but on entity URL
+
+    // 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(this.metadata, 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();
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java
new file mode 100644
index 0000000..40276d2
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/EntitySetResponse.java
@@ -0,0 +1,82 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.EntityCollectionSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class EntitySetResponse extends ServiceResponse {
+  private final ODataSerializer serializer;
+  private final EntityCollectionSerializerOptions options;
+  private final ContentType responseContentType;
+
+  private EntitySetResponse(ServiceMetadata metadata, ODataResponse response, ODataSerializer serializer,
+      EntityCollectionSerializerOptions options,
+      ContentType responseContentType, Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.serializer = serializer;
+    this.options = options;
+    this.responseContentType = responseContentType;
+  }
+
+  public static EntitySetResponse getInstance(ServiceRequest request, ContextURL contextURL,
+      boolean referencesOnly, ODataResponse response) throws ContentNegotiatorException, SerializerException {
+    EntityCollectionSerializerOptions options = request.getSerializerOptions(
+        EntityCollectionSerializerOptions.class, contextURL, referencesOnly);
+    return new EntitySetResponse(request.getServiceMetaData(),response, request.getSerializer(), options,
+        request.getResponseContentType(), request.getPreferences());
+  }
+
+  // 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;
+    }
+
+    // write the whole collection to response
+    this.response.setContent(this.serializer.entityCollection(metadata, entityType, entitySet, this.options));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java
new file mode 100644
index 0000000..055c0b0
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/MetadataResponse.java
@@ -0,0 +1,62 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class MetadataResponse extends ServiceResponse {
+  private final ODataSerializer serializer;
+  private final ContentType responseContentType;
+
+  public static MetadataResponse getInstance(ServiceRequest request,
+      ODataResponse response) throws ContentNegotiatorException, SerializerException {
+    return new MetadataResponse(request.getServiceMetaData(), response, request.getSerializer(),
+        request.getResponseContentType(), request.getPreferences());
+  }
+
+  private MetadataResponse(ServiceMetadata metadata, ODataResponse response, ODataSerializer serializer,
+      ContentType responseContentType, Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.serializer = serializer;
+    this.responseContentType = responseContentType;
+  }
+
+  public void writeMetadata()throws ODataTranslatedException {
+    assert (!isClosed());
+    this.response.setContent(this.serializer.metadataDocument(this.metadata));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/NoContentResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/NoContentResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/NoContentResponse.java
new file mode 100644
index 0000000..eb16365
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/NoContentResponse.java
@@ -0,0 +1,100 @@
+/*
+ * 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.responses;
+
+import java.util.Collections;
+
+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.ServiceMetadata;
+
+public class NoContentResponse extends ServiceResponse {
+
+  public NoContentResponse(ServiceMetadata metadata, ODataResponse response) {
+    super(metadata, response, Collections.EMPTY_MAP);
+  }
+
+  // 200
+  public void writeOK() {
+    this.response.setStatusCode(HttpStatusCode.OK.getStatusCode());
+    close();
+  }
+
+  // 201
+  public void writeCreated() {
+    this.response.setStatusCode(HttpStatusCode.CREATED.getStatusCode());
+    close();
+  }
+
+  // 202
+  public void writeAccepted() {
+    this.response.setStatusCode(HttpStatusCode.ACCEPTED.getStatusCode());
+    close();
+  }
+
+  // 204
+  public void writeNoContent() {
+    writeNoContent(true);
+  }
+
+  // 304
+  public void writeNotModified() {
+    this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
+    close();
+  }
+
+  // error response codes
+
+  // 404
+  public void writeNotFound() {
+    writeNotFound(true);
+  }
+
+  // 501
+  public void writeNotImplemented() {
+    this.response.setStatusCode(HttpStatusCode.NOT_IMPLEMENTED.getStatusCode());
+    close();
+  }
+
+  // 405
+  public void writeMethodNotAllowed() {
+    this.response.setStatusCode(HttpStatusCode.METHOD_NOT_ALLOWED.getStatusCode());
+    close();
+  }
+
+  // 410
+  public void writeGone() {
+    this.response.setStatusCode(HttpStatusCode.GONE.getStatusCode());
+    close();
+  }
+
+  // 412
+  public void writePreConditionFailed() {
+    this.response.setStatusCode(HttpStatusCode.PRECONDITION_FAILED.getStatusCode());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java
new file mode 100644
index 0000000..005bfca
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PrimitiveValueResponse.java
@@ -0,0 +1,105 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmProperty;
+import org.apache.olingo.commons.api.edm.EdmReturnType;
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.FixedFormatSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveValueSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class PrimitiveValueResponse extends ServiceResponse {
+  private final boolean returnCollection;
+  private EdmProperty type;
+  private EdmReturnType returnType;
+  private final FixedFormatSerializer serializer;
+
+  public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
+      boolean collection, EdmProperty type) {
+    FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
+    return new PrimitiveValueResponse(request.getServiceMetaData(), serializer, response,
+        collection, type, request.getPreferences());
+  }
+
+  public static PrimitiveValueResponse getInstance(ServiceRequest request, ODataResponse response,
+      boolean collection, EdmReturnType type) {
+    FixedFormatSerializer serializer = request.getOdata().createFixedFormatSerializer();
+    return new PrimitiveValueResponse(request.getServiceMetaData(), serializer, response,
+        collection, type, request.getPreferences());
+  }
+
+  private PrimitiveValueResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
+      ODataResponse response, boolean collection, EdmProperty type, Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.returnCollection = collection;
+    this.type = type;
+    this.serializer = serializer;
+  }
+
+  private PrimitiveValueResponse(ServiceMetadata metadata, FixedFormatSerializer serializer,
+      ODataResponse response, boolean collection, EdmReturnType type,
+      Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.returnCollection = collection;
+    this.returnType = type;
+    this.serializer = serializer;
+  }
+
+  public void write(Object value) throws SerializerException {
+    if (value == null) {
+      writeNoContent(true);
+      return;
+    }
+
+    if (this.type != null) {
+      PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
+          .facetsFrom(this.type).build();
+
+      this.response.setContent(this.serializer.primitiveValue((EdmPrimitiveType) this.type.getType(),
+          value, options));
+    } else {
+      PrimitiveValueSerializerOptions options = PrimitiveValueSerializerOptions.with()
+          .nullable(this.returnType.isNullable()).maxLength(this.returnType.getMaxLength())
+          .precision(this.returnType.getPrecision()).scale(this.returnType.getScale()).build();
+      this.response.setContent(this.serializer.primitiveValue(
+          (EdmPrimitiveType) this.returnType.getType(), value, options));
+    }
+
+    writeOK(HttpContentType.TEXT_PLAIN);
+  }
+
+  public boolean isReturnCollection() {
+    return returnCollection;
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java
new file mode 100644
index 0000000..e6b951d
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/PropertyResponse.java
@@ -0,0 +1,144 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+import org.apache.olingo.commons.api.data.ContextURL;
+import org.apache.olingo.commons.api.data.Property;
+import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmPrimitiveType;
+import org.apache.olingo.commons.api.edm.EdmType;
+import org.apache.olingo.commons.api.edm.constants.EdmTypeKind;
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.ComplexSerializerOptions;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.PrimitiveSerializerOptions;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class PropertyResponse extends ServiceResponse {
+  private PrimitiveSerializerOptions primitiveOptions;
+  private ComplexSerializerOptions complexOptions;
+  private final ContentType responseContentType;
+  private final ODataSerializer serializer;
+  private final boolean collection;
+
+  public static PropertyResponse getInstance(ServiceRequest request, ODataResponse response,
+      EdmType edmType, ContextURL contextURL, boolean collection) throws ContentNegotiatorException,
+      SerializerException {
+    if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
+      PrimitiveSerializerOptions options = request.getSerializerOptions(
+          PrimitiveSerializerOptions.class, contextURL, false);
+      ContentType type = request.getResponseContentType();
+      return new PropertyResponse(request.getServiceMetaData(), request.getSerializer(), response,
+          options, type, collection, request.getPreferences());
+    }
+    ComplexSerializerOptions options = request.getSerializerOptions(ComplexSerializerOptions.class,
+        contextURL, false);
+    ContentType type = request.getResponseContentType();
+    return new PropertyResponse(request.getServiceMetaData(), request.getSerializer(), response,
+        options, type, collection, request.getPreferences());
+  }
+
+  private PropertyResponse(ServiceMetadata metadata, ODataSerializer serializer,
+      ODataResponse response, PrimitiveSerializerOptions options, ContentType contentType,
+      boolean collection, Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.serializer = serializer;
+    this.primitiveOptions = options;
+    this.responseContentType = contentType;
+    this.collection = collection;
+  }
+
+  private PropertyResponse(ServiceMetadata metadata, ODataSerializer serializer, ODataResponse response,
+      ComplexSerializerOptions options, ContentType contentType, boolean collection,
+      Map<String, String> preferences) {
+    super(metadata, response, preferences);
+    this.serializer = serializer;
+    this.complexOptions = options;
+    this.responseContentType = contentType;
+    this.collection = collection;
+  }
+
+  public void writeProperty(EdmType edmType, Property property) throws SerializerException {
+    assert (!isClosed());
+
+    if (property == null) {
+      writeNotFound(true);
+      return;
+    }
+
+    if (property.getValue() == null) {
+      writeNoContent(true);
+      return;
+    }
+
+    if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
+      writePrimitiveProperty((EdmPrimitiveType) edmType, property);
+    } else {
+      writeComplexProperty((EdmComplexType) edmType, property);
+    }
+  }
+
+  private void writeComplexProperty(EdmComplexType type, Property property)
+      throws SerializerException {
+    if (this.collection) {
+      this.response.setContent(this.serializer.complexCollection(this.metadata, type, property,
+          this.complexOptions));
+    } else {
+      this.response.setContent(this.serializer.complex(this.metadata, type, property,
+          this.complexOptions));
+    }
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  private void writePrimitiveProperty(EdmPrimitiveType type, Property property)
+      throws SerializerException {
+    if(this.collection) {
+      this.response.setContent(this.serializer.primitiveCollection(type, property, this.primitiveOptions));
+    } else {
+      this.response.setContent(this.serializer.primitive(type, property, this.primitiveOptions));
+    }
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+
+  public void writePropertyUpdated() {
+    // spec says just success response; so either 200 or 204. 200 typically has
+    // payload
+    writeNoContent(true);
+  }
+
+  public void writePropertyDeleted() {
+    writeNoContent(true);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/2b73abcc/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java
new file mode 100644
index 0000000..86c420b
--- /dev/null
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceDocumentResponse.java
@@ -0,0 +1,63 @@
+/*
+ * 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.responses;
+
+import java.util.Map;
+
+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.ServiceMetadata;
+import org.apache.olingo.server.api.serializer.ODataSerializer;
+import org.apache.olingo.server.api.serializer.SerializerException;
+import org.apache.olingo.server.core.ContentNegotiatorException;
+import org.apache.olingo.server.core.ServiceRequest;
+
+public class ServiceDocumentResponse extends ServiceResponse {
+  private final ODataSerializer serializer;
+  private final ContentType responseContentType;
+
+  public static ServiceDocumentResponse getInstace(ServiceRequest request, ODataResponse respose,
+      ContentType responseContentType) throws ContentNegotiatorException, SerializerException {
+    return new ServiceDocumentResponse(request.getServiceMetaData(), respose,
+        request.getSerializer(), responseContentType, request.getPreferences());
+  }
+
+  private ServiceDocumentResponse(ServiceMetadata metadata, ODataResponse respose,
+      ODataSerializer serializer, ContentType responseContentType, Map<String, String> preferences) {
+    super(metadata, respose, preferences);
+    this.serializer = serializer;
+    this.responseContentType = responseContentType;
+  }
+
+  public void writeServiceDocument(String serviceRoot)
+      throws ODataTranslatedException {
+    assert (!isClosed());
+    this.response.setContent(this.serializer.serviceDocument(this.metadata.getEdm(), serviceRoot));
+    writeOK(this.responseContentType.toContentTypeString());
+    close();
+  }
+
+  @Override
+  public void accepts(ServiceResponseVisior visitor) throws ODataTranslatedException,
+      ODataApplicationException {
+    visitor.visit(this);
+  }
+}