You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by sk...@apache.org on 2014/05/12 10:07:43 UTC

[05/17] git commit: [OLINGO-260] provided auth request integration test on proxy

[OLINGO-260] provided auth request integration test on proxy


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

Branch: refs/heads/olingo-266-ref
Commit: ce8d9932a81304e1ba8e6085fe76b8010c9b02a0
Parents: b497634
Author: fmartelli <fa...@gmail.com>
Authored: Fri May 9 14:30:45 2014 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Fri May 9 14:30:45 2014 +0200

----------------------------------------------------------------------
 .../ext/proxy/EntityContainerFactory.java       |   5 +
 .../commons/AbstractTypeInvocationHandler.java  | 178 +++++++------------
 .../commons/ComplexTypeInvocationHandler.java   |  73 +++++---
 .../commons/EntityTypeInvocationHandler.java    | 107 +++++++++--
 .../olingo/ext/proxy/utils/EngineUtils.java     |   6 +-
 .../proxy/v3/AuthEntityRetrieveTestITCase.java  |  50 ++++++
 .../proxy/v4/AuthEntityRetrieveTestITCase.java  |  49 +++++
 .../olingo/fit/v4/DerivedTypeTestITCase.java    |   3 +-
 .../olingo/client/api/op/CommonODataBinder.java |   9 +
 .../client/core/op/impl/v3/ODataBinderImpl.java |   9 +-
 .../client/core/op/impl/v4/ODataBinderImpl.java |   9 +-
 .../core/v3/EdmEnabledODataClientImpl.java      |   3 +
 .../core/v4/EdmEnabledODataClientImpl.java      |   3 +
 13 files changed, 344 insertions(+), 160 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
index 4d70364..c9e832a 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/EntityContainerFactory.java
@@ -22,6 +22,7 @@ import java.lang.reflect.Proxy;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.olingo.client.api.CommonConfiguration;
 import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
 import org.apache.olingo.client.core.ODataClientFactory;
 import org.apache.olingo.commons.api.format.ODataPubFormat;
@@ -80,6 +81,10 @@ public class EntityContainerFactory {
     this.serviceRoot = serviceRoot;
   }
 
+  public CommonConfiguration getConfiguration() {
+    return client.getConfiguration();
+  }
+
   public String getServiceRoot() {
     return serviceRoot;
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractTypeInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractTypeInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractTypeInvocationHandler.java
index 0ed9975..968852f 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractTypeInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractTypeInvocationHandler.java
@@ -24,11 +24,8 @@ import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.net.URI;
-import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
 import org.apache.commons.lang3.ArrayUtils;
 import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
 import org.apache.olingo.client.api.communication.response.ODataRetrieveResponse;
@@ -58,14 +55,6 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
 
   protected final Class<?> typeRef;
 
-  protected Map<String, Object> propertyChanges = new HashMap<String, Object>();
-
-  protected Map<NavigationProperty, Object> linkChanges = new HashMap<NavigationProperty, Object>();
-
-  protected int propertiesTag;
-
-  protected int linksTag;
-
   protected final EntityContext entityContext = EntityContainerFactory.getContext().entityContext();
 
   protected final EntityTypeInvocationHandler<C> targetHandler;
@@ -81,8 +70,6 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
     super(client, containerHandler);
     this.internal = internal;
     this.typeRef = typeRef;
-    this.propertiesTag = 0;
-    this.linksTag = 0;
     this.targetHandler = EntityTypeInvocationHandler.class.cast(this);
   }
 
@@ -94,8 +81,6 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
     super(client, targetHandler.containerHandler);
     this.internal = internal;
     this.typeRef = typeRef;
-    this.propertiesTag = 0;
-    this.linksTag = 0;
     this.targetHandler = targetHandler;
   }
 
@@ -105,14 +90,6 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
     return typeRef;
   }
 
-  public Map<String, Object> getPropertyChanges() {
-    return propertyChanges;
-  }
-
-  public Map<NavigationProperty, Object> getLinkChanges() {
-    return linkChanges;
-  }
-
   @Override
   @SuppressWarnings("unchecked")
   public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
@@ -183,7 +160,12 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
         throw new UnsupportedOperationException("Unsupported method " + method.getName());
       }
 
-      return newComplex(property.name(), getter.getReturnType());
+      final ComplexTypeInvocationHandler<C> complexTypeHandler = newComplex(property.name(), getter.getReturnType());
+
+      return Proxy.newProxyInstance(
+              Thread.currentThread().getContextClassLoader(),
+              new Class<?>[] {getter.getReturnType()},
+              complexTypeHandler);
     } else {
       throw new UnsupportedOperationException("Method not found: " + method);
     }
@@ -210,7 +192,7 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
   }
 
   @SuppressWarnings({"unchecked"})
-  protected <NE> NE newComplex(final String propertyName, final Class<NE> reference) {
+  protected ComplexTypeInvocationHandler<C> newComplex(final String propertyName, final Class<?> reference) {
     final Class<?> complexTypeRef;
     final boolean isCollection;
     if (Collection.class.isAssignableFrom(reference)) {
@@ -232,35 +214,19 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
     final ODataComplexValue<? extends CommonODataProperty> complex =
             client.getObjectFactory().newComplexValue(typeName.toString());
 
-    final ComplexTypeInvocationHandler<?> handler =
-            ComplexTypeInvocationHandler.getInstance(complex, complexTypeRef, targetHandler);
-
-    if (isCollection) {
-      Object value = propertyChanges.get(propertyName);
-
-      if (value == null) {
-        value = new ArrayList<ComplexTypeInvocationHandler<?>>();
-        propertyChanges.put(propertyName, value);
-      }
-
-      ((Collection<ComplexTypeInvocationHandler<?>>) value).add(handler);
-    } else {
-      propertyChanges.put(propertyName, handler);
-    }
+    final ComplexTypeInvocationHandler<C> handler = (ComplexTypeInvocationHandler<C>) ComplexTypeInvocationHandler.
+            getInstance(complex, complexTypeRef, targetHandler);
 
     attach(AttachedEntityStatus.CHANGED);
 
-    return (NE) Proxy.newProxyInstance(
-            Thread.currentThread().getContextClassLoader(),
-            new Class<?>[] {complexTypeRef},
-            handler);
+    addPropertyChanges(propertyName, handler, isCollection);
+
+    return handler;
   }
 
-  private Object getNavigationPropertyValue(final NavigationProperty property, final Method getter) {
-    if (!(internal instanceof ODataLinked)) {
-      throw new UnsupportedOperationException("Internal object is not navigable");
-    }
+  protected abstract Object getNavigationPropertyValue(final NavigationProperty property, final Method getter);
 
+  protected Object retriveNavigationProperty(final NavigationProperty property, final Method getter) {
     final Class<?> type = getter.getReturnType();
     final Class<?> collItemType;
     if (AbstractEntityCollection.class.isAssignableFrom(type)) {
@@ -273,58 +239,48 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
 
     final Object navPropValue;
 
-    if (linkChanges.containsKey(property)) {
-      navPropValue = linkChanges.get(property);
+    final ODataLink link = ((ODataLinked) internal).getNavigationLink(property.name());
+    if (link instanceof ODataInlineEntity) {
+      // return entity
+      navPropValue = getEntityProxy(
+              ((ODataInlineEntity) link).getEntity(),
+              property.targetContainer(),
+              property.targetEntitySet(),
+              type,
+              false);
+    } else if (link instanceof ODataInlineEntitySet) {
+      // return entity set
+      navPropValue = getEntityCollection(
+              collItemType,
+              type,
+              property.targetContainer(),
+              ((ODataInlineEntitySet) link).getEntitySet(),
+              link.getLink(),
+              false);
     } else {
-      final ODataLink link = ((ODataLinked) internal).getNavigationLink(property.name());
-      if (link instanceof ODataInlineEntity) {
-        // return entity
-        navPropValue = getEntityProxy(
-                ((ODataInlineEntity) link).getEntity(),
-                property.targetContainer(),
-                property.targetEntitySet(),
-                type,
-                false);
-      } else if (link instanceof ODataInlineEntitySet) {
-        // return entity set
+      // navigate
+      final URI uri = URIUtils.getURI(
+              containerHandler.getFactory().getServiceRoot(), link.getLink().toASCIIString());
+
+      if (AbstractEntityCollection.class.isAssignableFrom(type)) {
         navPropValue = getEntityCollection(
                 collItemType,
                 type,
                 property.targetContainer(),
-                ((ODataInlineEntitySet) link).getEntitySet(),
-                link.getLink(),
-                false);
+                client.getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody(),
+                uri,
+                true);
       } else {
-        // navigate
-        final URI uri = URIUtils.getURI(
-                containerHandler.getFactory().getServiceRoot(), link.getLink().toASCIIString());
-
-        if (AbstractEntityCollection.class.isAssignableFrom(type)) {
-          navPropValue = getEntityCollection(
-                  collItemType,
-                  type,
-                  property.targetContainer(),
-                  client.getRetrieveRequestFactory().getEntitySetRequest(uri).execute().getBody(),
-                  uri,
-                  true);
-        } else {
-          final ODataRetrieveResponse<CommonODataEntity> res =
-                  client.getRetrieveRequestFactory().getEntityRequest(uri).execute();
-
-          navPropValue = getEntityProxy(
-                  res.getBody(),
-                  property.targetContainer(),
-                  property.targetEntitySet(),
-                  type,
-                  res.getETag(),
-                  true);
-        }
-      }
+        final ODataRetrieveResponse<CommonODataEntity> res =
+                client.getRetrieveRequestFactory().getEntityRequest(uri).execute();
 
-      if (navPropValue != null) {
-        int checkpoint = linkChanges.hashCode();
-        linkChanges.put(property, navPropValue);
-        updateLinksTag(checkpoint);
+        navPropValue = getEntityProxy(
+                res.getBody(),
+                property.targetContainer(),
+                property.targetEntitySet(),
+                type,
+                res.getETag(),
+                true);
       }
     }
 
@@ -337,6 +293,11 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
     return getPropertyValue(property.name(), type);
   }
 
+  public void addAdditionalProperty(final String name, final Object value) {
+    addPropertyChanges(name, value, false);
+    attach(AttachedEntityStatus.CHANGED);
+  }
+
   public Object getAdditionalProperty(final String name) {
     return getPropertyValue(name, null);
   }
@@ -359,40 +320,25 @@ public abstract class AbstractTypeInvocationHandler<C extends CommonEdmEnabledOD
       }
 
       @SuppressWarnings("unchecked")
-      final EntityTypeInvocationHandler<C> targetHandler = (EntityTypeInvocationHandler<C>) etih;
-      if (!targetHandler.getTypeRef().isAnnotationPresent(EntityType.class)) {
-        throw new IllegalArgumentException("Invalid argument type " + targetHandler.getTypeRef().getSimpleName());
+      final EntityTypeInvocationHandler<C> linkedHandler = (EntityTypeInvocationHandler<C>) etih;
+      if (!linkedHandler.getTypeRef().isAnnotationPresent(EntityType.class)) {
+        throw new IllegalArgumentException("Invalid argument type " + linkedHandler.getTypeRef().getSimpleName());
       }
 
-      if (!entityContext.isAttached(targetHandler)) {
-        entityContext.attach(targetHandler, AttachedEntityStatus.LINKED);
+      if (!entityContext.isAttached(linkedHandler)) {
+        entityContext.attach(linkedHandler, AttachedEntityStatus.LINKED);
       }
     }
 
     // 3) add links
-    linkChanges.put(property, value);
+    addLinkChanges(property, value);
   }
 
   protected abstract void setPropertyValue(final Property property, final Object value);
 
-  public void addAdditionalProperty(final String name, final Object value) {
-    propertyChanges.put(name, value);
-    if (!entityContext.isAttached(targetHandler)) {
-      entityContext.attach(targetHandler, AttachedEntityStatus.CHANGED);
-    }
-  }
+  protected abstract void addPropertyChanges(final String name, final Object value, final boolean isCollection);
 
-  protected void updatePropertiesTag(final int checkpoint) {
-    if (checkpoint == propertiesTag) {
-      propertiesTag = propertyChanges.hashCode();
-    }
-  }
-
-  private void updateLinksTag(final int checkpoint) {
-    if (checkpoint == linksTag) {
-      linksTag = linkChanges.hashCode();
-    }
-  }
+  protected abstract void addLinkChanges(final NavigationProperty navProp, final Object value);
 
   public abstract boolean isChanged();
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexTypeInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexTypeInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexTypeInvocationHandler.java
index 40dd5c2..05aa7ff 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexTypeInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/ComplexTypeInvocationHandler.java
@@ -20,6 +20,7 @@ package org.apache.olingo.ext.proxy.commons;
 
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.util.Collection;
 import java.util.HashSet;
@@ -28,9 +29,15 @@ import java.util.Set;
 import org.apache.olingo.client.api.CommonEdmEnabledODataClient;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
 import org.apache.olingo.commons.api.domain.ODataComplexValue;
+import org.apache.olingo.commons.api.domain.ODataLinked;
+import org.apache.olingo.commons.api.edm.EdmElement;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
+import org.apache.olingo.commons.core.edm.EdmTypeInfo;
+import org.apache.olingo.ext.proxy.api.annotations.ComplexType;
+import org.apache.olingo.ext.proxy.api.annotations.NavigationProperty;
 import org.apache.olingo.ext.proxy.api.annotations.Property;
 import org.apache.olingo.ext.proxy.context.AttachedEntityStatus;
+import org.apache.olingo.ext.proxy.utils.ClassUtils;
 import org.apache.olingo.ext.proxy.utils.EngineUtils;
 
 public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?>>
@@ -57,10 +64,6 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
 
   public void setComplex(final ODataComplexValue<?> complex) {
     this.internal = complex;
-    this.propertyChanges.clear();
-    this.linkChanges.clear();
-    this.propertiesTag = 0;
-    this.linksTag = 0;
   }
 
   @Override
@@ -68,8 +71,9 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
     return new FullQualifiedName(((ODataComplexValue<?>) this.internal).getTypeName());
   }
 
-  public ODataComplexValue<?> getComplex() {
-    return (ODataComplexValue<?>) this.internal;
+  @SuppressWarnings("unchecked")
+  public ODataComplexValue<CommonODataProperty> getComplex() {
+    return (ODataComplexValue<CommonODataProperty>) this.internal;
   }
 
   @Override
@@ -79,10 +83,13 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
 
       final CommonODataProperty property = getComplex().get(name);
 
-      if (propertyChanges.containsKey(name)) {
-        res = propertyChanges.get(name);
-      } else if (property.hasComplexValue()) {
-        res = newComplex(name, (Class<?>) type);
+      if (property.hasComplexValue()) {
+
+        res = Proxy.newProxyInstance(
+                Thread.currentThread().getContextClassLoader(),
+                new Class<?>[] {(Class<?>) type},
+                newComplex(name, (Class<?>) type));
+
         EngineUtils.populate(
                 client.getCachedEdm(),
                 res,
@@ -90,16 +97,9 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
                 Property.class,
                 property.getValue().asComplex().iterator());
       } else {
-
         res = type == null
                 ? EngineUtils.getValueFromProperty(client.getCachedEdm(), property)
                 : EngineUtils.getValueFromProperty(client.getCachedEdm(), property, type);
-
-        if (res != null) {
-          int checkpoint = propertyChanges.hashCode();
-          propertyChanges.put(name, res);
-          updatePropertiesTag(checkpoint);
-        }
       }
 
       return res;
@@ -110,21 +110,18 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
 
   @Override
   public Collection<String> getAdditionalPropertyNames() {
-    final Set<String> res = new HashSet<String>(propertyChanges.keySet());
+    final Set<String> res = new HashSet<String>();
     final Set<String> propertyNames = new HashSet<String>();
     for (Method method : typeRef.getMethods()) {
       final Annotation ann = method.getAnnotation(Property.class);
       if (ann != null) {
         final String property = ((Property) ann).name();
         propertyNames.add(property);
-
-        // maybe someone could add a normal attribute to the additional set
-        res.remove(property);
       }
     }
 
-    for (Iterator<?> itor = ((ODataComplexValue<?>) this.internal).iterator(); itor.hasNext();) {
-      CommonODataProperty property = (CommonODataProperty) itor.next();
+    for (Iterator<? extends CommonODataProperty> itor = getComplex().iterator(); itor.hasNext();) {
+      final CommonODataProperty property = itor.next();
       if (!propertyNames.contains(property.getName())) {
         res.add(property.getName());
       }
@@ -135,7 +132,16 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
 
   @Override
   protected void setPropertyValue(final Property property, final Object value) {
-    propertyChanges.put(property.name(), value);
+    final FullQualifiedName fqn =
+            new FullQualifiedName(ClassUtils.getNamespace(typeRef), typeRef.getAnnotation(ComplexType.class).name());
+
+    final EdmElement edmProperty = client.getCachedEdm().getComplexType(fqn).getProperty(property.name());
+
+    final EdmTypeInfo type = new EdmTypeInfo.Builder().
+            setEdm(client.getCachedEdm()).setTypeExpression(
+            edmProperty.isCollection() ? "Collection(" + property.type() + ")" : property.type()).build();
+
+    client.getBinder().add(getComplex(), EngineUtils.getODataProperty(client, property.name(), type, value));
 
     if (!entityContext.isAttached(targetHandler)) {
       entityContext.attach(targetHandler, AttachedEntityStatus.CHANGED);
@@ -143,6 +149,25 @@ public class ComplexTypeInvocationHandler<C extends CommonEdmEnabledODataClient<
   }
 
   @Override
+  protected Object getNavigationPropertyValue(final NavigationProperty property, final Method getter) {
+    if (!(internal instanceof ODataLinked)) {
+      throw new UnsupportedOperationException("Internal object is not navigable");
+    }
+
+    return retriveNavigationProperty(property, getter);
+  }
+
+  @Override
+  protected void addPropertyChanges(final String name, final Object value, final boolean isCollection) {
+    // do nothing ....
+  }
+
+  @Override
+  protected void addLinkChanges(final NavigationProperty navProp, final Object value) {
+    // do nothing ....
+  }
+
+  @Override
   public boolean isChanged() {
     return targetHandler.isChanged();
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityTypeInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityTypeInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityTypeInvocationHandler.java
index 4feeee7..7c4ea37 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityTypeInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityTypeInvocationHandler.java
@@ -21,8 +21,10 @@ package org.apache.olingo.ext.proxy.commons;
 import java.io.InputStream;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.net.URI;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -39,6 +41,7 @@ import org.apache.olingo.commons.api.domain.ODataLinked;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ODataMediaFormat;
 import org.apache.olingo.ext.proxy.api.annotations.EntityType;
+import org.apache.olingo.ext.proxy.api.annotations.NavigationProperty;
 import org.apache.olingo.ext.proxy.api.annotations.Property;
 import org.apache.olingo.ext.proxy.context.AttachedEntityStatus;
 import org.apache.olingo.ext.proxy.context.EntityUUID;
@@ -51,6 +54,14 @@ public class EntityTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?
 
   private CommonODataEntity entity;
 
+  protected Map<String, Object> propertyChanges = new HashMap<String, Object>();
+
+  protected Map<NavigationProperty, Object> linkChanges = new HashMap<NavigationProperty, Object>();
+
+  protected int propertiesTag = 0;
+
+  protected int linksTag = 0;
+
   private Map<String, InputStream> streamedPropertyChanges = new HashMap<String, InputStream>();
 
   private InputStream stream;
@@ -157,22 +168,51 @@ public class EntityTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?
     this.entity.setETag(eTag);
   }
 
+  public Map<String, Object> getPropertyChanges() {
+    return propertyChanges;
+  }
+
+  public Map<NavigationProperty, Object> getLinkChanges() {
+    return linkChanges;
+  }
+
+  private void updatePropertiesTag(final int checkpoint) {
+    if (checkpoint == propertiesTag) {
+      propertiesTag = propertyChanges.hashCode();
+    }
+  }
+
+  private void updateLinksTag(final int checkpoint) {
+    if (checkpoint == linksTag) {
+      linksTag = linkChanges.hashCode();
+    }
+  }
+
   @Override
   protected Object getPropertyValue(final String name, final Type type) {
     try {
       final Object res;
-      
+
       final CommonODataProperty property = entity.getProperty(name);
-      
+
       if (propertyChanges.containsKey(name)) {
-        res = propertyChanges.get(name);
+        res = property.hasComplexValue()
+                ? Proxy.newProxyInstance(
+                Thread.currentThread().getContextClassLoader(),
+                new Class<?>[] {(Class<?>) type},
+                (ComplexTypeInvocationHandler<?>) propertyChanges.get(name))
+                : propertyChanges.get(name);
       } else if (property.hasComplexValue()) {
-        res = newComplex(name, (Class<?>) type);
+        res = Proxy.newProxyInstance(
+                Thread.currentThread().getContextClassLoader(),
+                new Class<?>[] {(Class<?>) type},
+                newComplex(name, (Class<?>) type));
+
         EngineUtils.populate(
-                client.getCachedEdm(), 
-                res, 
-                (Class<?>) type, 
-                Property.class, 
+                client.getCachedEdm(),
+                res,
+                (Class<?>) type,
+                Property.class,
                 property.getValue().asComplex().iterator());
       } else {
 
@@ -181,9 +221,7 @@ public class EntityTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?
                 : EngineUtils.getValueFromProperty(client.getCachedEdm(), property, type);
 
         if (res != null) {
-          int checkpoint = propertyChanges.hashCode();
-          propertyChanges.put(name, res);
-          updatePropertiesTag(checkpoint);
+          addPropertyChanges(name, res, false);
         }
       }
 
@@ -222,7 +260,7 @@ public class EntityTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?
     if (property.type().equalsIgnoreCase("Edm.Stream")) {
       setStreamedProperty(property, (InputStream) value);
     } else {
-      propertyChanges.put(property.name(), value);
+      addPropertyChanges(property.name(), value, false);
     }
 
     attach(AttachedEntityStatus.CHANGED);
@@ -304,6 +342,51 @@ public class EntityTypeInvocationHandler<C extends CommonEdmEnabledODataClient<?
   }
 
   @Override
+  protected Object getNavigationPropertyValue(final NavigationProperty property, final Method getter) {
+    final Object navPropValue;
+
+    if (linkChanges.containsKey(property)) {
+      navPropValue = linkChanges.get(property);
+    } else {
+      navPropValue = retriveNavigationProperty(property, getter);
+    }
+
+    if (navPropValue != null) {
+      addLinkChanges(property, navPropValue);
+    }
+
+    return navPropValue;
+  }
+
+  @Override
+  @SuppressWarnings("unchecked")
+  protected void addPropertyChanges(final String name, final Object value, final boolean isCollection) {
+    int checkpoint = propertyChanges.hashCode();
+
+    if (isCollection) {
+      Object collItem = propertyChanges.get(name);
+
+      if (collItem == null) {
+        collItem = new ArrayList<Object>();
+        propertyChanges.put(name, collItem);
+      }
+
+      ((Collection<Object>) collItem).add(value);
+    } else {
+      propertyChanges.put(name, value);
+    }
+
+    updatePropertiesTag(checkpoint);
+  }
+
+  @Override
+  protected void addLinkChanges(final NavigationProperty navProp, final Object value) {
+    int checkpoint = linkChanges.hashCode();
+    linkChanges.put(navProp, value);
+    updateLinksTag(checkpoint);
+  }
+
+  @Override
   public String toString() {
     return uuid.toString();
   }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/EngineUtils.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/EngineUtils.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/EngineUtils.java
index 801250a..b66461f 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/EngineUtils.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/utils/EngineUtils.java
@@ -127,7 +127,7 @@ public final class EngineUtils {
     return value;
   }
 
-  private static CommonODataProperty getODataEntityProperty(
+  private static CommonODataProperty getODataProperty(
           final CommonEdmEnabledODataClient<?> client,
           final FullQualifiedName entity,
           final String property,
@@ -151,7 +151,7 @@ public final class EngineUtils {
     return getODataProperty(client, property, type, obj);
   }
 
-  private static CommonODataProperty getODataProperty(
+  public static CommonODataProperty getODataProperty(
           final CommonEdmEnabledODataClient<?> client, final String name, final EdmTypeInfo type, final Object obj) {
     final CommonODataProperty oprop;
 
@@ -200,7 +200,7 @@ public final class EngineUtils {
       }
 
       ((List<CommonODataProperty>) entity.getProperties()).add(
-              getODataEntityProperty(client, entity.getTypeName(), property.getKey(), property.getValue()));
+              getODataProperty(client, entity.getTypeName(), property.getKey(), property.getValue()));
     }
   }
 

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/fit/src/test/java/org/apache/olingo/fit/proxy/v3/AuthEntityRetrieveTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v3/AuthEntityRetrieveTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v3/AuthEntityRetrieveTestITCase.java
new file mode 100644
index 0000000..c995f2b
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v3/AuthEntityRetrieveTestITCase.java
@@ -0,0 +1,50 @@
+/*
+ * 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.proxy.v3;
+
+import static org.junit.Assert.assertNotNull;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import org.apache.olingo.client.core.http.BasicAuthHttpClientFactory;
+import org.apache.olingo.client.core.http.DefaultHttpClientFactory;
+import org.apache.olingo.ext.proxy.EntityContainerFactory;
+import org.apache.olingo.fit.proxy.v3.staticservice.microsoft.test.odata.services.astoriadefaultservice.
+        DefaultContainer;
+
+public class AuthEntityRetrieveTestITCase extends EntityRetrieveTestITCase {
+
+  @BeforeClass
+  public static void enableBasicAuth() {
+    containerFactory.getConfiguration().
+            setHttpClientFactory(new BasicAuthHttpClientFactory("odatajclient", "odatajclient"));
+  }
+
+  @AfterClass
+  public static void disableBasicAuth() {
+    containerFactory.getConfiguration().setHttpClientFactory(new DefaultHttpClientFactory());
+  }
+
+  @BeforeClass
+  public static void setupContaner() {
+    containerFactory = EntityContainerFactory.getV3Instance(testAuthServiceRootURL);
+    container = containerFactory.getEntityContainer(DefaultContainer.class);
+    assertNotNull(container);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AuthEntityRetrieveTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AuthEntityRetrieveTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AuthEntityRetrieveTestITCase.java
new file mode 100644
index 0000000..0d327a7
--- /dev/null
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/AuthEntityRetrieveTestITCase.java
@@ -0,0 +1,49 @@
+/*
+ * 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.proxy.v4;
+
+import org.apache.olingo.client.core.http.BasicAuthHttpClientFactory;
+import org.apache.olingo.client.core.http.DefaultHttpClientFactory;
+import org.apache.olingo.ext.proxy.EntityContainerFactory;
+import org.apache.olingo.fit.proxy.v4.staticservice.microsoft.test.odata.services.odatawcfservice.InMemoryEntities;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public class AuthEntityRetrieveTestITCase extends EntityRetrieveTestITCase {
+
+  @BeforeClass
+  public static void enableBasicAuth() {
+    containerFactory.getConfiguration().
+            setHttpClientFactory(new BasicAuthHttpClientFactory("odatajclient", "odatajclient"));
+  }
+
+  @AfterClass
+  public static void disableBasicAuth() {
+    containerFactory.getConfiguration().setHttpClientFactory(new DefaultHttpClientFactory());
+  }
+
+  @BeforeClass
+  public static void setupContaner() {
+    containerFactory = EntityContainerFactory.getV3Instance(testAuthServiceRootURL);
+    container = containerFactory.getEntityContainer(InMemoryEntities.class);
+    assertNotNull(container);
+  }
+}

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/fit/src/test/java/org/apache/olingo/fit/v4/DerivedTypeTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/v4/DerivedTypeTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/v4/DerivedTypeTestITCase.java
index 9cbb779..c594183 100644
--- a/fit/src/test/java/org/apache/olingo/fit/v4/DerivedTypeTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/v4/DerivedTypeTestITCase.java
@@ -30,6 +30,7 @@ import org.apache.olingo.commons.api.domain.ODataComplexValue;
 import org.apache.olingo.commons.api.domain.v4.ODataEntity;
 import org.apache.olingo.commons.api.domain.v4.ODataEntitySet;
 import org.apache.olingo.commons.api.domain.v4.ODataProperty;
+import org.apache.olingo.commons.api.domain.v4.ODataValuable;
 import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
 import org.apache.olingo.commons.api.edm.FullQualifiedName;
 import org.apache.olingo.commons.api.format.ODataPubFormat;
@@ -125,7 +126,7 @@ public class DerivedTypeTestITCase extends AbstractTestITCase {
     final ODataEntity actual = fetchReq.execute().getBody();
     assertEquals("Microsoft.Test.OData.Services.ODataWCFService.Customer", actual.getTypeName().toString());
     assertEquals("Microsoft.Test.OData.Services.ODataWCFService.CompanyAddress",
-            actual.getProperty("HomeAddress").getValue().getTypeName());
+            ((ODataValuable)actual.getProperty("HomeAddress")).getValue().getTypeName());
     
     final ODataDeleteRequest deleteReq = client.getCUDRequestFactory().getDeleteRequest(actual.getEditLink());
     assertEquals(204, deleteReq.execute().getStatusCode());

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataBinder.java
----------------------------------------------------------------------
diff --git a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataBinder.java b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataBinder.java
index 08ee08d..cf7dc5c 100644
--- a/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataBinder.java
+++ b/lib/client-api/src/main/java/org/apache/olingo/client/api/op/CommonODataBinder.java
@@ -29,6 +29,7 @@ import org.apache.olingo.commons.api.domain.CommonODataEntity;
 import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
 import org.apache.olingo.commons.api.domain.ODataLink;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
 import org.apache.olingo.commons.api.domain.ODataServiceDocument;
 
 public interface CommonODataBinder extends Serializable {
@@ -70,6 +71,14 @@ public interface CommonODataBinder extends Serializable {
   Property getProperty(CommonODataProperty property, Class<? extends Entity> reference);
 
   /**
+   * Adds the given property to the given complex value.
+   *
+   * @param complex OData complex value.
+   * @param property OData property.
+   */
+  void add(ODataComplexValue<CommonODataProperty> complex, CommonODataProperty property);
+
+  /**
    * Adds the given property to the given entity.
    *
    * @param entity OData entity.

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
index 246c8e1..f977953 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v3/ODataBinderImpl.java
@@ -30,6 +30,7 @@ import org.apache.olingo.commons.api.data.v3.LinkCollection;
 import org.apache.olingo.commons.api.domain.CommonODataEntity;
 import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
 import org.apache.olingo.commons.api.domain.v3.ODataEntity;
 import org.apache.olingo.commons.api.domain.v3.ODataEntitySet;
 import org.apache.olingo.commons.api.domain.v3.ODataProperty;
@@ -46,6 +47,11 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
   }
 
   @Override
+  public void add(final ODataComplexValue<CommonODataProperty> complex, final CommonODataProperty property) {
+    complex.add((ODataProperty) property);
+  }
+
+  @Override
   public boolean add(final CommonODataEntity entity, final CommonODataProperty property) {
     return ((ODataEntity) entity).getProperties().add((ODataProperty) property);
   }
@@ -89,7 +95,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
     return new ODataPropertyImpl(property.getPayload().getName(),
             getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
-                    property.getPayload(), property.getContextURL(), property.getMetadataETag()));
+            property.getPayload(), property.getContextURL(), property.getMetadataETag()));
   }
 
   @Override
@@ -98,5 +104,4 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
     collection.setLinks(linkCollection.getLinks());
     return collection;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
index 4bcec5a..a4a38ea 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/op/impl/v4/ODataBinderImpl.java
@@ -44,6 +44,7 @@ import org.apache.olingo.commons.api.data.Value;
 import org.apache.olingo.commons.api.domain.CommonODataEntity;
 import org.apache.olingo.commons.api.domain.CommonODataEntitySet;
 import org.apache.olingo.commons.api.domain.CommonODataProperty;
+import org.apache.olingo.commons.api.domain.ODataComplexValue;
 import org.apache.olingo.commons.api.domain.ODataInlineEntity;
 import org.apache.olingo.commons.api.domain.ODataInlineEntitySet;
 import org.apache.olingo.commons.api.domain.ODataLinked;
@@ -84,6 +85,11 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
   }
 
   @Override
+  public void add(final ODataComplexValue<CommonODataProperty> complex, final CommonODataProperty property) {
+    complex.add((ODataProperty) property);
+  }
+
+  @Override
   public boolean add(final CommonODataEntity entity, final CommonODataProperty property) {
     return ((ODataEntity) entity).getProperties().add((ODataProperty) property);
   }
@@ -272,7 +278,7 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
     final ODataProperty property = new ODataPropertyImpl(resource.getPayload().getName(),
             getODataValue(typeInfo == null ? null : typeInfo.getFullQualifiedName(),
-                    resource.getPayload(), resource.getContextURL(), resource.getMetadataETag()));
+            resource.getPayload(), resource.getContextURL(), resource.getMetadataETag()));
     odataAnnotations(resource.getPayload(), property);
 
     return property;
@@ -375,5 +381,4 @@ public class ODataBinderImpl extends AbstractODataBinder implements ODataBinder
 
     return delta;
   }
-
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/EdmEnabledODataClientImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/EdmEnabledODataClientImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/EdmEnabledODataClientImpl.java
index 531d500..5d2cbe8 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/EdmEnabledODataClientImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/v3/EdmEnabledODataClientImpl.java
@@ -52,6 +52,9 @@ public class EdmEnabledODataClientImpl extends ODataClientImpl implements EdmEna
 
   @Override
   public Edm getCachedEdm() {
+    if (edm == null) {
+      getEdm(null);
+    }
     return this.edm;
   }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/ce8d9932/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/EdmEnabledODataClientImpl.java
----------------------------------------------------------------------
diff --git a/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/EdmEnabledODataClientImpl.java b/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/EdmEnabledODataClientImpl.java
index b42f269..fc0282b 100644
--- a/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/EdmEnabledODataClientImpl.java
+++ b/lib/client-core/src/main/java/org/apache/olingo/client/core/v4/EdmEnabledODataClientImpl.java
@@ -59,6 +59,9 @@ public class EdmEnabledODataClientImpl extends ODataClientImpl implements EdmEna
 
   @Override
   public Edm getCachedEdm() {
+    if (edm == null) {
+      getEdm(null);
+    }
     return this.edm;
   }
 }