Author: julien(a)jboss.com
Date: 2007-12-28 16:57:29 -0500 (Fri, 28 Dec 2007)
New Revision: 9400
Modified:
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/AssociationContext.java
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/UIObjectContainer.java
branches/presentation/presentation/src/main/org/jboss/portal/presentation/test/model/ModelTestCase.java
Log:
- test a bit more the refresh operation and improve its implementation
Modified:
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/AssociationContext.java
===================================================================
---
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/AssociationContext.java 2007-12-28
00:39:56 UTC (rev 9399)
+++
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/AssociationContext.java 2007-12-28
21:57:29 UTC (rev 9400)
@@ -32,6 +32,7 @@
import java.util.HashSet;
import java.util.Collection;
import java.util.AbstractSet;
+import java.util.ArrayList;
/**
* @author <a href="mailto:julien@jboss.org">Julien Viet</a>
@@ -86,16 +87,21 @@
/** . */
private UIContainerObject related;
- /** . */
- private UIContainerObject ref;
+ /** The context pointing at us via a OneToMany. */
+ private Set<ObjectContext> refs;
private ManyToOne()
{
this.loaded = false;
this.related = null;
- this.ref = null;
+ this.refs = new HashSet<ObjectContext>();
}
+ Set<ObjectContext> getReferences()
+ {
+ return refs;
+ }
+
boolean isLoaded()
{
return loaded;
@@ -296,7 +302,7 @@
/** . */
private Set<UIContainerObject> relateds;
- /** . */
+ /** The contexts pointing at us via a ManyToOne. */
private Set<ObjectContext> refs;
private OneToMany()
@@ -322,6 +328,8 @@
{
throw new IllegalArgumentException("No null child accepted");
}
+
+ //
for (UIContainerObject r : relateds)
{
if (related.getId().equals(r.getId()))
@@ -329,7 +337,9 @@
throw new IllegalStateException("Cannot add duplicate");
}
}
- relateds.add(related);
+
+ //
+ attach(related);
}
void setLoadedRelateds(Set<UIContainerObject> relateds)
@@ -338,10 +348,21 @@
{
throw new IllegalStateException("Not loaded");
}
- this.relateds = relateds;
+
+ //
+ for (UIContainerObject related : new
ArrayList<UIContainerObject>(this.relateds))
+ {
+ detach(related);
+ }
+
+ //
+ for (UIContainerObject related : relateds)
+ {
+ attach(related);
+ }
}
- void removeLoadedRelated(String relatedId)
+ UIContainerObject removeLoadedRelated(String relatedId)
{
if (!isLoaded())
{
@@ -351,17 +372,19 @@
{
throw new IllegalArgumentException();
}
- for (Iterator<UIContainerObject> i = relateds.iterator();i.hasNext();)
+
+ //
+ for (UIContainerObject related : relateds)
{
- UIContainerObject child = i.next();
-
- //
- if (relatedId.equals(child.getId()))
+ if (relatedId.equals(related.getId()))
{
- i.remove();
- break;
+ detach(related);
+ return related;
}
}
+
+ //
+ throw new AssertionError("BUG");
}
Collection<UIContainerObject> getRelateds()
@@ -369,6 +392,11 @@
return list;
}
+ Set<ObjectContext> getReferences()
+ {
+ return refs;
+ }
+
/**
* Load the related side.
*
@@ -381,6 +409,42 @@
protected abstract ManyToOne getManyToOne(UIContainerObject related);
+ private void detach(UIContainerObject related)
+ {
+ ManyToOne manyToOne = getManyToOne(related);
+
+ //
+ ObjectContext owner = getOwner();
+
+ //
+ if (!manyToOne.refs.contains(owner))
+ {
+ throw new AssertionError("BUG");
+ }
+
+ //
+ manyToOne.refs.remove(owner);
+ relateds.remove(related);
+ }
+
+ private void attach(UIContainerObject related)
+ {
+ ManyToOne manyToOne = getManyToOne(related);
+
+ //
+ ObjectContext owner = getOwner();
+
+ //
+ if (manyToOne.refs.contains(owner))
+ {
+ throw new AssertionError("Context already referenced by the provided
object");
+ }
+
+ //
+ manyToOne.refs.add(owner);
+ relateds.add(related);
+ }
+
private void load()
{
ObjectContext owner = getOwner();
@@ -388,9 +452,6 @@
//
try
{
- Set<UIContainerObject> relateds = new
HashSet<UIContainerObject>();
-
- //
for (StructuralObject relatedSO : doLoad())
{
UIContainerObject related = owner.container.get(relatedSO);
@@ -415,11 +476,10 @@
}
//
- relateds.add(related);
+ attach(related);
}
//
- this.relateds = relateds;
this.loaded = true;
}
catch (StateException e)
Modified:
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/UIObjectContainer.java
===================================================================
---
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/UIObjectContainer.java 2007-12-28
00:39:56 UTC (rev 9399)
+++
branches/presentation/presentation/src/main/org/jboss/portal/presentation/impl/model/container/UIObjectContainer.java 2007-12-28
21:57:29 UTC (rev 9400)
@@ -402,117 +402,99 @@
ObjectContext context = (ObjectContext)object.getContext();
//
- switch (context.status)
+ if (context.status == UIObject.Status.INVALID)
{
- case VALID:
- case STALE:
- try
+ return;
+ }
+
+ //
+ StructuralObject.Refresh refresh = null;
+ try
+ {
+ refresh = structuralStateContext.refresh(context.structuralObject);
+ }
+ catch (NoSuchStateException e)
+ {
+ context.status = UIObject.Status.INVALID;
+ return;
+ }
+
+ //
+ boolean loaded = context.associationContext.children.isLoaded();
+ boolean refreshChildren = scope.enterChildren(object, loaded);
+
+ // Update the structural state
+ if (!context.structuralObject.compareTo(refresh.getObject()))
+ {
+ if (loaded)
+ {
+ // Take care of the added children
+ for (StructuralObject addedSO : refresh.getAddedChildren())
{
- StructuralObject.Refresh refresh =
structuralStateContext.refresh(context.structuralObject);
+ UIContainerObject added = get(addedSO);
- // Update the structural state
- if (!context.structuralObject.compareTo(refresh.getObject()))
+ //
+ if (added != null)
{
- boolean loaded = context.associationContext.children.isLoaded();
+ ObjectContext addedContext = (ObjectContext)added.getContext();
- //
- if (loaded)
+ // Find parent pointing at us and set as dirty
+ for (ObjectContext addedParentContext :
addedContext.associationContext.parent.getReferences())
{
- boolean refreshChildren = scope.enterChildren(object, loaded);
+ addedParentContext.status = UIObject.Status.STALE;
+ }
- // The new list of children
- Set<UIContainerObject> children = new
HashSet<UIContainerObject>();
+ // Update parent if it was loaded
+ if (addedContext.associationContext.parent.isLoaded())
+ {
+ addedContext.associationContext.parent.setLoadedRelated(object);
+ }
+ }
+ else
+ {
+ added = create(addedSO);
- // Take care of the added children
- for (StructuralObject addedSO : refresh.getAddedChildren())
- {
- UIContainerObject added = get(addedSO);
+ //
+ attach(added);
+ }
- //
- if (added != null)
- {
- ObjectContext addedContext =
(ObjectContext)added.getContext();
+ //
+ context.associationContext.children.addLoadedRelated(added);
+ }
- // Set the parent as stale if needed
- if (addedContext.associationContext.parent.isLoaded())
- {
- ObjectContext addedParentContext =
(ObjectContext)addedContext.associationContext.parent.getLoadedRelated().getContext();
+ //
+ for (StructuralObject staleSO : refresh.getStaleChildren().values())
+ {
+ UIContainerObject stale = get(staleSO);
- // Mark the parent as stale
- addedParentContext.status = UIObject.Status.STALE;
+ // It must be here as it is loaded
+ ObjectContext staleContext = (ObjectContext)stale.getContext();
- //
-
addedParentContext.associationContext.parent.setLoadedRelated(get(context.structuralObject));
- }
- }
- else
- {
- added = create(addedSO);
-
- //
- attach(added);
- }
-
- //
- children.add(added);
- }
-
- //
- for (String validId : refresh.getValidChildren())
- {
- UIContainerObject valid = get(validId);
-
- // It must be here...
- children.add(valid);
- }
-
-
- //
- for (StructuralObject staleSO :
refresh.getStaleChildren().values())
- {
- UIContainerObject stale = get(staleSO);
-
- //
- ObjectContext staleContext =
(ObjectContext)stale.getContext();
-
- // Mark as stale
- staleContext.status = UIObject.Status.STALE;
-
- //
- children.add(stale);
- }
-
- // Removals
- for (String removedId : refresh.getRemovedChildren())
- {
- UIContainerObject removed = get(removedId);
-
- //
- if (removed != null)
- {
- // We should try to now if it is somehow referenced by
someone that is not us
- // i.e it has been already be moved somewhere else
- throw new NotYetImplemented();
- }
- }
-
- // Update state
- context.structuralObject = refresh.getObject();
- context.status = UIObject.Status.VALID;
- context.associationContext.children.setLoadedRelateds(children);
- }
- }
+ // Mark as stale
+ staleContext.status = UIObject.Status.STALE;
}
- catch (NoSuchStateException e)
+
+ // Removals
+ for (String removedId : refresh.getRemovedChildren())
{
- context.status = UIObject.Status.INVALID;
+ UIContainerObject removed =
context.associationContext.children.removeLoadedRelated(removedId);
}
- //
- break;
- case INVALID:
+ // Update state
+ context.structuralObject = refresh.getObject();
+ context.status = UIObject.Status.VALID;
+ }
}
+ // Recursively refresh children
+ if (refreshChildren)
+ {
+ for (UIContainerObject child :
context.associationContext.children.getRelateds())
+ {
+ refresh(child, scope);
+ }
+ }
+
//
//
Modified:
branches/presentation/presentation/src/main/org/jboss/portal/presentation/test/model/ModelTestCase.java
===================================================================
---
branches/presentation/presentation/src/main/org/jboss/portal/presentation/test/model/ModelTestCase.java 2007-12-28
00:39:56 UTC (rev 9399)
+++
branches/presentation/presentation/src/main/org/jboss/portal/presentation/test/model/ModelTestCase.java 2007-12-28
21:57:29 UTC (rev 9400)
@@ -781,7 +781,7 @@
// Load fully the context 1
UIContext context1 = createContext();
- loadDescendants(context1);
+ loadSubTree(context1);
// Concurrent move
UIContext context2 = createContext();
@@ -791,11 +791,86 @@
context1.getChild("bar").refresh();
}
- private void loadDescendants(UIObject object)
+ public void testRefreshAfterConcurrentMove2() throws Exception
{
+ MockObject mockRoot = model.getRoot();
+
+ MockObject mockFoo = mockRoot.addChild("foo", MockObject.Type.PORTAL);
+ MockObject mockBar = mockRoot.addChild("bar", MockObject.Type.PORTAL);
+
+ MockObject mockFooJuu = mockFoo.addChild("juu", MockObject.Type.PAGE);
+ MockObject mockFooDaa = mockFoo.addChild("daa", MockObject.Type.PAGE);
+
+ MockObject mockBarDaa = mockBar.addChild("daa", MockObject.Type.PAGE);
+
+ // Load fully the context 1
+ UIContext context1 = createContext();
+ loadSubTree(context1);
+
+ // Concurrent move
+ UIContext context2 = createContext();
+
context2.getChild("foo").getChild("juu").move(context2.getChild("bar"));
+
+ //
+ context1.getChild("foo").refresh();
+ }
+
+ public void testPartialRefreshAfterConcurrentMove() throws Exception
+ {
+ MockObject mockRoot = model.getRoot();
+
+ MockObject mockFoo = mockRoot.addChild("foo", MockObject.Type.PORTAL);
+ MockObject mockBar = mockRoot.addChild("bar", MockObject.Type.PORTAL);
+ MockObject mockJuu = mockFoo.addChild("juu", MockObject.Type.PAGE);
+
+ // Load fully the context 1
+ UIContext context1 = createContext();
+ loadSubTree(context1);
+ UIObject foo1 = context1.getChild("foo");
+ UIObject juu1 = foo1.getChild("juu");
+ UIObject bar1 = context1.getChild("bar");
+
+ // Load fully the context 2
+ UIContext context2 = createContext();
+ loadSubTree(context2);
+ UIObject foo2 = context2.getChild("foo");
+ UIObject juu2 = foo2.getChild("juu");
+ UIObject bar2 = context2.getChild("bar");
+
+ // Load fully the context 3
+ UIContext context3 = createContext();
+ loadSubTree(context3);
+ UIObject foo3 = context3.getChild("foo");
+ UIObject juu3 = foo3.getChild("juu");
+ UIObject bar3 = context3.getChild("bar");
+
+ // Concurrent move
+ UIContext context = createContext();
+
context.getChild("foo").getChild("juu").move(context.getChild("bar"));
+
+ //
+ foo1.refresh(CRAWLER);
+ assertEquals(UIObject.Status.VALID, foo1.getStatus());
+ assertEquals(0, foo1.getChildren().size());
+
+ //
+ bar2.refresh(CRAWLER);
+ assertEquals(UIObject.Status.STALE, foo2.getStatus());
+ assertEquals(UIObject.Status.VALID, bar2.getStatus());
+ assertEquals(Tools.toSet(juu2), new HashSet<UIObject>(bar2.getChildren()));
+
+ //
+ context3.refresh(CRAWLER);
+ assertEquals(UIObject.Status.VALID, foo3.getStatus());
+ assertEquals(UIObject.Status.VALID, bar3.getStatus());
+ assertEquals(Tools.toSet(juu3), new HashSet<UIObject>(bar3.getChildren()));
+ }
+
+ private void loadSubTree(UIObject object)
+ {
for (UIObject child : object.getChildren())
{
- loadDescendants(child);
+ loadSubTree(child);
}
}
@@ -831,4 +906,22 @@
assertEquals(Collections.singleton(fooDaa), new
HashSet<UIObject>(fooChildren));
assertEquals(Tools.toSet(barDaa, fooJuu), new
HashSet<UIObject>(barChildren));
}
+
+ private static final UIObject.Visitor CRAWLER = new UIObject.Visitor()
+ {
+ public boolean enterObject(UIObject object)
+ {
+ return true;
+ }
+
+ public void leaveObject(UIObject object)
+ {
+ }
+
+ public boolean enterChildren(UIObject object, boolean loaded)
+ {
+ return loaded;
+ }
+ };
+
}