You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by fm...@apache.org on 2014/07/28 22:06:17 UTC

git commit: [OLINGO-365] fix for link update via reference ID

Repository: olingo-odata4
Updated Branches:
  refs/heads/master 67cc0c440 -> a5e983c9b


[OLINGO-365] fix for link update via reference ID


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

Branch: refs/heads/master
Commit: a5e983c9b884be030f6bb548da3c512b44912206
Parents: 67cc0c4
Author: fmartelli <fa...@gmail.com>
Authored: Mon Jul 28 22:06:03 2014 +0200
Committer: fmartelli <fa...@gmail.com>
Committed: Mon Jul 28 22:06:03 2014 +0200

----------------------------------------------------------------------
 .../AbstractCollectionInvocationHandler.java    |  14 ++
 .../commons/AbstractPersistenceManager.java     | 133 +++++++++++++------
 .../proxy/commons/EntityInvocationHandler.java  |  16 ++-
 .../fit/proxy/v4/APIBasicDesignTestITCase.java  |   7 +
 4 files changed, 128 insertions(+), 42 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a5e983c9/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
index f1b9eb5..b06b594 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractCollectionInvocationHandler.java
@@ -56,6 +56,8 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
 
   protected Collection<String> referenceItems;
 
+  protected Collection<T> newest;
+
   protected final URI baseURI;
 
   protected CommonURIBuilder<?> uri;
@@ -67,6 +69,8 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
   private final Map<Class<? extends AbstractTerm>, Object> annotationsByTerm =
           new HashMap<Class<? extends AbstractTerm>, Object>();
 
+  private boolean changed = false;
+
   public AbstractCollectionInvocationHandler(
           final AbstractService<?> service,
           final Collection<T> items,
@@ -78,6 +82,7 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
     this.itemRef = itemRef;
     this.items = items;
     this.referenceItems = new ArrayList<String>();
+    this.newest = new ArrayList<T>();
     this.uri = uri;
     this.baseURI = this.uri == null ? null : this.uri.build();
   }
@@ -176,6 +181,8 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
         service.getContext().entityContext().attachNew(handler);
       }
     }
+    changed = true;
+    newest.add(element);
     return items.add(element);
   }
 
@@ -191,6 +198,7 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
         return false;
       }
 
+      changed = true;
       return referenceItems.add(id.toASCIIString());
     }
 
@@ -249,6 +257,8 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
 
   @Override
   public boolean addAll(final Collection<? extends T> collection) {
+    changed = true;
+    newest.addAll(collection);
     return items.addAll(collection);
   }
 
@@ -325,4 +335,8 @@ public abstract class AbstractCollectionInvocationHandler<T extends Serializable
     this.uri = this.baseURI == null ? null : getClient().newURIBuilder(baseURI.toASCIIString());
     this.nextPageURI = null;
   }
+
+  public boolean isChanged() {
+    return changed;
+  }
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a5e983c9/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
index 62b701a..03d9072 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/AbstractPersistenceManager.java
@@ -174,51 +174,13 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
               : ODataLinkType.ENTITY_NAVIGATION;
 
       final Set<EntityInvocationHandler> toBeLinked = new HashSet<EntityInvocationHandler>();
-
       for (Object proxy : type == ODataLinkType.ENTITY_SET_NAVIGATION
               ? (Collection<?>) property.getValue() : Collections.singleton(property.getValue())) {
 
         final EntityInvocationHandler target = (EntityInvocationHandler) Proxy.getInvocationHandler(proxy);
 
-        final AttachedEntityStatus status;
-        if (!service.getContext().entityContext().isAttached(target)) {
-          status = resolveNavigationLink(property.getKey(), target);
-        } else {
-          status = service.getContext().entityContext().getStatus(target);
-        }
-
-        LOG.debug("Found link to '{}({})'", target, status);
-
-        final URI editLink = target.getEntity().getEditLink();
-
-        if ((status == AttachedEntityStatus.ATTACHED || status == AttachedEntityStatus.LINKED) && !target.isChanged()) {
-          LOG.debug("Add link to '{}'", target);
-          entity.addLink(buildNavigationLink(
-                  property.getKey().name(),
-                  URIUtils.getURI(service.getClient().getServiceRoot(), editLink.toASCIIString()), type));
-        } else {
-          if (!items.contains(target)) {
-            pos = processEntityContext(target, pos, items, delayedUpdates, changeset);
-            pos++;
-          }
-
-          final Integer targetPos = items.get(target);
-          if (targetPos == null) {
-            // schedule update for the current object
-            LOG.debug("Schedule '{}' from '{}' to '{}'", type.name(), handler, target);
-            toBeLinked.add(target);
-          } else if (status == AttachedEntityStatus.CHANGED) {
-            LOG.debug("Changed: '{}' from '{}' to (${}) '{}'", type.name(), handler, targetPos, target);
-            entity.addLink(buildNavigationLink(
-                    property.getKey().name(),
-                    URIUtils.getURI(service.getClient().getServiceRoot(), editLink.toASCIIString()), type));
-          } else {
-            // create the link for the current object
-            LOG.debug("'{}' from '{}' to (${}) '{}'", type.name(), handler, targetPos, target);
-
-            entity.addLink(buildNavigationLink(property.getKey().name(), URI.create("$" + targetPos), type));
-          }
-        }
+        toBeLinked.addAll(processLinkChanges(
+                handler, target, property.getKey(), type, pos, items, delayedUpdates, changeset));
       }
 
       if (!toBeLinked.isEmpty()) {
@@ -236,6 +198,41 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
       }
     }
 
+    // Required by linking provided on existent object. Say: 
+    //                    container.getCustomers().getByKey(1).getOrders().add(order)
+    // Required by linking provided via entity reference ID. Say: 
+    //                    container.getCustomers().getByKey(1).getOrders().addRef(order)
+    for (Map.Entry<NavigationProperty, Object> property : handler.linkCache.entrySet()) {
+      if (property.getValue() instanceof Proxy) {
+        final InvocationHandler target = Proxy.getInvocationHandler(property.getValue());
+
+        if (target instanceof EntityCollectionInvocationHandler
+                && ((EntityCollectionInvocationHandler) target).isChanged()) {
+
+          final ODataLinkType type = Collection.class.isAssignableFrom(property.getValue().getClass())
+                  ? ODataLinkType.ENTITY_SET_NAVIGATION
+                  : ODataLinkType.ENTITY_NAVIGATION;
+
+          final Set<EntityInvocationHandler> toBeLinked = new HashSet<EntityInvocationHandler>();
+
+          for (Object proxy : ((EntityCollectionInvocationHandler) target).newest) {
+            final EntityInvocationHandler targetEntity = (EntityInvocationHandler) Proxy.getInvocationHandler(proxy);
+
+            toBeLinked.addAll(processLinkChanges(
+                    handler, targetEntity, property.getKey(), type, pos, items, delayedUpdates, changeset));
+          }
+
+          if (!toBeLinked.isEmpty()) {
+            delayedUpdates.add(new EntityLinkDesc(property.getKey().name(), handler, toBeLinked, type));
+          }
+
+          for (String ref : ((EntityCollectionInvocationHandler<?>) target).referenceItems) {
+            delayedUpdates.add(new EntityLinkDesc(property.getKey().name(), handler, ref));
+          }
+        }
+      }
+    }
+
     if (entity instanceof ODataEntity) {
       for (Map.Entry<String, AnnotatableInvocationHandler> entry : handler.getNavPropAnnotatableHandlers().entrySet()) {
 
@@ -305,6 +302,62 @@ abstract class AbstractPersistenceManager implements PersistenceManager {
     return pos;
   }
 
+  protected Set<EntityInvocationHandler> processLinkChanges(
+          final EntityInvocationHandler source,
+          final EntityInvocationHandler target,
+          final NavigationProperty property,
+          final ODataLinkType type,
+          int pos,
+          final TransactionItems items,
+          final List<EntityLinkDesc> delayedUpdates,
+          final PersistenceChanges changeset) {
+
+    final Set<EntityInvocationHandler> toBeLinked = new HashSet<EntityInvocationHandler>();
+
+    final AttachedEntityStatus status;
+    if (!service.getContext().entityContext().isAttached(target)) {
+      status = resolveNavigationLink(property, target);
+    } else {
+      status = service.getContext().entityContext().getStatus(target);
+    }
+
+    LOG.debug("Found link to '{}({})'", target, status);
+
+    final URI editLink = target.getEntity().getEditLink();
+
+    if ((status == AttachedEntityStatus.ATTACHED || status == AttachedEntityStatus.LINKED) && !target.isChanged()) {
+      LOG.debug("Add link to '{}'", target);
+      source.getEntity().addLink(buildNavigationLink(
+              property.name(),
+              URIUtils.getURI(service.getClient().getServiceRoot(), editLink.toASCIIString()), type));
+    } else {
+      if (!items.contains(target)) {
+        pos = processEntityContext(target, pos, items, delayedUpdates, changeset);
+        pos++;
+      }
+
+      final Integer targetPos = items.get(target);
+      if (targetPos == null) {
+        // schedule update for the current object
+        LOG.debug("Schedule '{}' from '{}' to '{}'", type.name(), source, target);
+        toBeLinked.add(target);
+      } else if (status == AttachedEntityStatus.CHANGED) {
+        LOG.debug("Changed: '{}' from '{}' to (${}) '{}'", type.name(), source, targetPos, target);
+        source.getEntity().addLink(buildNavigationLink(
+                property.name(),
+                URIUtils.getURI(service.getClient().getServiceRoot(), editLink.toASCIIString()), type));
+      } else {
+        // create the link for the current object
+        LOG.debug("'{}' from '{}' to (${}) '{}'", type.name(), source, targetPos, target);
+
+        source.getEntity().addLink(
+                buildNavigationLink(property.name(), URI.create("$" + targetPos), type));
+      }
+    }
+
+    return toBeLinked;
+  }
+
   protected void processDelayedUpdates(
           final List<EntityLinkDesc> delayedUpdates,
           int pos,

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a5e983c9/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
----------------------------------------------------------------------
diff --git a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
index 054604b..51d62ad 100644
--- a/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
+++ b/ext/client-proxy/src/main/java/org/apache/olingo/ext/proxy/commons/EntityInvocationHandler.java
@@ -294,10 +294,21 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
     return isChanged(true);
   }
 
-  public boolean isChanged(final boolean includeMedia) {
+  public boolean isChanged(final boolean deep) {
+    boolean linkedChanges = false;
+    for (Map.Entry<NavigationProperty, Object> link : linkCache.entrySet()) {
+      final InvocationHandler handler = Proxy.getInvocationHandler(link.getValue());
+      if (handler instanceof EntityInvocationHandler) {
+        linkedChanges = linkedChanges || ((EntityInvocationHandler) handler).isChanged();
+      } else if (handler instanceof EntityCollectionInvocationHandler) {
+        linkedChanges = linkedChanges || ((EntityCollectionInvocationHandler) handler).isChanged();
+      }
+    }
+
     return this.linkChanges.hashCode() != this.linksTag
             || this.propertyChanges.hashCode() != this.propertiesTag
-            || (includeMedia && (this.stream != null
+            || (deep && (linkedChanges
+            || this.stream != null
             || !this.streamedPropertyChanges.isEmpty()));
   }
 
@@ -355,6 +366,7 @@ public class EntityInvocationHandler extends AbstractStructuredInvocationHandler
 
     if (navPropValue != null) {
       cacheLink(property, navPropValue);
+      attach();
     }
 
     return navPropValue;

http://git-wip-us.apache.org/repos/asf/olingo-odata4/blob/a5e983c9/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
----------------------------------------------------------------------
diff --git a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
index 15076d0..6db0317 100644
--- a/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
+++ b/fit/src/test/java/org/apache/olingo/fit/proxy/v4/APIBasicDesignTestITCase.java
@@ -115,6 +115,13 @@ public class APIBasicDesignTestITCase extends AbstractTestITCase {
     container.getCustomers().getByKey(1).setOrders(orders);
     container.flush();
   }
+  
+  @Test
+  public void addViaReference2() {
+    final Order order = container.getOrders().getByKey(8).load();
+    container.getCustomers().getByKey(1).getOrders().addRef(order);
+    container.flush();
+  }
 
   @Test
   public void readAndCheckForPrimitive() {