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:14 UTC

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

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()) {