olingo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rare...@apache.org
Subject [4/4] olingo-odata4 git commit: OLINGO-567: Support for odata.metadata=full
Date Sun, 26 Jun 2016 14:58:58 GMT
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/3c0225c9
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata4/tree/3c0225c9
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata4/diff/3c0225c9

Branch: refs/heads/master
Commit: 3c0225c9dac6ac26ebe933a3c53e40cf849682ed
Parents: b32a2ce
Author: Ramesh Reddy <rareddy@jboss.org>
Authored: Mon May 23 14:44:12 2016 -0500
Committer: Ramesh Reddy <rareddy@jboss.org>
Committed: Sun Jun 26 07:50:39 2016 -0700

----------------------------------------------------------------------
 .../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 +
 .../org/apache/olingo/commons/api/edm/Edm.java  |  21 ++
 .../olingo/commons/core/edm/AbstractEdm.java    |  36 ++
 .../core/edm/primitivetype/EdmStream.java       |   7 +
 .../olingo/server/core/ServiceRequest.java      |   9 +-
 .../server/core/responses/EntityResponse.java   |  19 +
 .../core/responses/EntitySetResponse.java       |  64 +++-
 .../server/core/responses/PropertyResponse.java |  43 +++
 .../server/core/responses/ServiceResponse.java  |  50 ++-
 .../server/example/TripPinServiceTest.java      |  24 ++
 .../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 +++++++++-
 54 files changed, 1883 insertions(+), 125 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/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/3c0225c9/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java
----------------------------------------------------------------------
diff --git a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java
index 19ae049..1efdaca 100644
--- a/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java
+++ b/lib/commons-api/src/main/java/org/apache/olingo/commons/api/edm/Edm.java
@@ -121,6 +121,17 @@ public interface Edm {
       Boolean isBindingParameterCollection);
 
   /**
+   * Get Action by full qualified name and binding parameter type.
+   * Note: action can not be overloaded on binding type
+   * 
+   * @param bindingParameterTypeName must not be null
+   * @param isBindingParameterCollection may be null
+   * @return {@link EdmAction}
+   */  
+  EdmAction getBoundActionWithBindingType(FullQualifiedName bindingParameterTypeName,
+      Boolean isBindingParameterCollection);
+
+  /**
    * Get Function by full qualified name.
    *
    * @param functionName must not be null
@@ -150,6 +161,16 @@ public interface Edm {
       Boolean isBindingParameterCollection, List<String> parameterNames);
 
   /**
+   * Get Function by binding parameter type
+   *
+   * @param bindingParameterTypeName must not be null
+   * @param isBindingParameterCollection may be null
+   * @return {@link EdmFunction}
+   */
+  List<EdmFunction> getBoundFunctionsWithBindingType(FullQualifiedName bindingParameterTypeName,
+      Boolean isBindingParameterCollection);  
+
+  /**
    * Get Term full by qualified name.
    *
    * @param termName must not be null

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java
----------------------------------------------------------------------
diff --git a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java
index 44597f3..bcfd394 100644
--- a/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java
+++ b/lib/commons-core/src/main/java/org/apache/olingo/commons/core/edm/AbstractEdm.java
@@ -32,6 +32,7 @@ import org.apache.olingo.commons.api.edm.EdmEntityContainer;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
 import org.apache.olingo.commons.api.edm.EdmEnumType;
 import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmParameter;
 import org.apache.olingo.commons.api.edm.EdmSchema;
 import org.apache.olingo.commons.api.edm.EdmTerm;
 import org.apache.olingo.commons.api.edm.EdmTypeDefinition;
@@ -416,4 +417,39 @@ public abstract class AbstractEdm implements Edm {
     TargetQualifierMapKey key = new TargetQualifierMapKey(targetName, annotationsGroup.getQualifier());
     annotationGroups.put(key, annotationsGroup);
   }
+  
+  @Override
+  public EdmAction getBoundActionWithBindingType(FullQualifiedName bindingParameterTypeName,
+      Boolean isBindingParameterCollection) {
+    for (EdmSchema schema:getSchemas()) {
+      for (EdmAction action: schema.getActions()) {
+        if (action.isBound()) {
+          EdmParameter bindingParameter = action.getParameter(action.getParameterNames().get(0));
+          if (bindingParameter.getType().getFullQualifiedName().equals(bindingParameterTypeName)
+              && bindingParameter.isCollection() == isBindingParameterCollection) {
+            return action;  
+          }          
+        }
+      }
+    }
+    return null;
+  }
+  
+  @Override
+  public List<EdmFunction> getBoundFunctionsWithBindingType(FullQualifiedName bindingParameterTypeName,
+      Boolean isBindingParameterCollection){
+    List<EdmFunction> functions = new ArrayList<EdmFunction>();
+    for (EdmSchema schema:getSchemas()) {
+      for (EdmFunction function: schema.getFunctions()) {
+        if (function.isBound()) {
+          EdmParameter bindingParameter = function.getParameter(function.getParameterNames().get(0));
+          if (bindingParameter.getType().getFullQualifiedName().equals(bindingParameterTypeName)
+              && bindingParameter.isCollection() == isBindingParameterCollection) {
+            functions.add(function);
+          }
+        }
+      }
+    }
+    return functions;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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/3c0225c9/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/3c0225c9/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
index b55d3dd..6d92abc 100644
--- 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
@@ -18,12 +18,15 @@
  */
 package org.apache.olingo.server.core.responses;
 
+import java.util.List;
 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.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmEntitySet;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeException;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.format.ContentType;
@@ -43,6 +46,7 @@ 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;
+import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
 
 public class EntityResponse extends ServiceResponse {
   private final ReturnRepresentation returnRepresentation;
@@ -92,6 +96,21 @@ public class EntityResponse extends ServiceResponse {
       return;
     }
 
+    if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) {
+      EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType(
+          entityType.getFullQualifiedName(), false);
+      if (action != null) {
+        entity.getOperations().add(buildOperation(action, entity.getId().toASCIIString()));
+      }
+      
+      List<EdmFunction> functions = this.metadata.getEdm()
+          .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),false);
+      
+      for (EdmFunction function:functions) {
+        entity.getOperations().add(buildOperation(function, entity.getId().toASCIIString()));
+      }
+    }
+    
     // write the entity to response
     this.response.setContent(this.serializer.entity(this.metadata, entityType, entity, this.options).getContent());
     writeOK(responseContentType);

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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
index 622c95d..88762d2 100644
--- 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
@@ -18,13 +18,18 @@
  */
 package org.apache.olingo.server.core.responses;
 
+import java.util.List;
 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.data.EntityCollection;
+import org.apache.olingo.commons.api.edm.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmEntityType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
 import org.apache.olingo.commons.api.format.ContentType;
 import org.apache.olingo.commons.api.http.HttpHeader;
+import org.apache.olingo.commons.core.Encoder;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataServerError;
@@ -35,6 +40,7 @@ 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;
+import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
 
 public class EntitySetResponse extends ServiceResponse {
   private final ODataSerializer serializer;
@@ -70,6 +76,9 @@ public class EntitySetResponse extends ServiceResponse {
       return;
     }
 
+    if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) {
+      buildOperations(entityType, entitySet);      
+    }    
     // write the whole collection to response
     this.response.setContent(this.serializer.entityCollection(metadata, entityType, entitySet, this.options)
                                             .getContent());
@@ -90,5 +99,58 @@ public class EntitySetResponse extends ServiceResponse {
     } catch (SerializerException e) {
       writeServerError(true);
     }
-  }  
+  }
+    
+  private void buildOperations(EdmEntityType entityType,
+      EntityCollection entitySet) {
+    EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType(
+        entityType.getFullQualifiedName(), true);
+    if (action != null) {
+      entitySet.getOperations().add(buildOperation(action, buildOperationTarget(options.getContextURL())));
+    }
+    
+    action = this.metadata.getEdm().getBoundActionWithBindingType(
+        entityType.getFullQualifiedName(), false);
+    if (action != null) {
+      for (Entity entity:entitySet.getEntities()) {
+        entity.getOperations().add(buildOperation(action, entity.getId().toASCIIString()));
+      }
+    }      
+    
+    List<EdmFunction> functions = this.metadata.getEdm()
+        .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),true);
+    
+    for (EdmFunction function:functions) {
+      entitySet.getOperations().add(buildOperation(function, buildOperationTarget(options.getContextURL())));
+    }
+    
+    functions = this.metadata.getEdm()
+        .getBoundFunctionsWithBindingType(entityType.getFullQualifiedName(),false);
+    
+    for (Entity entity:entitySet.getEntities()) {
+      for (EdmFunction function:functions) {
+        entity.getOperations().add(buildOperation(function, entity.getId().toASCIIString()));
+      }
+    }
+  }
+  
+  private String buildOperationTarget(ContextURL contextURL) {
+    StringBuilder result = new StringBuilder();
+    if (contextURL.getServiceRoot() != null) {
+      result.append(contextURL.getServiceRoot());
+    }
+    if (contextURL.getEntitySetOrSingletonOrType() != null) {
+      if (result.length() != 0) {
+        result.append("/");
+      }
+      result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType()));
+    }
+    if (contextURL.getKeyPath() != null) {
+      result.append('(').append(contextURL.getKeyPath()).append(')');
+    }    
+    if (contextURL.getNavOrPropertyPath() != null) {
+      result.append('/').append(contextURL.getNavOrPropertyPath());
+    }
+    return result.toString();
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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
index 9dac341..4be20fc 100644
--- 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
@@ -18,17 +18,21 @@
  */
 package org.apache.olingo.server.core.responses;
 
+import java.util.List;
 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.EdmAction;
 import org.apache.olingo.commons.api.edm.EdmComplexType;
+import org.apache.olingo.commons.api.edm.EdmFunction;
 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.commons.api.http.HttpHeader;
 import org.apache.olingo.commons.api.http.HttpStatusCode;
+import org.apache.olingo.commons.core.Encoder;
 import org.apache.olingo.server.api.ODataApplicationException;
 import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ODataServerError;
@@ -40,6 +44,7 @@ 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;
+import org.apache.olingo.server.core.serializer.utils.ContentTypeHelper;
 
 public class PropertyResponse extends ServiceResponse {
   private PrimitiveSerializerOptions primitiveOptions;
@@ -108,6 +113,24 @@ public class PropertyResponse extends ServiceResponse {
       writeNoContent(true);
       return;
     }
+    
+    if (ContentTypeHelper.isODataMetadataFull(this.responseContentType)) {
+      ContextURL contextURL = (this.complexOptions != null)
+          ? this.complexOptions.getContextURL()
+          : this.primitiveOptions.getContextURL();
+      EdmAction action = this.metadata.getEdm().getBoundActionWithBindingType(
+          edmType.getFullQualifiedName(), this.collection);
+      if (action != null) {
+        property.getOperations().add(buildOperation(action, buildOperationTarget(contextURL)));
+      }
+      
+      List<EdmFunction> functions = this.metadata.getEdm()
+          .getBoundFunctionsWithBindingType(edmType.getFullQualifiedName(), this.collection);
+      
+      for (EdmFunction function:functions) {
+        property.getOperations().add(buildOperation(function, buildOperationTarget(contextURL)));
+      }
+    }    
 
     if (edmType.getKind() == EdmTypeKind.PRIMITIVE) {
       writePrimitiveProperty((EdmPrimitiveType) edmType, property);
@@ -170,5 +193,25 @@ public class PropertyResponse extends ServiceResponse {
   public void writeNotModified() {
     this.response.setStatusCode(HttpStatusCode.NOT_MODIFIED.getStatusCode());
     close();
+  }
+  
+  private String buildOperationTarget(ContextURL contextURL) {
+    StringBuilder result = new StringBuilder();
+    if (contextURL.getServiceRoot() != null) {
+      result.append(contextURL.getServiceRoot());
+    }
+    if (contextURL.getEntitySetOrSingletonOrType() != null) {
+      if (result.length() != 0) {
+        result.append("/");
+      }
+      result.append(Encoder.encode(contextURL.getEntitySetOrSingletonOrType()));
+    }
+    if (contextURL.getKeyPath() != null) {
+      result.append('(').append(contextURL.getKeyPath()).append(')');
+    }    
+    if (contextURL.getNavOrPropertyPath() != null) {
+      result.append('/').append(contextURL.getNavOrPropertyPath());
+    }
+    return result.toString();
   }  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java
index 17dd272..d0a9f23 100644
--- a/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java
+++ b/lib/server-core-ext/src/main/java/org/apache/olingo/server/core/responses/ServiceResponse.java
@@ -20,14 +20,19 @@
 package org.apache.olingo.server.core.responses;
 
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Map;
 
+import org.apache.olingo.commons.api.data.Operation;
+import org.apache.olingo.commons.api.edm.EdmAction;
+import org.apache.olingo.commons.api.edm.EdmFunction;
+import org.apache.olingo.commons.api.edm.EdmParameter;
 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.ODataLibraryException;
+import org.apache.olingo.server.api.ODataResponse;
 import org.apache.olingo.server.api.ServiceMetadata;
 
 public abstract class ServiceResponse {
@@ -126,4 +131,47 @@ public abstract class ServiceResponse {
 
   public abstract void accepts(ServiceResponseVisior visitor) throws ODataLibraryException,
       ODataApplicationException;
+  
+  protected static Operation buildOperation(EdmFunction function, String id) {
+    String fqn = function.getFullQualifiedName().getFullQualifiedNameAsString();
+    Operation operation = new Operation();          
+    operation.setType(Operation.Type.FUNCTION);
+    operation.setTitle(fqn);
+    StringBuilder params = new StringBuilder();
+    StringBuilder nameFQN = new StringBuilder();
+    params.append(fqn);
+    nameFQN.append(fqn);
+    if (!function.getParameterNames().isEmpty() && function.getParameterNames().size() > 1) {
+      params.append("(");
+      nameFQN.append("(");
+      boolean first = true;
+      for (int i = 1; i < function.getParameterNames().size(); i++) {
+        String parameterName = function.getParameterNames().get(i);
+        EdmParameter p = function.getParameter(parameterName);
+        if (first) {
+          first = false;
+        } else {
+          params.append(",");
+          nameFQN.append(",");                
+        }
+        params.append(p.getName()).append("=").append("@").append(p.getName());
+        nameFQN.append(p.getName());
+      }            
+      params.append(")");
+      nameFQN.append(")");
+    }
+    operation.setMetadataAnchor("#"+nameFQN);
+    operation.setTarget(URI.create(id+"/"+params.toString()));
+    return operation;
+  }
+
+  protected Operation buildOperation(EdmAction action, String id) {
+    String fqn = action.getFullQualifiedName().getFullQualifiedNameAsString();
+    Operation operation = new Operation();
+    operation.setMetadataAnchor("#"+fqn);
+    operation.setType(Operation.Type.ACTION);
+    operation.setTitle(fqn);
+    operation.setTarget(URI.create(id+"/"+fqn));
+    return operation;
+  }  
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
----------------------------------------------------------------------
diff --git a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
index 1299f68..5d7e2b2 100644
--- a/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
+++ b/lib/server-core-ext/src/test/java/org/apache/olingo/server/example/TripPinServiceTest.java
@@ -163,6 +163,30 @@ public class TripPinServiceTest {
   }
 
   @Test
+  public void testReadEntityWithFullMetadata() throws Exception {
+    HttpResponse response = httpGET(
+        baseURL+ "/People('russellwhyte')?$format=application/json;odata.metadata=full",
+        200);
+    JsonNode node = getJSONNode(response);
+    assertEquals("#Collection(String)", node.get("Emails@odata.type").asText());
+    assertEquals("Microsoft.OData.SampleService.Models.TripPin.ShareTrip",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.ShareTrip").get("title").asText());
+    assertEquals("/People('russellwhyte')/Microsoft.OData.SampleService.Models.TripPin.ShareTrip",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.ShareTrip").get("target").asText());    
+
+    assertEquals("Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline").get("title").asText());
+    assertEquals("/People('russellwhyte')/Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFavoriteAirline").get("target").asText());    
+
+    assertEquals("Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips(userName)").get("title").asText());
+    assertEquals("/People('russellwhyte')/Microsoft.OData."
+        + "SampleService.Models.TripPin.GetFriendsTrips(userName=@userName)",
+        node.get("#Microsoft.OData.SampleService.Models.TripPin.GetFriendsTrips(userName)").get("target").asText());
+  }
+  
+  @Test
   public void testErrorResponse() throws Exception {
     HttpResponse response = httpGET(baseURL + "/Airlines(1)", 400);
     Header[] headers = response.getHeaders("Content-Type");

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/3c0225c9/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/3c0225c9/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/3c0225c9/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());


Mime
View raw message