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 2016/06/02 17:21:56 UTC

[3/3] olingo-odata4 git commit: OLINGO-567: Support for odata.metadata=full

OLINGO-567: Support for odata.metadata=full


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

Branch: refs/heads/OLINGO-567-rareddy
Commit: eaceb01d1ae00f664cef6811f11a303f8771db8c
Parents: 2675f8f
Author: Ramesh Reddy <ra...@jboss.org>
Authored: Mon May 23 14:44:12 2016 -0500
Committer: Ramesh Reddy <ra...@jboss.org>
Committed: Thu Jun 2 12:19:55 2016 -0500

----------------------------------------------------------------------
 .../fit/tecsvc/client/BoundOpearionITCase.java  | 149 ++++++++
 .../tecsvc/client/EntityWithStreamITCase.java   | 112 ++++++
 .../fit/tecsvc/http/BasicStreamITCase.java      |   2 +-
 .../client/api/domain/ClientEntitySet.java      |  15 +
 .../olingo/client/api/domain/ClientLink.java    |  25 +-
 .../client/api/domain/ClientLinkType.java       |   9 +
 .../client/api/domain/ClientObjectFactory.java  |   6 +-
 .../client/api/domain/ClientProperty.java       |  17 +
 .../core/domain/ClientComplexValueImpl.java     |   1 +
 .../client/core/domain/ClientEntityImpl.java    |   1 +
 .../client/core/domain/ClientEntitySetImpl.java |  26 ++
 .../core/domain/ClientObjectFactoryImpl.java    |  18 +-
 .../client/core/domain/ClientPropertyImpl.java  |  27 +-
 .../core/serialization/AtomDeserializer.java    |   4 +-
 .../core/serialization/JsonDeserializer.java    |   1 +
 .../serialization/JsonEntityDeserializer.java   |  49 ++-
 .../JsonEntitySetDeserializer.java              |  16 +-
 .../serialization/JsonPropertyDeserializer.java |  15 +-
 .../core/serialization/ODataBinderImpl.java     |  26 +-
 .../apache/olingo/commons/api/Constants.java    |   4 +
 .../api/data/AbstractEntityCollection.java      |   3 +
 .../commons/api/data/EntityCollection.java      |  13 +-
 .../olingo/commons/api/data/Operation.java      |  20 +-
 .../olingo/commons/api/data/Property.java       |  13 +
 .../core/edm/primitivetype/EdmStream.java       |   7 +
 .../olingo/server/core/ServiceRequest.java      |   9 +-
 .../olingo/server/core/ContentNegotiator.java   |   1 +
 .../apache/olingo/server/core/ODataImpl.java    |   3 +-
 .../deserializer/xml/ODataXmlDeserializer.java  |   3 +-
 .../serializer/json/ODataJsonSerializer.java    | 179 +++++++--
 .../serializer/utils/ContentTypeHelper.java     |   5 +
 .../core/serializer/xml/ODataXmlSerializer.java |  18 +-
 .../server/core/ContentNegotiatorTest.java      |   1 -
 .../olingo/server/core/ODataImplTest.java       |   7 +-
 .../olingo/server/tecsvc/data/ActionData.java   |  14 +-
 .../olingo/server/tecsvc/data/DataCreator.java  | 232 ++++++++++--
 .../olingo/server/tecsvc/data/DataProvider.java |   6 +-
 .../olingo/server/tecsvc/data/FunctionData.java |   5 +
 .../processor/TechnicalEntityProcessor.java     |   7 +
 .../ExpandSystemQueryOptionHandler.java         |   2 +-
 .../server/tecsvc/provider/ActionProvider.java  |  22 +-
 .../tecsvc/provider/ContainerProvider.java      |   5 +
 .../tecsvc/provider/EntityTypeProvider.java     |  13 +-
 .../tecsvc/provider/FunctionProvider.java       |  86 ++++-
 .../tecsvc/provider/PropertyProvider.java       |   6 +
 .../json/ODataJsonSerializerTest.java           | 360 ++++++++++++++++++-
 .../serializer/xml/ODataXmlSerializerTest.java  | 188 +++++++++-
 47 files changed, 1628 insertions(+), 123 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java
new file mode 100644
index 0000000..a37ab49
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/BoundOpearionITCase.java
@@ -0,0 +1,149 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.request.retrieve.ODataPropertyRequest;
+import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.api.domain.ClientAnnotation;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientOperation;
+import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+
+public class BoundOpearionITCase extends AbstractParamTecSvcITCase {
+  private static final ContentType CONTENT_TYPE_JSON_FULL_METADATA =
+      ContentType.create(ContentType.JSON, ContentType.PARAMETER_ODATA_METADATA, 
+          ContentType.VALUE_ODATA_METADATA_FULL);
+
+  @Parameterized.Parameters(name = "{0}")
+  public static List<ContentType[]> parameters() {
+    ContentType[] a = new ContentType[1];
+    a[0] = CONTENT_TYPE_JSON_FULL_METADATA;
+    ArrayList<ContentType[]> type = new ArrayList<ContentType[]>();
+    type.add(a);
+    return type;
+  }  
+  
+  @Test
+  public void readEntitySetOperation() {
+    ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
+        .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
+            .appendEntitySetSegment("ESAllPrim").build());    
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertEquals("application/json; odata.metadata=full", response.getContentType());
+
+    final ClientEntitySet entitySet = response.getBody();
+    assertNotNull(entitySet);
+
+    assertNull(entitySet.getCount());
+    assertNull(entitySet.getNext());
+    assertEquals(Collections.<ClientAnnotation> emptyList(), entitySet.getAnnotations());
+    assertNull(entitySet.getDeltaLink());
+
+    List<ClientOperation> ecOperations = entitySet.getOperations();
+    assertNotNull(ecOperations);
+    assertEquals(4, ecOperations.size());
+    
+    assertEquals("#olingo.odata.test1.BAESAllPrimRTETAllPrim", ecOperations.get(0).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BAESAllPrimRTETAllPrim", ecOperations.get(0).getTitle());
+    assertEquals("/ESAllPrim/olingo.odata.test1.BAESAllPrimRTETAllPrim", 
+        ecOperations.get(0).getTarget().toASCIIString());    
+    
+    assertEquals("#olingo.odata.test1.BAESAllPrimRT", ecOperations.get(1).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BAESAllPrimRT", ecOperations.get(1).getTitle());
+    assertEquals("/ESAllPrim/olingo.odata.test1.BAESAllPrimRT", 
+        ecOperations.get(1).getTarget().toASCIIString());
+    
+    
+    assertEquals("#olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(2).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(2).getTitle());
+    assertEquals("/ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim", 
+        ecOperations.get(2).getTarget().toASCIIString());
+    
+    assertEquals("#olingo.odata.test1.BFNESAllPrimRTCTAllPrim(Param2)", ecOperations.get(3).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BFNESAllPrimRTCTAllPrim", ecOperations.get(3).getTitle());
+    assertEquals("/ESAllPrim/olingo.odata.test1.BFNESAllPrimRTCTAllPrim(Param2=@Param2)", 
+        ecOperations.get(3).getTarget().toASCIIString());
+    
+    final List<ClientEntity> entities = entitySet.getEntities();
+    assertNotNull(entities);
+    assertEquals(3, entities.size());
+    
+    ClientEntity entity = entities.get(0);
+    assertNotNull(entity);
+    List<ClientOperation> operations = entity.getOperations();
+    assertNotNull(operations);
+    assertEquals(1, operations.size());
+    
+    assertEquals("#olingo.odata.test1.BAETAllPrimRT", operations.get(0).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BAETAllPrimRT", operations.get(0).getTitle());
+    assertEquals("/ESAllPrim(32767)/olingo.odata.test1.BAETAllPrimRT", 
+        operations.get(0).getTarget().toASCIIString());              
+  } 
+  
+  @Test
+  public void readComplexPropertyOperation() {
+    ODataPropertyRequest<ClientProperty> request = getClient().getRetrieveRequestFactory()
+        .getPropertyRequest(getClient().newURIBuilder(SERVICE_URI)
+            .appendEntitySetSegment("ESCompAllPrim")
+            .appendKeySegment(32767)
+            .appendPropertySegment("PropertyComp")
+            .build());    
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientProperty> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertEquals("application/json; odata.metadata=full", response.getContentType());
+
+    final ClientProperty property = response.getBody();
+    assertNotNull(property);
+    
+    List<ClientOperation> operations = property.getOperations();
+    assertNotNull(operations);
+    
+    assertEquals(1, operations.size());
+    
+    assertEquals("#olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", operations.get(0).getMetadataAnchor());
+    assertEquals("olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", operations.get(0).getTitle());
+    assertEquals("PropertyComp/olingo.odata.test1.BFCColCTAllPrimRTESAllPrim", 
+        operations.get(0).getTarget().toASCIIString());                  
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java
new file mode 100644
index 0000000..a99f02c
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/client/EntityWithStreamITCase.java
@@ -0,0 +1,112 @@
+/*
+ * 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.fit.tecsvc.client;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.olingo.client.api.communication.request.retrieve.ODataEntitySetRequest;
+import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
+import org.apache.olingo.client.api.domain.ClientAnnotation;
+import org.apache.olingo.client.api.domain.ClientEntity;
+import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientLink;
+import org.apache.olingo.client.api.domain.ClientLinkType;
+import org.apache.olingo.client.api.domain.ClientProperty;
+import org.apache.olingo.commons.api.Constants;
+import org.apache.olingo.commons.api.format.ContentType;
+import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.junit.Test;
+import org.junit.runners.Parameterized;
+
+public class EntityWithStreamITCase extends AbstractParamTecSvcITCase {
+  private static final ContentType CONTENT_TYPE_JSON_FULL_METADATA =
+      ContentType.create(ContentType.JSON, ContentType.PARAMETER_ODATA_METADATA, 
+          ContentType.VALUE_ODATA_METADATA_FULL);
+  private static final String PROPERTY_INT16 = "PropertyInt16";
+
+  @Parameterized.Parameters(name = "{0}")
+  public static List<ContentType[]> parameters() {
+    ContentType[] a = new ContentType[1];
+    a[0] = CONTENT_TYPE_JSON_FULL_METADATA;
+    ArrayList<ContentType[]> type = new ArrayList<ContentType[]>();
+    type.add(a);
+    return type;
+  }  
+  
+  @Test
+  public void readEntitySetWithStreamProperty() {
+    ODataEntitySetRequest<ClientEntitySet> request = getClient().getRetrieveRequestFactory()
+        .getEntitySetRequest(getClient().newURIBuilder(SERVICE_URI)
+            .appendEntitySetSegment("ESWithStream").build());    
+    assertNotNull(request);
+    setCookieHeader(request);
+
+    final ODataRetrieveResponse<ClientEntitySet> response = request.execute();
+    saveCookieHeader(response);
+    assertEquals(HttpStatusCode.OK.getStatusCode(), response.getStatusCode());
+    assertEquals("application/json; odata.metadata=full", response.getContentType());
+
+    final ClientEntitySet entitySet = response.getBody();
+    assertNotNull(entitySet);
+
+    assertNull(entitySet.getCount());
+    assertNull(entitySet.getNext());
+    assertEquals(Collections.<ClientAnnotation> emptyList(), entitySet.getAnnotations());
+    assertNull(entitySet.getDeltaLink());
+
+    final List<ClientEntity> entities = entitySet.getEntities();
+    assertNotNull(entities);
+    assertEquals(2, entities.size());
+    
+    ClientEntity entity = entities.get(0);
+    assertNotNull(entity);
+    ClientProperty property = entity.getProperty(PROPERTY_INT16);
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(Short.MAX_VALUE, property.getPrimitiveValue().toValue());
+    
+    ClientLink link = entity.getMediaEditLinks().get(0);
+    assertNotNull(link);
+    
+    assertEquals("/readLink", link.getLink().toASCIIString());
+    assertEquals(ClientLinkType.MEDIA_READ, link.getType());
+    
+    entity = entities.get(1);
+    assertNotNull(entity);
+    property = entity.getProperty(PROPERTY_INT16);
+    assertNotNull(property);
+    assertNotNull(property.getPrimitiveValue());
+    assertShortOrInt(7, property.getPrimitiveValue().toValue());
+    
+    assertEquals(1, entity.getMediaEditLinks().size());
+    
+    link = entity.getMediaEditLinks().get(0);
+    assertNotNull(link);
+    assertEquals("http://mediaserver:1234/editLink", link.getLink().toASCIIString());
+    assertEquals(ClientLinkType.fromString(Constants.NS_MEDIA_EDIT_LINK_REL, "image/jpeg").name(), 
+        link.getType().name());
+    assertEquals("eTag", link.getMediaETag());    
+  } 
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
index 566cb39..33eb4f5 100644
--- a/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/tecsvc/http/BasicStreamITCase.java
@@ -70,7 +70,7 @@ public class BasicStreamITCase extends AbstractBaseTestITCase {
     assertEquals(ContentType.APPLICATION_XML, ContentType.create(connection.getHeaderField(HttpHeader.CONTENT_TYPE)));
 
     final String content = IOUtils.toString(connection.getInputStream());
-
+System.out.println(content);
     assertTrue(content.contains("<m:element>Streamed-Employee1@company.example</m:element>" +
             "<m:element>Streamed-Employee2@company.example</m:element>" +
             "<m:element>Streamed-Employee3@company.example</m:element>"));

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java
index 6b5f1f1..e1664be 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientEntitySet.java
@@ -68,4 +68,19 @@ public interface ClientEntitySet extends ClientInvokeResult, ClientAnnotatable {
    * @param deltaLink delta link.
    */
   void setDeltaLink(URI deltaLink);
+  
+  /**
+   * Searches for operation with given title.
+   * 
+   * @param title operation to look for
+   * @return operation if found with given title, <tt>null</tt> otherwise
+   */
+  ClientOperation getOperation(String title);
+
+  /**
+   * Gets operations.
+   * 
+   * @return operations.
+   */
+  List<ClientOperation> getOperations();  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java
index 5307165..35f89fb 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLink.java
@@ -36,7 +36,9 @@ public class ClientLink extends ClientItem implements ClientAnnotatable {
     private ClientLinkType type;
 
     private String title;
-
+    
+    private String mediaETag;
+    
     public Builder setURI(final URI uri) {
       this.uri = uri;
       return this;
@@ -57,8 +59,13 @@ public class ClientLink extends ClientItem implements ClientAnnotatable {
       return this;
     }
 
+    public Builder setEtag(final String eTag) {
+      this.mediaETag= eTag;
+      return this;
+    }
+
     public ClientLink build() {
-      return new ClientLink(uri, type, title);
+      return new ClientLink(uri, type, title, mediaETag);
     }
   }
 
@@ -110,10 +117,15 @@ public class ClientLink extends ClientItem implements ClientAnnotatable {
    * @param title title.
    */
   public ClientLink(final URI uri, final ClientLinkType type, final String title) {
+    this(uri, type, title, null);
+  }
+  
+  public ClientLink(final URI uri, final ClientLinkType type, final String title, final String eTag) {
     super(title);
 
     this.type = type;
     setLink(uri);
+    this.mediaETag = eTag;
 
     switch (this.type) {
     case ASSOCIATION:
@@ -126,12 +138,19 @@ public class ClientLink extends ClientItem implements ClientAnnotatable {
       break;
 
     case MEDIA_EDIT:
+      rel = Constants.NS_MEDIA_EDIT_LINK_REL + title;
+      break;
+
+    case MEDIA_READ:
+      rel = Constants.NS_MEDIA_READ_LINK_REL + title;
+      break;
+      
     default:
       rel = Constants.NS_MEDIA_EDIT_LINK_REL + title;
       break;
     }
   }
-
+  
   /**
    * Constructor.
    * 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java
index 2b89b95..ff1f6f4 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientLinkType.java
@@ -42,6 +42,11 @@ public enum ClientLinkType {
    * Media-edit link.
    */
   MEDIA_EDIT("*/*"),
+  
+  /**
+   * Media-read link
+   */
+  MEDIA_READ("*/*"),
 
   /**
    * Entity binding link.
@@ -80,6 +85,10 @@ public enum ClientLinkType {
     if (rel != null && rel.startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) {
       return MEDIA_EDIT.setType(type == null || type.isEmpty() ? "*/*" : type);
     }
+    
+    if (rel != null && rel.startsWith(Constants.NS_MEDIA_READ_LINK_REL)) {
+      return MEDIA_READ.setType(type == null || type.isEmpty() ? "*/*" : type);
+    }
 
     if (ClientLinkType.ENTITY_NAVIGATION.type.equals(type)) {
       return ENTITY_NAVIGATION;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java
index 5bf1e08..774bd94 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientObjectFactory.java
@@ -105,8 +105,10 @@ public interface ClientObjectFactory {
 
   ClientLink newAssociationLink(String name, URI link);
 
-  ClientLink newMediaEditLink(String name, URI link);
-
+  ClientLink newMediaEditLink(String name, URI link, String type, String eTag);
+  
+  ClientLink newMediaReadLink(String name, URI link, String type, String eTag);
+  
   ClientPrimitiveValue.Builder newPrimitiveValueBuilder();
 
   ClientEnumValue newEnumValue(String typeName, String value);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java
index 2e5dde8..8e14c94 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/domain/ClientProperty.java
@@ -18,6 +18,8 @@
  */
 package org.apache.olingo.client.api.domain;
 
+import java.util.List;
+
 /**
  * OData entity property.
  */
@@ -29,4 +31,19 @@ public interface ClientProperty extends ClientInvokeResult, ClientAnnotatable, C
    * @return property name.
    */
   String getName();
+  
+  /**
+   * Searches for operation with given title.
+   * 
+   * @param title operation to look for
+   * @return operation if found with given title, <tt>null</tt> otherwise
+   */
+  ClientOperation getOperation(String title);
+
+  /**
+   * Gets operations.
+   * 
+   * @return operations.
+   */
+  List<ClientOperation> getOperations();  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java
index 9cd083e..1338a92 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientComplexValueImpl.java
@@ -89,6 +89,7 @@ public class ClientComplexValueImpl extends AbstractClientValue implements Clien
       break;
 
     case MEDIA_EDIT:
+    case MEDIA_READ:
       throw new IllegalArgumentException("Complex values cannot have media links!");
 
     default:

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java
index 4426e03..76ee05f 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntityImpl.java
@@ -160,6 +160,7 @@ public class ClientEntityImpl extends AbstractClientPayload implements ClientEnt
         break;
 
       case MEDIA_EDIT:
+      case MEDIA_READ:
         result = mediaEditLinks.contains(link) ? false : mediaEditLinks.add(link);
         break;
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java
index 21e13b4..a979196 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientEntitySetImpl.java
@@ -26,6 +26,7 @@ import org.apache.olingo.client.api.domain.AbstractClientPayload;
 import org.apache.olingo.client.api.domain.ClientAnnotation;
 import org.apache.olingo.client.api.domain.ClientEntity;
 import org.apache.olingo.client.api.domain.ClientEntitySet;
+import org.apache.olingo.client.api.domain.ClientOperation;
 
 public class ClientEntitySetImpl extends AbstractClientPayload implements ClientEntitySet {
 
@@ -46,6 +47,8 @@ public class ClientEntitySetImpl extends AbstractClientPayload implements Client
   private final List<ClientEntity> entities = new ArrayList<ClientEntity>();
 
   private final List<ClientAnnotation> annotations = new ArrayList<ClientAnnotation>();
+  
+  private final List<ClientOperation> operations = new ArrayList<ClientOperation>();
 
   public ClientEntitySetImpl() {
     super(null);
@@ -93,6 +96,29 @@ public class ClientEntitySetImpl extends AbstractClientPayload implements Client
   }
 
   @Override
+  public ClientOperation getOperation(final String title) {
+    ClientOperation result = null;
+    for (ClientOperation operation : operations) {
+      if (title.equals(operation.getTitle())) {
+        result = operation;
+        break;
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Gets operations.
+   *
+   * @return operations.
+   */
+  @Override
+  public List<ClientOperation> getOperations() {
+    return operations;
+  }
+  
+  @Override
   public int hashCode() {
     final int prime = 31;
     int result = super.hashCode();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java
index 7bca6c3..5914cee 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientObjectFactoryImpl.java
@@ -35,6 +35,7 @@ import org.apache.olingo.client.api.domain.ClientPrimitiveValue;
 import org.apache.olingo.client.api.domain.ClientProperty;
 import org.apache.olingo.client.api.domain.ClientSingleton;
 import org.apache.olingo.client.api.domain.ClientValue;
+import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 
 public class ClientObjectFactoryImpl implements ClientObjectFactory {
@@ -95,11 +96,20 @@ public class ClientObjectFactoryImpl implements ClientObjectFactory {
   }
 
   @Override
-  public ClientLink newMediaEditLink(final String name, final URI link) {
-    return new ClientLink.Builder().setURI(link).
-        setType(ClientLinkType.MEDIA_EDIT).setTitle(name).build();
+  public ClientLink newMediaEditLink(String name, URI link, String type, String eTag) {
+    return new ClientLink.Builder().setURI(link).setEtag(eTag).
+        setType(ClientLinkType.fromString(Constants.NS_MEDIA_EDIT_LINK_REL,
+            type == null ? Constants.MEDIA_EDIT_LINK_TYPE : type))
+        .setTitle(name).build();    
   }
-
+  
+  public ClientLink newMediaReadLink(String name, URI link, String type, String eTag) {
+    return new ClientLink.Builder().setURI(link).setEtag(eTag).
+        setType(ClientLinkType.fromString(Constants.NS_MEDIA_READ_LINK_REL,
+            type == null ? Constants.MEDIA_EDIT_LINK_TYPE : type))
+        .setTitle(name).build();    
+  }
+  
   @Override
   public ClientPrimitiveValue.Builder newPrimitiveValueBuilder() {
     return new ClientPrimitiveValueImpl.BuilderImpl();

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
index 8c8c3ee..d9aa892 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/domain/ClientPropertyImpl.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.olingo.client.api.domain.ClientAnnotation;
+import org.apache.olingo.client.api.domain.ClientOperation;
 import org.apache.olingo.client.api.domain.ClientProperty;
 import org.apache.olingo.client.api.domain.ClientValue;
 
@@ -29,7 +30,8 @@ public final class ClientPropertyImpl extends ClientValuableImpl implements Clie
 
   private final List<ClientAnnotation> annotations = new ArrayList<ClientAnnotation>();
   private final String name;
-
+  private final List<ClientOperation> operations = new ArrayList<ClientOperation>();
+  
   public ClientPropertyImpl(final String name, final ClientValue value) {
     super(value);
     this.name = name;
@@ -45,6 +47,29 @@ public final class ClientPropertyImpl extends ClientValuableImpl implements Clie
     return name;
   }
 
+  @Override
+  public ClientOperation getOperation(final String title) {
+    ClientOperation result = null;
+    for (ClientOperation operation : operations) {
+      if (title.equals(operation.getTitle())) {
+        result = operation;
+        break;
+      }
+    }
+
+    return result;
+  }
+
+  /**
+   * Gets operations.
+   *
+   * @return operations.
+   */
+  @Override
+  public List<ClientOperation> getOperations() {
+    return operations;
+  }
+  
   /**
    * Checks if has null value.
    *

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
index 5c3b59e..037ebb5 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/AtomDeserializer.java
@@ -640,8 +640,8 @@ public class AtomDeserializer extends AbstractAtomDealer implements ODataDeseria
               inline(reader, event.asStartElement(), link);
             } else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) {
               entity.getAssociationLinks().add(link);
-            } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) {
-
+            } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL) ||
+                link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) {
               final Attribute metag = event.asStartElement().getAttributeByName(etagQName);
               if (metag != null) {
                 link.setMediaETag(metag.getValue());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java
index 3691d8b..8775f17 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonDeserializer.java
@@ -30,6 +30,7 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.olingo.client.api.data.ResWrap;
 import org.apache.olingo.client.api.serialization.ODataDeserializer;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java
index 53de9cb..53a0cab 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntityDeserializer.java
@@ -148,29 +148,41 @@ public class JsonEntityDeserializer extends JsonDeserializer {
       final Matcher customAnnotation = CUSTOM_ANNOTATION.matcher(field.getKey());
 
       links(field, entity, toRemove, tree, parser.getCodec());
-      if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK))) {
+      if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_READ_LINK))) {
         final Link link = new Link();
         link.setTitle(getTitle(field));
-        link.setRel(Constants.NS_MEDIA_EDIT_LINK_REL + getTitle(field));
-        link.setHref(field.getValue().textValue());
+        link.setRel(Constants.NS_MEDIA_READ_LINK_REL + getTitle(field));
         link.setType(Constants.MEDIA_EDIT_LINK_TYPE);
+        link.setHref(field.getValue().textValue());
         entity.getMediaEditLinks().add(link);
-
+        
         if (tree.has(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG))) {
           link.setMediaETag(tree.get(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG)).asText());
           toRemove.add(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_ETAG));
         }
 
+        if (tree.has(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) {
+          link.setType(tree.get(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE)).asText());
+          toRemove.add(link.getTitle() + getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE));
+        }        
+        
+        toRemove.add(field.getKey());
+        toRemove.add(setInline(field.getKey(), getJSONAnnotation(Constants.JSON_MEDIA_READ_LINK), tree, parser
+            .getCodec(), link));
+      } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK))) {
+        final Link link = getOrCreateMediaLink(entity, getTitle(field));
+        link.setRel(Constants.NS_MEDIA_EDIT_LINK_REL + getTitle(field));
+        link.setHref(field.getValue().textValue());
         toRemove.add(field.getKey());
         toRemove.add(setInline(field.getKey(), getJSONAnnotation(Constants.JSON_MEDIA_EDIT_LINK), tree, parser
             .getCodec(), link));
-      } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) {
-        final String linkTitle = getTitle(field);
-        for (Link link : entity.getMediaEditLinks()) {
-          if (linkTitle.equals(link.getTitle())) {
-            link.setType(field.getValue().asText());
-          }
-        }
+      } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_CONTENT_TYPE))) {        
+        final Link link = getOrCreateMediaLink(entity, getTitle(field));
+        link.setType(field.getValue().asText());
+        toRemove.add(field.getKey());
+      } else if (field.getKey().endsWith(getJSONAnnotation(Constants.JSON_MEDIA_ETAG))) {        
+        final Link link = getOrCreateMediaLink(entity, getTitle(field));
+        link.setMediaETag(field.getValue().asText());
         toRemove.add(field.getKey());
       } else if (field.getKey().charAt(0) == '#') {
         final Operation operation = new Operation();
@@ -226,4 +238,19 @@ public class JsonEntityDeserializer extends JsonDeserializer {
 
     return new ResWrap<Entity>(contextURL, metadataETag, entity);
   }
+  
+  private Link getOrCreateMediaLink(final Entity entity, final String name) {
+    final String rel = Constants.NS_MEDIA_EDIT_LINK_REL + name;
+    for (Link link : entity.getMediaEditLinks()) {
+      if (link.getRel().equals(rel)) {        
+        return link;
+      }
+    }
+    final Link link = new Link();
+    link.setTitle(name);
+    link.setRel(rel);
+    link.setType(Constants.MEDIA_EDIT_LINK_TYPE);
+    entity.getMediaEditLinks().add(link);
+    return link;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java
index 401b31a..d54b98b 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonEntitySetDeserializer.java
@@ -20,14 +20,17 @@ package org.apache.olingo.client.core.serialization;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.olingo.client.api.data.ResWrap;
 import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.data.Annotation;
 import org.apache.olingo.commons.api.data.EntityCollection;
+import org.apache.olingo.commons.api.data.Operation;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 
 import com.fasterxml.jackson.core.JsonParser;
@@ -98,7 +101,7 @@ public class JsonEntitySetDeserializer extends JsonDeserializer {
       }
       tree.remove(Constants.VALUE);
     }
-
+    final Set<String> toRemove = new HashSet<String>();
     // any remaining entry is supposed to be an annotation or is ignored
     for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) {
       final Map.Entry<String, JsonNode> field = itor.next();
@@ -112,9 +115,18 @@ public class JsonEntitySetDeserializer extends JsonDeserializer {
           throw new IOException(e);
         }
         entitySet.getAnnotations().add(annotation);
+      } else if (field.getKey().charAt(0) == '#') {
+        final Operation operation = new Operation();
+        operation.setMetadataAnchor(field.getKey());
+
+        final ObjectNode opNode = (ObjectNode) tree.get(field.getKey());
+        operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText());
+        operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText()));
+        entitySet.getOperations().add(operation);
+        toRemove.add(field.getKey());
       }
     }
-
+    tree.remove(toRemove);
     return new ResWrap<EntityCollection>(contextURL, metadataETag, entitySet);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java
index cb1c65a..af21df7 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/JsonPropertyDeserializer.java
@@ -20,13 +20,16 @@ package org.apache.olingo.client.core.serialization;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Set;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.olingo.client.api.data.ResWrap;
 import org.apache.olingo.commons.api.Constants;
 import org.apache.olingo.commons.api.data.Annotation;
+import org.apache.olingo.commons.api.data.Operation;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.data.ValueType;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
@@ -93,6 +96,7 @@ public class JsonPropertyDeserializer extends JsonDeserializer {
       tree.remove(Constants.VALUE);
     }
 
+    Set<String> toRemove = new HashSet<String>();
     // any remaining entry is supposed to be an annotation or is ignored
     for (final Iterator<Map.Entry<String, JsonNode>> itor = tree.fields(); itor.hasNext();) {
       final Map.Entry<String, JsonNode> field = itor.next();
@@ -106,9 +110,18 @@ public class JsonPropertyDeserializer extends JsonDeserializer {
           throw new IOException(e);
         }
         property.getAnnotations().add(annotation);
+      } else if (field.getKey().charAt(0) == '#') {
+        final Operation operation = new Operation();
+        operation.setMetadataAnchor(field.getKey());
+
+        final ObjectNode opNode = (ObjectNode) tree.get(field.getKey());
+        operation.setTitle(opNode.get(Constants.ATTR_TITLE).asText());
+        operation.setTarget(URI.create(opNode.get(Constants.ATTR_TARGET).asText()));
+        property.getOperations().add(operation);
+        toRemove.add(field.getKey());
       }
     }
-
+    tree.remove(toRemove);
     return new ResWrap<Property>(contextURL, metadataETag, property);
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
index a67de48..1059c58 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/serialization/ODataBinderImpl.java
@@ -414,6 +414,14 @@ public class ODataBinderImpl implements ODataBinder {
     if (resource.getPayload().getCount() != null) {
       entitySet.setCount(resource.getPayload().getCount());
     }
+    
+    for (Operation op : resource.getPayload().getOperations()) {
+      ClientOperation operation = new ClientOperation();
+      operation.setTarget(URIUtils.getURI(base, op.getTarget()));
+      operation.setTitle(op.getTitle());
+      operation.setMetadataAnchor(op.getMetadataAnchor());
+      entitySet.getOperations().add(operation);
+    }    
 
     for (Entity entityResource : resource.getPayload().getEntities()) {
       add(entitySet, getODataEntity(
@@ -660,8 +668,13 @@ public class ODataBinderImpl implements ODataBinder {
     odataNavigationLinks(edmType, resource.getPayload(), entity, resource.getMetadataETag(), base);
 
     for (Link link : resource.getPayload().getMediaEditLinks()) {
-      entity.addLink(client.getObjectFactory().
-          newMediaEditLink(link.getTitle(), URIUtils.getURI(base, link.getHref())));
+      if (link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) {
+        entity.addLink(client.getObjectFactory().newMediaReadLink(link.getTitle(), 
+            URIUtils.getURI(base, link.getHref()), link.getType(), link.getMediaETag()));
+      } else {
+        entity.addLink(client.getObjectFactory().newMediaEditLink(link.getTitle(), 
+            URIUtils.getURI(base, link.getHref()), link.getType(), link.getMediaETag()));        
+      }
     }
 
     for (Operation op : resource.getPayload().getOperations()) {
@@ -735,7 +748,14 @@ public class ODataBinderImpl implements ODataBinder {
         getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
             payload, resource.getContextURL(), resource.getMetadataETag()));
     odataAnnotations(payload, property);
-
+    
+    for (Operation op : resource.getPayload().getOperations()) {
+      ClientOperation operation = new ClientOperation();
+      operation.setTarget(op.getTarget());
+      operation.setTitle(op.getTitle());
+      operation.setMetadataAnchor(op.getMetadataAnchor());
+      property.getOperations().add(operation);
+    }     
     return property;
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java
index 88b3d86..74db088 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/Constants.java
@@ -51,6 +51,8 @@ public interface Constants {
   String NS_ASSOCIATION_LINK_REL = "http://docs.oasis-open.org/odata/ns/relatedlinks/";
 
   String NS_MEDIA_EDIT_LINK_REL = "http://docs.oasis-open.org/odata/ns/edit-media/";
+  
+  String NS_MEDIA_READ_LINK_REL = "http://docs.oasis-open.org/odata/ns/mediaresource/";
 
   String NS_DELTA_LINK_REL = "http://docs.oasis-open.org/odata/ns/delta";
 
@@ -274,6 +276,8 @@ public interface Constants {
   QName QNAME_ATOM_ELEM_CONTENT = new QName(NS_ATOM, ATOM_ELEM_CONTENT);
 
   String ATOM_ELEM_ACTION = "action";
+  
+  String ATOM_ELEM_FUNCTION = "function";
 
   String ATOM_ELEM_INLINE = "inline";
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java
index 2d7a689..9521591 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/AbstractEntityCollection.java
@@ -19,6 +19,7 @@
 package org.apache.olingo.commons.api.data;
 
 import java.net.URI;
+import java.util.List;
 
 public abstract class AbstractEntityCollection extends AbstractODataObject implements Iterable<Entity> {
   public abstract Integer getCount();
@@ -26,4 +27,6 @@ public abstract class AbstractEntityCollection extends AbstractODataObject imple
   public abstract URI getNext();
 
   public abstract URI getDeltaLink();
+  
+  public abstract List<Operation> getOperations();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java
index 86d8747..d95c536 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/EntityCollection.java
@@ -32,7 +32,8 @@ public class EntityCollection extends AbstractEntityCollection {
   private Integer count;
   private URI next;
   private URI deltaLink;
-
+  private final List<Operation> operations = new ArrayList<Operation>();
+  
   /**
    * Sets number of entries.
    *
@@ -98,6 +99,16 @@ public class EntityCollection extends AbstractEntityCollection {
   public void setDeltaLink(final URI deltaLink) {
     this.deltaLink = deltaLink;
   }
+  
+  /**
+   * Gets operations.
+   *
+   * @return operations.
+   */
+  @Override
+  public List<Operation> getOperations() {
+    return operations;
+  }  
 
   @Override
   public Iterator<Entity> iterator() {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java
index f7bf1fa..515de03 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Operation.java
@@ -24,13 +24,16 @@ import java.net.URI;
  * Data representation for an operation.
  */
 public class Operation {
-
+  public enum Type {ACTION, FUNCTION};
+  
   private String metadataAnchor;
 
   private String title;
 
   private URI target;
 
+  private Type type;
+  
   /**
    * Gets metadata anchor.
    *
@@ -84,5 +87,20 @@ public class Operation {
   public void setTarget(final URI target) {
     this.target = target;
   }
+  
+  /**
+   * Gets the Operation Type 
+   * @return
+   */
+  public Type getType() {
+    return type;
+  }
 
+  /**
+   * Set the Operation type
+   * @param type
+   */
+  public void setType(Type type) {
+    this.type = type;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java
index 2117241..c8ad3c8 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/data/Property.java
@@ -18,12 +18,16 @@
  */
 package org.apache.olingo.commons.api.data;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Data representation for a property.
  */
 public class Property extends Valuable {
 
   private String name;
+  private final List<Operation> operations = new ArrayList<Operation>();
   
   /**
    * Creates a new property
@@ -79,6 +83,15 @@ public class Property extends Valuable {
   public boolean isNull() {
     return getValue() == null || "Edm.Null".equals(getType());
   }
+  
+  /**
+   * Gets operations.
+   *
+   * @return operations.
+   */
+  public List<Operation> getOperations() {
+    return operations;
+  }  
 
   @Override
   public boolean equals(final Object o) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java
index ff46b7d..b9f3a6c 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/primitivetype/EdmStream.java
@@ -21,6 +21,7 @@ package org.apache.olingo.commons.core.edm.primitivetype;
 import java.net.URI;
 import java.net.URISyntaxException;
 
+import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 
 /**
@@ -69,6 +70,10 @@ public final class EdmStream extends SingletonPrimitiveType {
 
     if (returnType.isAssignableFrom(URI.class)) {
       return returnType.cast(stream);
+    } else if (returnType.isAssignableFrom(Link.class)) {
+      Link link = new Link();
+      link.setHref(value);
+      return returnType.cast(link);
     } else {
       throw new EdmPrimitiveTypeException("The value type " + returnType + " is not supported.");
     }
@@ -81,6 +86,8 @@ public final class EdmStream extends SingletonPrimitiveType {
 
     if (value instanceof URI) {
       return ((URI) value).toASCIIString();
+    } else if (value instanceof Link) {
+      return ((Link)value).getHref();
     } else {
       throw new EdmPrimitiveTypeException("The value type " + value.getClass() + " is not supported.");
     }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
index 67d794c..29c7134 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/ServiceRequest.java
@@ -220,14 +220,14 @@ public abstract class ServiceRequest {
     
     if (serilizerOptions.isAssignableFrom(EntitySerializerOptions.class)) {
       return (T) EntitySerializerOptions.with()
-          .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
+          .contextURL(contextUrl)
           .expand(uriInfo.getExpandOption()).select(this.uriInfo.getSelectOption())
           .writeOnlyReferences(references)
           .xml10InvalidCharReplacement(xmlReplacement)
           .build();
     } else if (serilizerOptions.isAssignableFrom(EntityCollectionSerializerOptions.class)) {
       return (T) EntityCollectionSerializerOptions.with()
-          .contextURL(isODataMetadataNone(getResponseContentType()) ? null : contextUrl)
+          .contextURL(contextUrl)
           .count(uriInfo.getCountOption()).expand(uriInfo.getExpandOption())
           .select(uriInfo.getSelectOption()).writeOnlyReferences(references)
           .id(getODataRequest().getRawBaseUri() + getODataRequest().getRawODataPath())
@@ -346,9 +346,4 @@ public abstract class ServiceRequest {
     dispatcher.request.setUriInfo(uriInfo);
     return (DataRequest)dispatcher.request;
   }
-  
-  private boolean isODataMetadataNone(final ContentType contentType) {
-    return contentType.isCompatible(ContentType.JSON) 
-        && ContentType.VALUE_ODATA_METADATA_NONE.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
-  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
index 86697d5..63452f4 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ContentNegotiator.java
@@ -41,6 +41,7 @@ public final class ContentNegotiator {
           ContentType.JSON,
           ContentType.JSON_NO_METADATA,
           ContentType.APPLICATION_JSON,
+          ContentType.JSON_FULL_METADATA,
           ContentType.APPLICATION_ATOM_XML,
           ContentType.APPLICATION_XML));
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
index 71ea0e7..b638ae7 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/ODataImpl.java
@@ -64,7 +64,8 @@ public class ODataImpl extends OData {
       final String metadata = contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA);
       if (metadata == null
           || ContentType.VALUE_ODATA_METADATA_MINIMAL.equals(metadata)
-          || ContentType.VALUE_ODATA_METADATA_NONE.equals(metadata)) {
+          || ContentType.VALUE_ODATA_METADATA_NONE.equals(metadata)
+          || ContentType.VALUE_ODATA_METADATA_FULL.equals(metadata)) {
         serializer = new ODataJsonSerializer(contentType);
       }
     } else if (contentType.isCompatible(ContentType.APPLICATION_XML)

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
index c8b5f96..21c9b37 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/deserializer/xml/ODataXmlDeserializer.java
@@ -543,7 +543,8 @@ public class ODataXmlDeserializer implements ODataDeserializer {
               }
             } else if (link.getRel().startsWith(Constants.NS_ASSOCIATION_LINK_REL)) {
               entity.getAssociationLinks().add(link);
-            } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL)) {
+            } else if (link.getRel().startsWith(Constants.NS_MEDIA_EDIT_LINK_REL) ||
+                link.getRel().startsWith(Constants.NS_MEDIA_READ_LINK_REL)) {
               final Attribute metag = event.asStartElement().getAttributeByName(etagQName);
               if (metag != null) {
                 link.setMediaETag(metag.getValue());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
index 396261f..759ae5c 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/json/ODataJsonSerializer.java
@@ -18,6 +18,9 @@
  */
 package org.apache.olingo.server.core.serializer.json;
 
+import static org.apache.olingo.server.core.serializer.utils.ContentTypeHelper.isODataMetadataFull;
+import static org.apache.olingo.server.core.serializer.utils.ContentTypeHelper.isODataMetadataNone;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.Collections;
@@ -33,6 +36,7 @@ import org.apache.olingo.commons.api.data.Entity;
 import org.apache.olingo.commons.api.data.EntityIterator;
 import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.data.Linked;
+import org.apache.olingo.commons.api.data.Operation;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.EdmComplexType;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
@@ -68,7 +72,6 @@ import org.apache.olingo.server.core.ODataWritableContent;
 import org.apache.olingo.server.core.serializer.AbstractODataSerializer;
 import org.apache.olingo.server.core.serializer.SerializerResultImpl;
 import org.apache.olingo.server.core.serializer.utils.CircleStreamBuffer;
-import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
 import org.apache.olingo.server.core.serializer.utils.ContextURLBuilder;
 import org.apache.olingo.server.core.serializer.utils.ExpandSelectHelper;
 import org.apache.olingo.server.core.uri.UriHelperImpl;
@@ -79,11 +82,11 @@ import com.fasterxml.jackson.core.JsonGenerator;
 public class ODataJsonSerializer extends AbstractODataSerializer {
 
   private final boolean isIEEE754Compatible;
-  private final boolean isODataMetadataNone;
+  private final ContentType contentType;
 
   public ODataJsonSerializer(final ContentType contentType) {
+    this.contentType = contentType;
     isIEEE754Compatible = isODataIEEE754Compatible(contentType);
-    isODataMetadataNone = ContentTypeHelper.isODataMetadataNone(contentType);
   }
 
   @Override
@@ -96,7 +99,8 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       CircleStreamBuffer buffer = new CircleStreamBuffer();
       outputStream = buffer.getOutputStream();
       JsonGenerator json = new JsonFactory().createGenerator(outputStream);
-      new ServiceDocumentJsonSerializer(metadata, serviceRoot, isODataMetadataNone).writeServiceDocument(json);
+      new ServiceDocumentJsonSerializer(metadata, serviceRoot, 
+          isODataMetadataNone(contentType)).writeServiceDocument(json);
 
       json.close();
       outputStream.close();
@@ -158,6 +162,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       if (options != null && options.getCount() != null && options.getCount().getValue()) {
         writeCount(entitySet, json);
       }
+      writeOperations(entitySet.getOperations(), json);
       json.writeFieldName(Constants.VALUE);
       if (options == null) {
         writeEntitySet(metadata, entityType, entitySet, null, null, false, json);
@@ -251,7 +256,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
   }
 
   ContextURL checkContextURL(final ContextURL contextURL) throws SerializerException {
-    if (isODataMetadataNone) {
+    if (isODataMetadataNone(contentType)) {
       return null;
     } else if (contextURL == null) {
       throw new SerializerException("ContextURL null!", SerializerException.MessageKeys.NO_CONTEXT_URL);
@@ -308,7 +313,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       final JsonGenerator json)
       throws IOException, SerializerException {
     json.writeStartObject();
-    if (!isODataMetadataNone) {
+    if (!isODataMetadataNone(contentType)) {
       // top-level entity
       if (contextURL != null) {
         writeContextURL(contextURL, json);
@@ -336,18 +341,43 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       json.writeStringField(Constants.JSON_ID, getEntityId(entity));
     } else {
       final EdmEntityType resolvedType = resolveEntityType(metadata, entityType, entity.getType());
-      if (!isODataMetadataNone && !resolvedType.equals(entityType)) {
+      if ((!isODataMetadataNone(contentType) && !resolvedType.equals(entityType)) 
+          || isODataMetadataFull(contentType)) {
         json.writeStringField(Constants.JSON_TYPE, "#" + entity.getType());
       }
-      if (!isODataMetadataNone && !areKeyPredicateNamesSelected(select, resolvedType)) {
+      if ((!isODataMetadataNone(contentType) && !areKeyPredicateNamesSelected(select, resolvedType)) 
+          || isODataMetadataFull(contentType)) {
         json.writeStringField(Constants.JSON_ID, getEntityId(entity));
       }
+      
+      if (isODataMetadataFull(contentType)) {
+        if (entity.getSelfLink() != null) {
+          json.writeStringField(Constants.JSON_READ_LINK, entity.getSelfLink().getHref());
+        }
+        if (entity.getEditLink() != null) {
+          json.writeStringField(Constants.JSON_EDIT_LINK, entity.getEditLink().getHref());
+        }
+      }
+      
       writeProperties(metadata, resolvedType, entity.getProperties(), select, json);
       writeNavigationProperties(metadata, resolvedType, entity, expand, json);
+      writeOperations(entity.getOperations(), json);
       json.writeEndObject();
     }
   }
 
+  private void writeOperations(final List<Operation> operations, final JsonGenerator json)
+      throws IOException {
+    if (isODataMetadataFull(contentType)) {
+      for (Operation operation : operations) {
+        json.writeObjectFieldStart(operation.getMetadataAnchor());
+        json.writeStringField(Constants.ATTR_TITLE, operation.getTitle());
+        json.writeStringField(Constants.ATTR_TARGET, operation.getTarget().toASCIIString());
+        json.writeEndObject();
+      }
+    }
+  }
+
   protected EdmEntityType resolveEntityType(final ServiceMetadata metadata, final EdmEntityType baseType,
       final String derivedTypeName) throws SerializerException {
     if (derivedTypeName == null ||
@@ -440,6 +470,17 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
               json);
         }
       }
+    } else if (isODataMetadataFull(contentType)) {
+      for (final String propertyName : type.getNavigationPropertyNames()) {
+        final Link navigationLink = linked.getNavigationLink(propertyName);
+        if (navigationLink != null) {
+          json.writeStringField(propertyName + Constants.JSON_NAVIGATION_LINK, navigationLink.getHref());  
+        }
+        final Link associationLink = linked.getAssociationLink(propertyName);
+        if (associationLink != null) {
+          json.writeStringField(propertyName + Constants.JSON_ASSOCIATION_LINK, associationLink.getHref());  
+        }
+      }
     }
   }
 
@@ -484,28 +525,79 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       }
     }
   }
+  
+  private boolean isStreamProperty(EdmProperty edmProperty) {
+    final EdmType type = edmProperty.getType();
+    return (edmProperty.isPrimitive() && type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream));    
+  }
 
-  protected void writeProperty(final ServiceMetadata metadata, final EdmProperty edmProperty, final Property property,
+  protected void writeProperty(final ServiceMetadata metadata,
+      final EdmProperty edmProperty, final Property property,
       final Set<List<String>> selectedPaths, final JsonGenerator json)
       throws IOException, SerializerException {
-    json.writeFieldName(edmProperty.getName());
-    if (property == null || property.isNull()) {
+    boolean isStreamProperty = isStreamProperty(edmProperty);
+    writePropertyType(edmProperty, property, json);
+    if (!isStreamProperty) {
+      json.writeFieldName(edmProperty.getName());
+    }
+    if ((property == null || property.isNull())) {
       if (edmProperty.isNullable() == Boolean.FALSE) {
         throw new SerializerException("Non-nullable property not present!",
             SerializerException.MessageKeys.MISSING_PROPERTY, edmProperty.getName());
       } else {
-        if (edmProperty.isCollection()) {
-          json.writeStartArray();
-          json.writeEndArray();
-        } else {
-          json.writeNull();
+        if (!isStreamProperty) {
+          if (edmProperty.isCollection()) {
+            json.writeStartArray();
+            json.writeEndArray();
+          } else {
+            json.writeNull();
+          }
         }
       }
     } else {
       writePropertyValue(metadata, edmProperty, property, selectedPaths, json);
     }
   }
-
+  
+  private void writePropertyType(final EdmProperty edmProperty, final Property property,
+      final JsonGenerator json) throws SerializerException, IOException {
+    if(!isODataMetadataFull(contentType)) {
+      return;
+    }
+    String typeName = edmProperty.getName()+Constants.JSON_TYPE;
+    final EdmType type = edmProperty.getType();
+    if (type.getKind() == EdmTypeKind.ENUM || type.getKind() == EdmTypeKind.DEFINITION) {
+      if (edmProperty.isCollection()) {
+        json.writeStringField(typeName, 
+            "#Collection("+type.getFullQualifiedName().getFullQualifiedNameAsString()+")");
+      } else {
+        json.writeStringField(typeName, "#"+type.getFullQualifiedName().getFullQualifiedNameAsString());
+      }      
+    } else if (edmProperty.isPrimitive()) {
+      if (edmProperty.isCollection()) {
+        json.writeStringField(typeName, 
+            "#Collection("+type.getFullQualifiedName().getName()+")");        
+      } else {
+        // exclude the properties that can be heuristically determined
+        if (type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Boolean) &&
+            type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Double) &&
+            type != EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.String)) {
+          json.writeStringField(typeName, 
+              "#"+type.getFullQualifiedName().getName());                  
+        }
+      }
+    } else if (type.getKind() == EdmTypeKind.COMPLEX) {
+      // non-collection case written in writeComplex method directly.
+      if (edmProperty.isCollection()) {
+        json.writeStringField(typeName, 
+            "#Collection("+type.getFullQualifiedName().getFullQualifiedNameAsString()+")");        
+      }
+    } else {
+      throw new SerializerException("Property type not yet supported!",
+          SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, edmProperty.getName());
+    }    
+  }
+  
   private void writePropertyValue(final ServiceMetadata metadata, final EdmProperty edmProperty,
       final Property property, final Set<List<String>> selectedPaths, final JsonGenerator json)
       throws IOException, SerializerException {
@@ -550,7 +642,8 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       case COLLECTION_PRIMITIVE:
       case COLLECTION_ENUM:
         try {
-          writePrimitiveValue(type, value, isNullable, maxLength, precision, scale, isUnicode, json);
+          writePrimitiveValue(property.getName(), type, value, isNullable,
+              maxLength, precision, scale, isUnicode, json);
         } catch (EdmPrimitiveTypeException e) {
           throw new SerializerException("Wrong value for property!", e,
               SerializerException.MessageKeys.WRONG_PROPERTY_VALUE,
@@ -591,13 +684,13 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       final Boolean isUnicode, final JsonGenerator json)
       throws EdmPrimitiveTypeException, IOException, SerializerException {
     if (property.isPrimitive()) {
-      writePrimitiveValue(type, property.asPrimitive(),
+      writePrimitiveValue(property.getName(), type, property.asPrimitive(),
           isNullable, maxLength, precision, scale, isUnicode, json);
     } else if (property.isGeospatial()) {
       throw new SerializerException("Property type not yet supported!",
           SerializerException.MessageKeys.UNSUPPORTED_PROPERTY_TYPE, property.getName());
     } else if (property.isEnum()) {
-      writePrimitiveValue(type, property.asEnum(),
+      writePrimitiveValue(property.getName(), type, property.asEnum(),
           isNullable, maxLength, precision, scale, isUnicode, json);
     } else {
       throw new SerializerException("Inconsistent property type!",
@@ -605,7 +698,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
     }
   }
 
-  protected void writePrimitiveValue(final EdmPrimitiveType type, final Object primitiveValue,
+  protected void writePrimitiveValue(final String name, final EdmPrimitiveType type, final Object primitiveValue,
       final Boolean isNullable, final Integer maxLength, final Integer precision, final Integer scale,
       final Boolean isUnicode, final JsonGenerator json) throws EdmPrimitiveTypeException, IOException {
     final String value = type.valueToString(primitiveValue,
@@ -624,6 +717,26 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
         || type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Int64))
         && !isIEEE754Compatible) {
       json.writeNumber(value);
+    } else if (type == EdmPrimitiveTypeFactory.getInstance(EdmPrimitiveTypeKind.Stream)) {
+      if (primitiveValue instanceof Link) {
+        Link stream = (Link)primitiveValue;
+        if (!isODataMetadataNone(contentType)) {
+          if (stream.getMediaETag() != null) {
+            json.writeStringField(name+Constants.JSON_MEDIA_ETAG, stream.getMediaETag());
+          }
+          if (stream.getType() != null) {
+            json.writeStringField(name+Constants.JSON_MEDIA_CONTENT_TYPE, stream.getType());
+          }
+        }
+        if (isODataMetadataFull(contentType)) {
+          if (stream.getRel() != null && stream.getRel().equals(Constants.NS_MEDIA_READ_LINK_REL)) {
+            json.writeStringField(name+Constants.JSON_MEDIA_READ_LINK, stream.getHref());
+          }
+          if (stream.getRel() == null || stream.getRel().equals(Constants.NS_MEDIA_EDIT_LINK_REL)) {
+            json.writeStringField(name+Constants.JSON_MEDIA_EDIT_LINK, stream.getHref());
+          }
+        }
+      }
     } else {
       json.writeString(value);
     }
@@ -637,9 +750,8 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
 
     final EdmComplexType resolvedType = resolveComplexType(metadata,
         type, complexProperty.getType());
-    if (!isODataMetadataNone && !resolvedType.equals(type)) {
-      json.writeStringField(Constants.JSON_TYPE,
-          "#" + complexProperty.getType());
+    if (!isODataMetadataNone(contentType) && !resolvedType.equals(type) || isODataMetadataFull(contentType)) {
+      json.writeStringField(Constants.JSON_TYPE, "#" + complexProperty.getType());
     }
 
     for (final String propertyName : resolvedType.getPropertyNames()) {
@@ -675,6 +787,7 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       json.writeStartObject();
       writeContextURL(contextURL, json);
       writeMetadataETag(metadata, json);
+      writeOperations(property.getOperations(), json);
       if (property.isNull()) {
         throw new SerializerException("Property value can not be null.", SerializerException.MessageKeys.NULL_INPUT);
       } else {
@@ -717,11 +830,12 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       JsonGenerator json = new JsonFactory().createGenerator(outputStream);
       json.writeStartObject();
       writeContextURL(contextURL, json);
-      writeMetadataETag(metadata, json);
+      writeMetadataETag(metadata, json);      
       final EdmComplexType resolvedType = resolveComplexType(metadata, type, property.getType());
-      if (!isODataMetadataNone && !resolvedType.equals(type)) {
+      if (!isODataMetadataNone(contentType) && !resolvedType.equals(type) || isODataMetadataFull(contentType)) {
         json.writeStringField(Constants.JSON_TYPE, "#" + property.getType());
       }
+      writeOperations(property.getOperations(), json);      
       final List<Property> values =
           property.isNull() ? Collections.<Property> emptyList() : property.asComplex().getValue();
       writeProperties(metadata, type, values, options == null ? null : options.getSelect(), json);
@@ -756,6 +870,10 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       json.writeStartObject();
       writeContextURL(contextURL, json);
       writeMetadataETag(metadata, json);
+      if (isODataMetadataFull(contentType)) {
+        json.writeStringField(Constants.JSON_TYPE,  "#Collection("+type.getFullQualifiedName().getName()+")");
+      }
+      writeOperations(property.getOperations(), json);
       json.writeFieldName(Constants.VALUE);
       writePrimitiveCollection(type, property,
           options == null ? null : options.isNullable(),
@@ -790,6 +908,11 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
       json.writeStartObject();
       writeContextURL(contextURL, json);
       writeMetadataETag(metadata, json);
+      if (isODataMetadataFull(contentType)) {
+        json.writeStringField(Constants.JSON_TYPE, 
+            "#Collection("+type.getFullQualifiedName().getFullQualifiedNameAsString()+")");                
+      }
+      writeOperations(property.getOperations(), json);
       json.writeFieldName(Constants.VALUE);
       writeComplexCollection(metadata, type, property, null, json);
       json.writeEndObject();
@@ -882,13 +1005,13 @@ public class ODataJsonSerializer extends AbstractODataSerializer {
   }
 
   void writeContextURL(final ContextURL contextURL, final JsonGenerator json) throws IOException {
-    if (!isODataMetadataNone && contextURL != null) {
+    if (!isODataMetadataNone(contentType) && contextURL != null) {
       json.writeStringField(Constants.JSON_CONTEXT, ContextURLBuilder.create(contextURL).toASCIIString());
     }
   }
 
   void writeMetadataETag(final ServiceMetadata metadata, final JsonGenerator json) throws IOException {
-    if (!isODataMetadataNone
+    if (!isODataMetadataNone(contentType)
         && metadata != null
         && metadata.getServiceMetadataETagSupport() != null
         && metadata.getServiceMetadataETagSupport().getMetadataETag() != null) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContentTypeHelper.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContentTypeHelper.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContentTypeHelper.java
index 68d85f7..99c0343 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContentTypeHelper.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/utils/ContentTypeHelper.java
@@ -30,4 +30,9 @@ public class ContentTypeHelper {
     return contentType.isCompatible(ContentType.APPLICATION_JSON)
         && ContentType.VALUE_ODATA_METADATA_NONE.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
   }
+  
+  public static boolean isODataMetadataFull(final ContentType contentType) {
+    return contentType.isCompatible(ContentType.APPLICATION_JSON)
+        && ContentType.VALUE_ODATA_METADATA_FULL.equals(contentType.getParameter(ContentType.PARAMETER_ODATA_METADATA));
+  }  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
index fecf920..b3d815b 100644
--- a/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
+++ b/lib/server-core/src/main/java/org/apache/olingo/server/core/serializer/xml/ODataXmlSerializer.java
@@ -39,6 +39,7 @@ import org.apache.olingo.commons.api.data.AbstractEntityCollection;
 import org.apache.olingo.commons.api.data.EntityIterator;
 import org.apache.olingo.commons.api.data.Link;
 import org.apache.olingo.commons.api.data.Linked;
+import org.apache.olingo.commons.api.data.Operation;
 import org.apache.olingo.commons.api.data.Property;
 import org.apache.olingo.commons.api.edm.EdmComplexType;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
@@ -240,7 +241,7 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
       writer.writeAttribute(METADATA, NS_METADATA, Constants.CONTEXT,
           ContextURLBuilder.create(contextURL).toASCIIString());
       writeMetadataETag(metadata, writer);
-
+      writeOperations(entitySet.getOperations(), writer);
       if (options != null && options.getId() != null) {
         writer.writeStartElement(ATOM, Constants.ATOM_ELEM_ID, NS_ATOM);
         writer.writeCharacters(options.getId());
@@ -487,9 +488,24 @@ public class ODataXmlSerializer extends AbstractODataSerializer {
     if (!entityType.hasStream()) { // content
       writer.writeEndElement();
     }
+    
+    writeOperations(entity.getOperations(), writer);
+    
     writer.writeEndElement(); // entry
   }
 
+  private void writeOperations(final List<Operation> operations,
+      final XMLStreamWriter writer) throws XMLStreamException {
+    for (Operation operation : operations) {
+      boolean action = (operation.getType() != null && operation.getType() == Operation.Type.ACTION);
+      writer.writeStartElement(METADATA, action?Constants.ATOM_ELEM_ACTION:Constants.ATOM_ELEM_FUNCTION, NS_METADATA);
+      writer.writeAttribute(Constants.ATTR_METADATA, operation.getMetadataAnchor());
+      writer.writeAttribute(Constants.ATTR_TITLE, operation.getTitle());
+      writer.writeAttribute(Constants.ATTR_TARGET, operation.getTarget().toASCIIString());
+      writer.writeEndElement();
+    }
+  }
+
   private void writerAuthorInfo(final String title, final XMLStreamWriter writer) throws XMLStreamException {
     writer.writeStartElement(NS_ATOM, Constants.ATTR_TITLE);
     if (title != null) {

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
index ce0abe7..ae6373c 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ContentNegotiatorTest.java
@@ -99,7 +99,6 @@ public class ContentNegotiatorTest {
       { null,                   "a/a",            null,                  "b/b"            },
       { null,                   "a/a;x=y",        null,                  "a/a;v=w"        },
       { null,                   null,             "a/a;x=y",             "a/a;v=w"        },
-      { null,                   null,             ACCEPT_CASE_FULL,      null             }, // not yet supported
       { null,                   null,             "*",                   null             },
       { null,                   "a/b;charset=ISO-8859-1", null,          "a/b"            },
       { null,                   null,             "a/b;charset=ISO-8859-1", "a/b"         },

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/eaceb01d/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
index c289b93..e0875e7 100644
--- a/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
+++ b/lib/server-core/src/test/java/org/apache/olingo/server/core/ODataImplTest.java
@@ -35,11 +35,8 @@ public class ODataImplTest {
     assertNotNull(odata.createSerializer(ContentType.JSON_NO_METADATA));
     assertNotNull(odata.createSerializer(ContentType.JSON));
     assertNotNull(odata.createSerializer(ContentType.APPLICATION_JSON));
-  }
-
-  @Test(expected = SerializerException.class)
-  public void jsonSerializerForODataMetadataFull() throws SerializerException {
-    odata.createSerializer(ContentType.JSON_FULL_METADATA);
+    assertNotNull(odata.createSerializer(ContentType.JSON_FULL_METADATA));
+    
   }
 
   @Test