You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2013/10/09 00:10:13 UTC

[1/2] git commit: ISIS-558: refresh collection after invoking bulk action

Updated Branches:
  refs/heads/master 595c8d51f -> 96f4156ab


ISIS-558: refresh collection after invoking bulk action


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

Branch: refs/heads/master
Commit: e6297bde51a4a0f198104d8940261d7a4a835011
Parents: 595c8d5
Author: Dan Haywood <da...@apache.org>
Authored: Tue Oct 8 20:09:44 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Oct 8 20:09:44 2013 +0100

----------------------------------------------------------------------
 .../model/models/EntityCollectionModel.java     | 48 ++++++++++++++++++--
 .../ui/components/actions/ActionPanel.java      |  1 +
 .../ajaxtable/BulkActionsLinkFactory.java       | 30 +++++-------
 .../widgets/cssmenu/CssMenuBuilder.java         | 25 ----------
 4 files changed, 57 insertions(+), 47 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/e6297bde/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index 99da83a..0f21696 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -24,6 +24,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
+import com.google.common.base.Ascii;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 
@@ -36,6 +37,7 @@ import org.apache.isis.core.metamodel.facets.collections.sortedby.SortedByFacet;
 import org.apache.isis.core.metamodel.facets.object.paged.PagedFacet;
 import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
@@ -140,10 +142,7 @@ public class EntityCollectionModel extends ModelAbstract<List<ObjectAdapter>> im
      * Factory.
      */
     public static EntityCollectionModel createStandalone(final ObjectAdapter collectionAsAdapter) {
-        final Iterable<Object> iterable = EntityCollectionModel.asIterable(collectionAsAdapter);
-
-        final Iterable<ObjectAdapterMemento> oidIterable = Iterables.transform(iterable, MementoFunctions.fromPojo(getAdapterManagerStatic()));
-        final List<ObjectAdapterMemento> mementoList = Lists.newArrayList(oidIterable);
+        final List<ObjectAdapterMemento> mementoList = asMementoList(collectionAsAdapter);
 
         final ObjectSpecification elementSpec = collectionAsAdapter.getElementSpecification();
         final Class<?> elementType = elementSpec.getCorrespondingClass();
@@ -152,6 +151,33 @@ public class EntityCollectionModel extends ModelAbstract<List<ObjectAdapter>> im
         return new EntityCollectionModel(elementType, mementoList, pageSize);
     }
 
+    private static List<ObjectAdapterMemento> asMementoList(final ObjectAdapter collectionAsAdapter) {
+        final Iterable<Object> iterable = EntityCollectionModel.asIterable(collectionAsAdapter);
+        return Lists.newArrayList(
+                Iterables.transform(iterable, MementoFunctions.fromPojo(getAdapterManagerStatic())));
+    }
+
+    /**
+     * The {@link ActionModel model} of the {@link ObjectAction action} 
+     * that generated this {@link EntityCollectionModel}.
+     * 
+     * <p>
+     * Populated only for {@link Type#STANDALONE standalone} collections.
+     * 
+     * @see #setActionHint(ActionModel)
+     */
+    public ActionModel getActionModelHint() {
+        return actionModelHint;
+    }
+    /**
+     * Called only for {@link Type#STANDALONE standalone} collections.
+     * 
+     * @see #getActionModelHint()
+     */
+    public void setActionHint(ActionModel actionModelHint) {
+        this.actionModelHint = actionModelHint;
+    }
+
     /**
      * Factory.
      */
@@ -203,6 +229,11 @@ public class EntityCollectionModel extends ModelAbstract<List<ObjectAdapter>> im
      */
     private Class<? extends Comparator<?>> sortedBy;
 
+    /**
+     * Optionally populated, only if {@link Type#STANDALONE} (ie called from an action).
+     */
+    private ActionModel actionModelHint;
+
     private EntityCollectionModel(final Class<?> typeOf, final List<ObjectAdapterMemento> mementoList, final int pageSize) {
         this.type = Type.STANDALONE;
         this.typeOf = typeOf;
@@ -282,6 +313,13 @@ public class EntityCollectionModel extends ModelAbstract<List<ObjectAdapter>> im
     }
     
     /**
+     * Not API, but to refresh the model list.
+     */
+    public void setObjectList(ObjectAdapter resultAdapter) {
+        this.mementoList = asMementoList(resultAdapter);
+    }
+
+    /**
      * Populated only if {@link Type#PARENTED}.
      */
     public ObjectAdapterMemento getParentObjectAdapterMemento() {
@@ -338,4 +376,6 @@ public class EntityCollectionModel extends ModelAbstract<List<ObjectAdapter>> im
         return IsisContext.getPersistenceSession().getAdapterManager();
     }
 
+
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e6297bde/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
index a698a74..50c0ccc 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionPanel.java
@@ -358,6 +358,7 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
 
             private void addOrReplaceCollectionResultsPanel(final ActionPanel panel, final ObjectAdapter resultAdapter) {
                 final EntityCollectionModel collectionModel = EntityCollectionModel.createStandalone(resultAdapter);
+                collectionModel.setActionHint(panel.getActionModel());
                 final ComponentFactoryRegistry componentFactoryRegistry = panel.getComponentFactoryRegistry();
                 componentFactoryRegistry.addOrReplaceComponent(panel, ComponentType.COLLECTION_CONTENTS, collectionModel);
 

http://git-wip-us.apache.org/repos/asf/isis/blob/e6297bde/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
index 957e415..8b13760 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
@@ -34,6 +34,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.mementos.ActionMemento;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuLinkFactory;
@@ -67,27 +68,20 @@ final class BulkActionsLinkFactory implements CssMenuLinkFactory {
                     final ObjectAdapter entityAdapter = entityAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
 
                     int numParameters = objectAction.getParameterCount();
-                    if(false /*objectAction.isContributed() */) {
-                        // a contributed action
-                        if(numParameters != 1) {
-                            return;
-                        }
-                        if(serviceAdapterMemento == null) {
-                            // not expected
-                            return;
-                        }
-                        final ObjectAdapter serviceAdapter = serviceAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
-                        objectAction.execute(serviceAdapter, new ObjectAdapter[]{entityAdapter});
-                    } else {
-                        // an entity action
-                        if(numParameters != 0) {
-                            return;
-                        }
-                        objectAction.execute(entityAdapter, new ObjectAdapter[]{});
+                    if(numParameters != 0) {
+                        return;
                     }
+                    objectAction.execute(entityAdapter, new ObjectAdapter[]{});
                 }
+                
                 model.clearToggleMementosList();
-                model.setObject(persistentAdaptersWithin(model.getObject()));
+                final ActionModel actionModelHint = model.getActionModelHint();
+                if(actionModelHint != null) {
+                    ObjectAdapter resultAdapter = actionModelHint.getObject();
+                    model.setObjectList(resultAdapter);
+                } else {
+                    model.setObject(persistentAdaptersWithin(model.getObject()));
+                }
             }
 
             private List<ObjectAdapter> persistentAdaptersWithin(List<ObjectAdapter> adapters) {

http://git-wip-us.apache.org/repos/asf/isis/blob/e6297bde/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuBuilder.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuBuilder.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuBuilder.java
index 7d8f6ba..fffb2cc 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuBuilder.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/CssMenuBuilder.java
@@ -142,31 +142,6 @@ public class CssMenuBuilder {
         }
     }
 
-//    /**
-//     * It's a bit hokey to have to do this, but the
-//     * {@link ObjectSpecification#getServiceActionsReturning(ActionType...)
-//     * method we call} on {@link ObjectSpecification}, while nicely traversing
-//     * the services for us, unfortunately does not pass us back the service
-//     * adapters also.
-//     */
-//    private ObjectAdapterMemento determineAdapterFor(final ObjectAction action) {
-//        
-//        if(getServiceAdapters() != null) {
-//            // null check required because could be null.
-//            
-//            // search through service adapters first
-//            final ObjectSpecification onType = action.getOnType();
-//            for (final ObjectAdapter serviceAdapter : getServiceAdapters()) {
-//                if (serviceAdapter.getSpecification() == onType) {
-//                    return ObjectAdapterMemento.createOrNull(serviceAdapter);
-//                }
-//            }
-//        }
-//
-//        // otherwise, specified adapter (could be null)
-//        return adapterMemento;
-//    }
-
     protected List<ObjectAdapter> getServiceAdapters() {
         return serviceAdapters;
     }


[2/2] git commit: ISIS-559: Bulk.InteractionContext.current.get()

Posted by da...@apache.org.
ISIS-559: Bulk.InteractionContext.current.get()

- provide information about the context in which a @Bulk action is invoked.


Project: http://git-wip-us.apache.org/repos/asf/isis/repo
Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/96f4156a
Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/96f4156a
Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/96f4156a

Branch: refs/heads/master
Commit: 96f4156ab7444ef4b220434b589fca7c3d5be8b5
Parents: e6297bd
Author: Dan Haywood <da...@apache.org>
Authored: Tue Oct 8 23:09:58 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Tue Oct 8 23:09:58 2013 +0100

----------------------------------------------------------------------
 .../ajaxtable/BulkActionsLinkFactory.java       | 37 +++++++---
 .../org/apache/isis/applib/annotation/Bulk.java | 75 ++++++++++++++++++++
 .../invoke/ActionInvocationFacetViaMethod.java  | 20 +++++-
 .../dom/src/main/java/dom/todo/ToDoItem.java    | 15 +++-
 .../test/java/dom/todo/ToDoTest_completed.java  |  9 ++-
 .../integration/glue/todoitem/ToDoItemGlue.java | 18 +++--
 6 files changed, 159 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
index 8b13760..e750c5c 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/BulkActionsLinkFactory.java
@@ -19,15 +19,21 @@
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 
 import org.apache.wicket.extensions.markup.html.repeater.data.table.DataTable;
 import org.apache.wicket.markup.html.link.AbstractLink;
 import org.apache.wicket.markup.html.link.Link;
 
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChecking;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -36,6 +42,8 @@ import org.apache.isis.viewer.wicket.model.mementos.ActionMemento;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.util.MementoFunctions;
+import org.apache.isis.viewer.wicket.model.util.ObjectAdapterFunctions;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuLinkFactory;
 import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
@@ -62,16 +70,29 @@ final class BulkActionsLinkFactory implements CssMenuLinkFactory {
             @Override
             public void onClick() {
                 final ObjectAction objectAction = actionMemento.getAction();
-                
-                for(ObjectAdapterMemento entityAdapterMemento: model.getToggleMementosList()) {
-                    // REVIEW: have disabled concurrency checking here...
-                    final ObjectAdapter entityAdapter = entityAdapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
 
-                    int numParameters = objectAction.getParameterCount();
-                    if(numParameters != 0) {
-                        return;
+                try {
+                    final List<ObjectAdapterMemento> toggleMementosList = model.getToggleMementosList();
+                    
+                    // REVIEW: have disabled concurrency checking here...
+                    final Iterable<ObjectAdapter> toggledAdapters = Iterables.transform(toggleMementosList, ObjectAdapterFunctions.fromMemento());
+                    
+                    final List<Object> domainObjects = Lists.newArrayList(Iterables.transform(toggledAdapters, ObjectAdapter.Functions.getObject()));
+                    final Bulk.InteractionContext interactionContext = new Bulk.InteractionContext(domainObjects);
+                    Bulk.InteractionContext.current.set(interactionContext);
+                    
+                    int i=0;
+                    for(final ObjectAdapter adapter : toggledAdapters) {
+    
+                        int numParameters = objectAction.getParameterCount();
+                        if(numParameters != 0) {
+                            return;
+                        }
+                        interactionContext.setIndex(i++);
+                        objectAction.execute(adapter, new ObjectAdapter[]{});
                     }
-                    objectAction.execute(entityAdapter, new ObjectAdapter[]{});
+                } finally {
+                    Bulk.InteractionContext.current.set(null);
                 }
                 
                 model.clearToggleMementosList();

http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
index c2e1ffb..8a35466 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
@@ -24,6 +24,8 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * Indicates the (entity) action should be used only against many objects
@@ -46,4 +48,77 @@ import java.lang.annotation.Target;
 @Target({ ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Bulk {
+    
+    public static class InteractionContext {
+
+        /**
+         * Intended only to be set only by the framework.
+         * 
+         * <p>
+         * Will be populated while a bulk action is being invoked.
+         * 
+         * <p>
+         * <b>Note</b>: the original design was for this field to be defined within {@link Bulk}.  However,
+         * this <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6982543">javac bug</a> unfortunately
+         * means that this field must live outside the annotation.
+         */
+        public static final ThreadLocal<InteractionContext> current = new ThreadLocal<InteractionContext>();
+
+        private final List<Object> domainObjects;
+        private final int size;
+        
+        private int index;
+
+        public InteractionContext(Object... domainObjects) {
+            this(Arrays.asList(domainObjects));
+        }
+
+        public InteractionContext(List<Object> domainObjects) {
+            this.domainObjects = domainObjects;
+            this.size = domainObjects.size();
+        }
+
+        public List<Object> getDomainObjects() {
+            return domainObjects;
+        }
+        
+        /**
+         * Will be a value in range [0, {@link #getSize() size}).
+         */
+        public int getIndex() {
+            return index;
+        }
+        
+        /**
+         * <b>NOT API</b>: intended to be called only by the framework.
+         */
+        public void setIndex(int index) {
+            this.index = index;
+        }
+        
+        public int getSize() {
+            return size;
+        }
+
+        public boolean isFirst() {
+            return this.index == 0;
+        }
+        
+        public boolean isLast() {
+            return this.index == (size-1);
+        }
+
+        /**
+         * @param runnable
+         */
+        public static void with(Runnable runnable, Object... domainObjects) {
+            try {
+                Bulk.InteractionContext.current.set(new Bulk.InteractionContext(domainObjects));
+                runnable.run();
+            } finally {
+                Bulk.InteractionContext.current.set(null);
+            }
+        }
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
index ceb8c6c..7a9ab55 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/invoke/ActionInvocationFacetViaMethod.java
@@ -27,6 +27,8 @@ import java.util.List;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext;
 import org.apache.isis.core.commons.lang.ThrowableExtensions;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
@@ -39,6 +41,7 @@ import org.apache.isis.core.metamodel.facets.typeof.ElementSpecificationProvider
 import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacet;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.ReflectiveActionException;
+import org.apache.isis.core.progmodel.facets.actions.bulk.BulkFacet;
 
 public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstract implements ImperativeFacet {
 
@@ -92,7 +95,22 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
             }
 
             final Object object = unwrap(inObject);
-            final Object result = method.invoke(object, executionParameters);
+            
+            final Object result;
+            
+            final BulkFacet bulkFacet = getFacetHolder().getFacet(BulkFacet.class);
+            if(bulkFacet != null && Bulk.InteractionContext.current.get() == null) {
+                // make sure that the Bulk interaction context is set if not already
+                try {
+                    Bulk.InteractionContext.current.set(new InteractionContext(object));
+                    result = method.invoke(object, executionParameters);
+                } finally {
+                    Bulk.InteractionContext.current.set(null);
+                }
+            } else {
+                result = method.invoke(object, executionParameters);
+            }
+            
             if (LOG.isDebugEnabled()) {
                 LOG.debug(" action result " + result);
             }

http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
index a73b604..d253850 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
@@ -43,10 +43,10 @@ import org.apache.isis.applib.annotation.Audited;
 import org.apache.isis.applib.annotation.AutoComplete;
 import org.apache.isis.applib.annotation.Bookmarkable;
 import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext;
 import org.apache.isis.applib.annotation.CssClass;
 import org.apache.isis.applib.annotation.Disabled;
 import org.apache.isis.applib.annotation.Hidden;
-import org.apache.isis.applib.annotation.MaxLength;
 import org.apache.isis.applib.annotation.MinLength;
 import org.apache.isis.applib.annotation.MultiLine;
 import org.apache.isis.applib.annotation.Named;
@@ -311,6 +311,18 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     @CssClass("x-highlight")
     public ToDoItem completed() {
         setComplete(true);
+        
+        // demonstrating the use of ... 
+        final InteractionContext ctxt = InteractionContext.current.get();
+        @SuppressWarnings("unused")
+        List<Object> allObjects = ctxt.getDomainObjects();
+        
+        LOG.debug("completed: "
+                + ctxt.getIndex() +
+                " [" + ctxt.getSize() + "]"
+                + (ctxt.isFirst() ? " (first)" : "")
+                + (ctxt.isLast() ? " (last)" : ""));
+
         return this;
     }
     // disable action dependent on state of object
@@ -323,6 +335,7 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     @Bulk
     public ToDoItem notYetCompleted() {
         setComplete(false);
+
         return this;
     }
     // disable action dependent on state of object

http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/example/application/quickstart_wicket_restful_jdo/dom/src/test/java/dom/todo/ToDoTest_completed.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/test/java/dom/todo/ToDoTest_completed.java b/example/application/quickstart_wicket_restful_jdo/dom/src/test/java/dom/todo/ToDoTest_completed.java
index 07f53cb..b0884ea 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/test/java/dom/todo/ToDoTest_completed.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/test/java/dom/todo/ToDoTest_completed.java
@@ -22,6 +22,8 @@ import static org.junit.Assert.assertThat;
 import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.isis.applib.annotation.Bulk;
+
 public class ToDoTest_completed {
 
     private ToDoItem toDoItem;
@@ -38,7 +40,12 @@ public class ToDoTest_completed {
         assertThat(toDoItem.disableCompleted(), is(nullValue()));
         
         // when
-        toDoItem.completed();
+        Bulk.InteractionContext.with(new Runnable() {
+            @Override
+            public void run() {
+                toDoItem.completed();
+            }
+        }, toDoItem);
         
         // then
         assertThat(toDoItem.isComplete(), is(true));

http://git-wip-us.apache.org/repos/asf/isis/blob/96f4156a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
index 000674c..a8b18ee 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/glue/todoitem/ToDoItemGlue.java
@@ -35,6 +35,7 @@ import dom.todo.ToDoItems;
 import org.jmock.Expectations;
 import org.junit.Assert;
 
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.core.specsupport.scenarios.InMemoryDB;
 import org.apache.isis.core.specsupport.specs.CukeGlueAbstract;
 
@@ -71,8 +72,19 @@ public class ToDoItemGlue extends CukeGlueAbstract {
     
     @When("^mark the item as complete$")
     public void mark_it_as_complete() throws Throwable {
-        ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
-        wrap(toDoItem).completed();
+        final ToDoItem toDoItem = getVar(null, "toDoItem", ToDoItem.class);
+        if(supportsMocks()) {
+            Bulk.InteractionContext.with(new Runnable(){
+                @Override
+                public void run() {
+                    toDoItem.completed();
+                }
+            }, toDoItem);
+        } else {
+            // can just call directly; 
+            // framework will take care of setting the Bulk.InteractionContext.
+            wrap(toDoItem).completed();
+        }
     }
     
     @Then("^the item is no longer listed as incomplete$")
@@ -81,8 +93,6 @@ public class ToDoItemGlue extends CukeGlueAbstract {
         whetherNotYetCompletedContains(toDoItem, false);
     }
 
-    
-    
     @Given("^.*completed .*item$")
     public void a_completed_ToDo_item() throws Throwable {
         if(supportsMocks()) {