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 2014/01/17 14:08:16 UTC

[3/3] git commit: ISIS-648, ISIS-652, ISIS-653, ISIS-655: bulk actions, request scoped services

ISIS-648, ISIS-652, ISIS-653, ISIS-655: bulk actions, request scoped services

ISIS-652: @RequestScoped services
- CDI 1.0 now a dependency of applib (for the @RequestScoped annotation)
- javassist is now a dependency of runtime
- ServiceInitializer, create javassist proxy for request-scoped services/beans
  (delegates to threadlocal held within the proxy)
- functionality in JavassistClassSubstitor now moved into core (ClassSubstitutorAbstract) so that
  ObjectSpecifications for @RequestScoped services are automatically setup correctly
  (the synthetic methods etc are disregarded)
- old JavassistClassSubstitor in core-bytecode-javassist now marked as deprecated
- PersistenceSession#open automatically initializes all request-scoped services (by downcasting to RequestScopedService and
  calling __isis_startRequest), and #close() similarly tidies up (by calling to __isis_endRequest)
- UserProfileLoaderDefault, when creating the UserProfile object, excludes any request-scoped services

ISIS-648, ISIS-655: enhanced bulk update support
- @Bulk#appliesTo property - whether to render action *only* as bulk
  - updates to EntityActionUtil to suppress in UI
- Bulk.InteractionContext#invokedAs added, to tell object whether the action called as a bulk or regular
- change in behaviour when invoking bulk actions, navigate to return value of action of last object called (if not null)
- ActionResultResponseType (etc) factored out for common handling of results from either
  regular actions or bulk actions

ISIS-655, refactored bulk interaction context
- Bulk.InteractionContext is now a request scoped service
  - deprecated the old threadlocal current
  - PersistenceSession#open copies over the service to the threadlocal
- deprecated Bulk.InteractionContext#with(...) methods
  - no longer required, so throw an explanatory exception (yes, this is a tiny breaking change...)

ISIS-653, Scratchpad @RequestScoped service
- Scratchpad service to get and set userdata, added to applib
  - allows apps to pass contextual information from one object's action to next
- TodoItem updated to demonstrate usage


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

Branch: refs/heads/master
Commit: e7f97df59ccbb0c996dcd53e5626f67a53a0b0a5
Parents: a008bfa
Author: Dan Haywood <da...@apache.org>
Authored: Fri Jan 17 13:07:43 2014 +0000
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Jan 17 13:07:43 2014 +0000

----------------------------------------------------------------------
 ...ataNucleusPersistenceMechanismInstaller.java |   2 +-
 .../ui/actionresponse/ActionResultResponse.java |  42 ++++
 .../ActionResultResponseHandlingStrategy.java   |  38 ++++
 .../ActionResultResponseType.java               | 168 +++++++++++++++
 .../ui/components/actions/ActionPanel.java      | 208 ++-----------------
 .../additionallinks/EntityActionUtil.java       |  12 +-
 .../ajaxtable/BulkActionsLinkFactory.java       |  47 +++--
 .../CollectionContentsAsAjaxTablePanel.java     |   1 +
 .../entity/header/EntityHeaderPanel.java        |  13 +-
 .../cssmenu/ActionLinkFactoryAbstract.java      |   3 +-
 core/applib/pom.xml                             |   5 +-
 .../org/apache/isis/applib/annotation/Bulk.java | 167 ++++++++++++---
 .../applib/services/scratchpad/Scratchpad.java  |  67 ++++++
 core/bytecode-javassist/pom.xml                 |   2 +-
 .../javassist/JavassistClassSubstitutor.java    |  23 +-
 .../bytecode/javassist/JavassistEnhanced.java   |   5 +-
 .../metamodel/spec/feature/ObjectAction.java    |  23 +-
 .../ClassSubstitutorAbstract.java               |   4 +
 .../classsubstitutor/JavassistEnhanced.java     |  28 +++
 .../facets/actions/bulk/BulkFacet.java          |   6 +-
 .../facets/actions/bulk/BulkFacetAbstract.java  |   9 +-
 .../annotation/BulkAnnotationFacetFactory.java  |   2 +-
 .../bulk/annotation/BulkFacetAnnotation.java    |   5 +-
 .../invoke/ActionInvocationFacetViaMethod.java  |  17 +-
 core/pom.xml                                    |  10 +-
 core/runtime/pom.xml                            |   5 +
 .../bytecode/dflt/ClassSubstitutorDefault.java  |  29 +++
 .../bytecode/dflt/ObjectFactoryBasic.java       |  54 +++++
 .../identity/ClassSubstitutorIdentity.java      |  31 ---
 .../bytecode/identity/ObjectFactoryBasic.java   |  54 -----
 .../PersistenceSessionFactoryDelegating.java    |  13 --
 .../runtime/services/RequestScopedService.java  |  43 ++++
 .../runtime/services/ServiceInstantiator.java   | 147 +++++++++++++
 .../ServicesInstallerFromConfiguration.java     |  37 ++--
 .../system/persistence/PersistenceSession.java  |  37 +++-
 .../persistence/PersistenceSessionFactory.java  |   4 -
 .../userprofile/UserProfileLoaderDefault.java   |  16 +-
 .../services/ServiceInstantiatorTest.java       | 145 +++++++++++++
 .../dom/src/main/java/dom/todo/ToDoItem.java    |  59 ++++--
 .../src/main/java/dom/todo/ToDoItem.layout.json |   1 +
 .../dom/src/main/java/dom/todo/ToDoItems.java   |   3 +
 .../test/java/dom/todo/ToDoTest_completed.java  |  13 +-
 .../java/integration/ToDoSystemInitializer.java |   5 +-
 .../integration/glue/todoitem/ToDoItemGlue.java |  18 +-
 .../src/main/webapp/WEB-INF/isis.properties     |   2 +
 45 files changed, 1168 insertions(+), 455 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusPersistenceMechanismInstaller.java
----------------------------------------------------------------------
diff --git a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusPersistenceMechanismInstaller.java b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusPersistenceMechanismInstaller.java
index aa19d74..92e8f22 100644
--- a/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusPersistenceMechanismInstaller.java
+++ b/component/objectstore/jdo/jdo-datanucleus/src/main/java/org/apache/isis/objectstore/jdo/datanucleus/DataNucleusPersistenceMechanismInstaller.java
@@ -39,7 +39,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutor;
 import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
-import org.apache.isis.core.runtime.bytecode.identity.ObjectFactoryBasic;
+import org.apache.isis.core.runtime.bytecode.dflt.ObjectFactoryBasic;
 import org.apache.isis.core.runtime.installerregistry.installerapi.PersistenceMechanismInstallerAbstract;
 import org.apache.isis.core.runtime.persistence.objectstore.ObjectStoreSpi;
 import org.apache.isis.core.runtime.persistence.objectstore.algorithm.PersistAlgorithm;

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
new file mode 100644
index 0000000..4f967d0
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponse.java
@@ -0,0 +1,42 @@
+package org.apache.isis.viewer.wicket.ui.actionresponse;
+
+import org.apache.wicket.request.IRequestHandler;
+
+import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
+
+/**
+ * The response to provide as a result of interpreting the response;
+ * either to show a {@link #toPage(PageAbstract) page}, or to {@link #withHandler(IRequestHandler) redirect} to a 
+ * handler (eg a download).
+ */
+public class ActionResultResponse {
+    private final ActionResultResponseType resultType;
+    private final IRequestHandler handler;
+    private final PageAbstract page;
+    public static ActionResultResponse withHandler(ActionResultResponseType resultType, IRequestHandler handler) {
+        return new ActionResultResponse(resultType, handler, null);
+    }
+    public static ActionResultResponse toPage(ActionResultResponseType resultType, PageAbstract page) {
+        return new ActionResultResponse(resultType, null, page);
+    }
+    private ActionResultResponse(ActionResultResponseType resultType, IRequestHandler handler, PageAbstract page) {
+        this.resultType = resultType;
+        this.handler = handler;
+        this.page = page;
+    }
+    public boolean isRedirect() {
+        return handler != null;
+    }
+    public boolean isToPage() {
+        return page != null;
+    }
+    public IRequestHandler getHandler() {
+        return handler;
+    }
+    public PageAbstract getToPage() {
+        return page;
+    }
+    public ActionResultResponseType getResultType() {
+        return resultType;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
new file mode 100644
index 0000000..bad371a
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseHandlingStrategy.java
@@ -0,0 +1,38 @@
+package org.apache.isis.viewer.wicket.ui.actionresponse;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.request.cycle.RequestCycle;
+
+import org.apache.isis.core.runtime.system.context.IsisContext;
+
+public enum ActionResultResponseHandlingStrategy {
+    REDIRECT_TO_PAGE {
+        @Override
+        public void handleResults(final Component component, final ActionResultResponse resultResponse) {
+            // force any changes in state etc to happen now prior to the redirect;
+            // in the case of an object being returned, this should cause our page mementos 
+            // (eg EntityModel) to hold the correct state.  I hope.
+            IsisContext.getTransactionManager().flushTransaction();
+            
+            // "redirect-after-post"
+            component.setResponsePage(resultResponse.getToPage());
+        }
+    },
+    SCHEDULE_HANDLER {
+        @Override
+        public void handleResults(final Component component, final ActionResultResponse resultResponse) {
+            RequestCycle requestCycle = component.getRequestCycle();
+            requestCycle.scheduleRequestHandlerAfterCurrent(resultResponse.getHandler());
+        }
+    };
+
+    public abstract void handleResults(Component component, ActionResultResponse resultResponse);
+
+    public static ActionResultResponseHandlingStrategy determineFor(final ActionResultResponse resultResponse) {
+        if(resultResponse.isToPage()) {
+            return REDIRECT_TO_PAGE;
+        } else {
+            return SCHEDULE_HANDLER;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
new file mode 100644
index 0000000..1b1d7fa
--- /dev/null
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
@@ -0,0 +1,168 @@
+package org.apache.isis.viewer.wicket.ui.actionresponse;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.google.common.collect.Lists;
+
+import org.apache.wicket.request.IRequestHandler;
+
+import org.apache.isis.applib.value.Blob;
+import org.apache.isis.applib.value.Clob;
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.runtime.system.context.IsisContext;
+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.models.ValueModel;
+import org.apache.isis.viewer.wicket.model.models.VoidModel;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
+import org.apache.isis.viewer.wicket.ui.pages.standalonecollection.StandaloneCollectionPage;
+import org.apache.isis.viewer.wicket.ui.pages.value.ValuePage;
+import org.apache.isis.viewer.wicket.ui.pages.voidreturn.VoidReturnPage;
+
+public enum ActionResultResponseType {
+    OBJECT {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            final ObjectAdapter actualAdapter = determineActualAdapter(resultAdapter);
+            return toEntityPage(model, actualAdapter, null);
+        }
+
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, ObjectAdapter targetAdapter, ConcurrencyException ex) {
+            return toEntityPage(model, targetAdapter, ex);
+        }
+
+        private ObjectAdapter determineActualAdapter(final ObjectAdapter resultAdapter) {
+            if (resultAdapter.getSpecification().isNotCollection()) {
+                return resultAdapter;
+            } else {
+                // will only be a single element
+                final List<Object> pojoList = asList(resultAdapter);
+                final Object pojo = pojoList.get(0);
+                return adapterFor(pojo);
+            }
+        }
+        private ObjectAdapter adapterFor(final Object pojo) {
+            return IsisContext.getPersistenceSession().getAdapterManager().adapterFor(pojo);
+        }
+
+        private ActionResultResponse toEntityPage(final ActionModel model, final ObjectAdapter actualAdapter, ConcurrencyException exIfAny) {
+            return ActionResultResponse.toPage(this, new EntityPage(actualAdapter, exIfAny));
+        }
+
+    },
+    COLLECTION {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel actionModel, final ObjectAdapter resultAdapter) {
+            final EntityCollectionModel collectionModel = EntityCollectionModel.createStandalone(resultAdapter);
+            collectionModel.setActionHint(actionModel);
+            return ActionResultResponse.toPage(this, new StandaloneCollectionPage(collectionModel));
+        }
+    },
+    VALUE {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            ValueModel valueModel = new ValueModel(resultAdapter);
+            final ValuePage valuePage = new ValuePage(valueModel);
+            return ActionResultResponse.toPage(this, valuePage);
+        }
+    },
+    VALUE_CLOB {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            final Object value = resultAdapter.getObject();
+            IRequestHandler handler = ActionModel.downloadHandler(value);
+            return ActionResultResponse.withHandler(this, handler);
+        }
+    },
+    VALUE_BLOB {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            final Object value = resultAdapter.getObject();
+            IRequestHandler handler = ActionModel.downloadHandler(value);
+            return ActionResultResponse.withHandler(this, handler);
+        }
+
+    },
+    VALUE_URL {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            final Object value = resultAdapter.getObject();
+            IRequestHandler handler = ActionModel.redirectHandler(value);
+            return ActionResultResponse.withHandler(this, handler);
+        }
+
+    },
+    VOID {
+        @Override
+        public ActionResultResponse interpretResult(final ActionModel model, final ObjectAdapter resultAdapter) {
+            final VoidModel voidModel = new VoidModel();
+            voidModel.setActionHint(model);
+            return ActionResultResponse.toPage(this, new VoidReturnPage(voidModel));
+        }
+    };
+
+    public abstract ActionResultResponse interpretResult(ActionModel model, ObjectAdapter resultAdapter);
+
+    /**
+     * Only overridden for {@link ActionResultResponseType#OBJECT object}
+     */
+    public ActionResultResponse interpretResult(ActionModel model, ObjectAdapter targetAdapter, ConcurrencyException ex) {
+        throw new UnsupportedOperationException("Cannot render concurrency exception for any result type other than OBJECT");
+    }
+
+    // //////////////////////////////////////
+
+    public static ActionResultResponse determineAndInterpretResult(final ActionModel model, ObjectAdapter resultAdapter) {
+        ActionResultResponseType arrt = determineFor(resultAdapter);
+        return arrt.interpretResult(model, resultAdapter);
+    }
+
+    private static ActionResultResponseType determineFor(final ObjectAdapter resultAdapter) {
+        if(resultAdapter == null) {
+            return ActionResultResponseType.VOID;
+        }
+        final ObjectSpecification resultSpec = resultAdapter.getSpecification();
+        if (resultSpec.isNotCollection()) {
+            if (resultSpec.getFacet(ValueFacet.class) != null) {
+                
+                final Object value = resultAdapter.getObject();
+                if(value instanceof Clob) {
+                    return ActionResultResponseType.VALUE_CLOB;
+                } 
+                if(value instanceof Blob) {
+                    return ActionResultResponseType.VALUE_BLOB;
+                } 
+                if(value instanceof java.net.URL) {
+                    return ActionResultResponseType.VALUE_URL;
+                } 
+                // else
+                return ActionResultResponseType.VALUE;
+            } else {
+                return ActionResultResponseType.OBJECT;
+            }
+        } else {
+            final List<Object> pojoList = asList(resultAdapter);
+            switch (pojoList.size()) {
+            case 1:
+                return ActionResultResponseType.OBJECT;
+            default:
+                return ActionResultResponseType.COLLECTION;
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private static List<Object> asList(final ObjectAdapter resultAdapter) {
+        final Collection<Object> coll = (Collection<Object>) resultAdapter.getObject();
+        return coll instanceof List
+                ? (List<Object>)coll
+                : Lists.<Object>newArrayList(coll);
+    }
+
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/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 a38e5ca..de310f0 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
@@ -19,55 +19,32 @@
 
 package org.apache.isis.viewer.wicket.ui.components.actions;
 
-import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 
-import com.google.common.base.Throwables;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.model.Model;
-import org.apache.wicket.request.IRequestHandler;
-import org.apache.wicket.request.cycle.RequestCycle;
-import org.apache.wicket.request.handler.resource.ResourceRequestHandler;
-import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
-import org.apache.wicket.request.http.handler.RedirectRequestHandler;
-import org.apache.wicket.request.resource.ByteArrayResource;
-import org.apache.wicket.request.resource.ContentDisposition;
-import org.apache.wicket.util.resource.StringResourceStream;
 
 import org.apache.isis.applib.ApplicationException;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
-import org.apache.isis.applib.value.Blob;
-import org.apache.isis.applib.value.Clob;
 import org.apache.isis.core.commons.authentication.MessageBroker;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
-import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.runtimecontext.ServicesInjector;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
-import org.apache.isis.viewer.wicket.model.isis.PersistenceSessionProvider;
 import org.apache.isis.viewer.wicket.model.models.ActionExecutor;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.BookmarkableModel;
 import org.apache.isis.viewer.wicket.model.models.BookmarkedPagesModel;
-import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
-import org.apache.isis.viewer.wicket.model.models.ValueModel;
-import org.apache.isis.viewer.wicket.model.models.VoidModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseHandlingStrategy;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponse;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseType;
 import org.apache.isis.viewer.wicket.ui.pages.BookmarkedPagesModelProvider;
-import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
-import org.apache.isis.viewer.wicket.ui.pages.standalonecollection.StandaloneCollectionPage;
-import org.apache.isis.viewer.wicket.ui.pages.value.ValuePage;
-import org.apache.isis.viewer.wicket.ui.pages.voidreturn.VoidReturnPage;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
 /**
@@ -85,7 +62,7 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
 
     private static final long serialVersionUID = 1L;
 
-    private static final String ID_ACTION_NAME = "actionName";
+    static final String ID_ACTION_NAME = "actionName";
 
     public ActionPanel(final String id, final ActionModel actionModel) {
         super(id, actionModel);
@@ -101,7 +78,7 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
         }
     }
 
-    private ActionModel getActionModel() {
+    ActionModel getActionModel() {
         return super.getModel();
     }
 
@@ -127,7 +104,8 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
             }
             
             // forward onto the target page with the concurrency exception
-            ResultType.OBJECT.addResults(this, targetAdapter, ex);
+            ActionResultResponse resultResponse = ActionResultResponseType.OBJECT.interpretResult(this.getActionModel(), targetAdapter, ex);
+            ActionResultResponseHandlingStrategy.determineFor(resultResponse).handleResults(this, resultResponse);
 
             getMessageBroker().addWarning(ex.getMessage());
         }
@@ -167,9 +145,9 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
                 targetAdapter = getModel().getTargetAdapter();
             }
 
-            
             // forward onto the target page with the concurrency exception
-            ResultType.OBJECT.addResults(this, targetAdapter, ex);
+            ActionResultResponse resultResponse = ActionResultResponseType.OBJECT.interpretResult(this.getActionModel(), targetAdapter, ex);
+            ActionResultResponseHandlingStrategy.determineFor(resultResponse).handleResults(this, resultResponse);
 
             getMessageBroker().addWarning(ex.getMessage());
             return false;
@@ -204,8 +182,9 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
             // will be thrown here
             getTransactionManager().flushTransaction();
             
-            final ResultType resultType = ResultType.determineFor(resultAdapter);
-            resultType.addResults(this, resultAdapter);
+            ActionResultResponse resultResponse = ActionResultResponseType.determineAndInterpretResult(this.getActionModel(), resultAdapter);
+            final ActionResultResponseHandlingStrategy resultType = ActionResultResponseHandlingStrategy.determineFor(resultResponse);
+            resultType.handleResults(this, resultResponse);
 
             if (actionModel.isBookmarkable()) {
                 bookmarkPage(actionModel);
@@ -224,8 +203,8 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
                     // forward on instead to void page
                     // (otherwise, we'll have rendered an action parameters page 
                     // and so we'll be staying on that page)
-                    final ResultType resultType = ResultType.determineFor(null);
-                    resultType.addResults(this, null);
+                    final ActionResultResponseHandlingStrategy resultType = ActionResultResponseHandlingStrategy.determineFor(null);
+                    resultType.handleResults(this, null);
                 }
 
                 return false;
@@ -306,165 +285,6 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
         }
     }
 
-    enum ResultType {
-        OBJECT {
-            @Override
-            public void addResults(final ActionPanel actionPanel, final ObjectAdapter resultAdapter) {
-                final ObjectAdapter actualAdapter = determineActualAdapter(resultAdapter, actionPanel);
-                redirectToEntityPage(actionPanel, actualAdapter, null);
-            }
-
-            @Override
-            public void addResults(ActionPanel actionPanel, ObjectAdapter targetAdapter, ConcurrencyException ex) {
-                redirectToEntityPage(actionPanel, targetAdapter, ex);
-            }
-
-            private void redirectToEntityPage(final ActionPanel panel, final ObjectAdapter actualAdapter, ConcurrencyException exIfAny) {
-                panel.permanentlyHide(ID_ACTION_NAME);
-
-                // force any changes in state etc to happen now prior to the redirect;
-                // this should cause our page mementos (eg EntityModel) to hold the correct state.  I hope.
-                panel.getTransactionManager().flushTransaction();
-                
-                // build page, also propagate any concurrency exception that might have occurred already
-                final EntityPage entityPage = new EntityPage(actualAdapter, exIfAny);
-                
-                // "redirect-after-post"
-                panel.setResponsePage(entityPage);
-            }
-
-        },
-        COLLECTION {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                
-                final EntityCollectionModel collectionModel = EntityCollectionModel.createStandalone(resultAdapter);
-                collectionModel.setActionHint(panel.getActionModel());
-                
-                final StandaloneCollectionPage standaloneCollectionPage = new StandaloneCollectionPage(collectionModel);
-                
-                // "redirect-after-post"
-                panel.setResponsePage(standaloneCollectionPage);
-            }
-        },
-        VALUE {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                ValueModel valueModel = new ValueModel(resultAdapter);
-                valueModel.setActionHint(panel.getActionModel());
-                final ValuePage valuePage = new ValuePage(valueModel);
-                panel.setResponsePage(valuePage);
-            }
-        },
-        VALUE_CLOB {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                final Object value = resultAdapter.getObject();
-                RequestCycle requestCycle = panel.getRequestCycle();
-                IRequestHandler handler = ActionModel.downloadHandler(value);
-                requestCycle.scheduleRequestHandlerAfterCurrent(handler);
-            }
-        },
-        VALUE_BLOB {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                final Object value = resultAdapter.getObject();
-                RequestCycle requestCycle = panel.getRequestCycle();
-                IRequestHandler handler = ActionModel.downloadHandler(value);
-                requestCycle.scheduleRequestHandlerAfterCurrent(handler);
-            }
-
-        },
-        VALUE_URL {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                final Object value = resultAdapter.getObject();
-                IRequestHandler handler = ActionModel.redirectHandler(value);
-                RequestCycle requestCycle = panel.getRequestCycle();
-                requestCycle.scheduleRequestHandlerAfterCurrent(handler);
-            }
-
-        },
-        VOID {
-            @Override
-            public void addResults(final ActionPanel panel, final ObjectAdapter resultAdapter) {
-                
-                final VoidModel voidModel = new VoidModel();
-                voidModel.setActionHint(panel.getActionModel());
-                
-                final VoidReturnPage voidReturnPage = new VoidReturnPage(voidModel);
-                
-                panel.setResponsePage(voidReturnPage);
-            }
-        };
-
-        public abstract void addResults(ActionPanel panel, ObjectAdapter resultAdapter);
-
-        /**
-         * Only overridden for ResultType.OBJECT
-         */
-        public void addResults(ActionPanel actionPanel, ObjectAdapter targetAdapter, ConcurrencyException ex) {
-            throw new UnsupportedOperationException("Cannot render concurrency exception for any result type other than OBJECT");
-        }
-
-        static ResultType determineFor(final ObjectAdapter resultAdapter) {
-            if(resultAdapter == null) {
-                return ResultType.VOID;
-            }
-            final ObjectSpecification resultSpec = resultAdapter.getSpecification();
-            if (resultSpec.isNotCollection()) {
-                if (resultSpec.getFacet(ValueFacet.class) != null) {
-                    
-                    final Object value = resultAdapter.getObject();
-                    if(value instanceof Clob) {
-                        return ResultType.VALUE_CLOB;
-                    } 
-                    if(value instanceof Blob) {
-                        return ResultType.VALUE_BLOB;
-                    } 
-                    if(value instanceof java.net.URL) {
-                        return ResultType.VALUE_URL;
-                    } 
-                    // else
-                    return ResultType.VALUE;
-                } else {
-                    return ResultType.OBJECT;
-                }
-            } else {
-                final List<Object> pojoList = asList(resultAdapter);
-                switch (pojoList.size()) {
-                case 1:
-                    return ResultType.OBJECT;
-                default:
-                    return ResultType.COLLECTION;
-                }
-            }
-        }
-    }
-
-    private static ObjectAdapter determineActualAdapter(final ObjectAdapter resultAdapter, final PersistenceSessionProvider psa) {
-        ObjectAdapter actualAdapter;
-        if (resultAdapter.getSpecification().isNotCollection()) {
-            actualAdapter = resultAdapter;
-        } else {
-            // will only be a single element
-            final List<Object> pojoList = asList(resultAdapter);
-            final Object pojo = pojoList.get(0);
-            actualAdapter = adapterFor(pojo, psa);
-        }
-        return actualAdapter;
-    }
-    private static ObjectAdapter adapterFor(final Object pojo, final PersistenceSessionProvider psa) {
-        return psa.getPersistenceSession().getAdapterManager().adapterFor(pojo);
-    }
-    @SuppressWarnings("unchecked")
-    private static List<Object> asList(final ObjectAdapter resultAdapter) {
-        final Collection<Object> coll = (Collection<Object>) resultAdapter.getObject();
-        return coll instanceof List
-                ? (List<Object>)coll
-                : Lists.<Object>newArrayList(coll);
-    }
-
 
     ///////////////////////////////////////////////////////
     // Dependencies (from context)

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
index 03632d7..f9b9aa0 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/additionallinks/EntityActionUtil.java
@@ -25,9 +25,7 @@ import java.util.List;
 import com.google.common.base.Function;
 import com.google.common.collect.Lists;
 
-import org.apache.wicket.Page;
 import org.apache.wicket.Session;
-import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
@@ -42,7 +40,6 @@ import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectActions;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
@@ -66,9 +63,12 @@ public final class EntityActionUtil {
         final ObjectAdapter adapter = entityModel.load(ConcurrencyChecking.NO_CHECK);
         final ObjectAdapterMemento adapterMemento = entityModel.getObjectAdapterMemento();
         
-        @SuppressWarnings("unchecked")
-        final List<ObjectAction> userActions = adapterSpec.getObjectActions(ActionType.USER, Contributed.INCLUDED,
-                Filters.and(ObjectAction.Filters.memberOrderOf(association), EntityActionUtil.dynamicallyVisibleFor(adapter)));
+        @SuppressWarnings({ "unchecked", "deprecation" })
+        Filter<ObjectAction> filter = Filters.and(
+                ObjectAction.Filters.memberOrderOf(association), 
+                EntityActionUtil.dynamicallyVisibleFor(adapter),
+                ObjectAction.Filters.notBulkOnly());
+        final List<ObjectAction> userActions = adapterSpec.getObjectActions(ActionType.USER, Contributed.INCLUDED, filter);
         Collections.sort(userActions, new Comparator<ObjectAction>() {
 
             @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/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 0b5feb5..287e61d 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
@@ -18,6 +18,7 @@
  */
 package org.apache.isis.viewer.wicket.ui.components.collectioncontents.ajaxtable;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
@@ -32,9 +33,11 @@ import org.apache.wicket.Session;
 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.wicket.request.mapper.parameter.PageParameters;
 
 import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.Bulk.InteractionContext;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext.InvokedAs;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.commons.authentication.AuthenticationSessionProvider;
 import org.apache.isis.core.commons.authentication.MessageBroker;
@@ -49,11 +52,15 @@ 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.ActionPromptProvider;
 import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
 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.actionresponse.ActionResultResponse;
+import org.apache.isis.viewer.wicket.ui.actionresponse.ActionResultResponseType;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.CssMenuItem;
 import org.apache.isis.viewer.wicket.ui.components.widgets.cssmenu.ActionLinkFactory;
 import org.apache.isis.viewer.wicket.ui.errors.JGrowlBehaviour;
+import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
 
 final class BulkActionsLinkFactory implements ActionLinkFactory {
     
@@ -94,21 +101,25 @@ final class BulkActionsLinkFactory implements ActionLinkFactory {
                     
                     final List<Object> domainObjects = Lists.newArrayList(Iterables.transform(toggledAdapters, ObjectAdapter.Functions.getObject()));
                     
-                    try {
-                        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[]{});
+                    
+                    final Bulk.InteractionContext bulkInteractionContext = Bulk.InteractionContext.current.get();
+                    if (bulkInteractionContext != null) {
+                        bulkInteractionContext.setInvokedAs(InvokedAs.BULK);
+                        bulkInteractionContext.setDomainObjects(domainObjects);
+                    }
+
+                    ObjectAdapter lastReturnedAdapter = null;
+                    int i=0;
+                    for(final ObjectAdapter adapter : toggledAdapters) {
+    
+                        int numParameters = objectAction.getParameterCount();
+                        if(numParameters != 0) {
+                            return;
                         }
-                    } finally {
-                        Bulk.InteractionContext.current.set(null);
+                        if (bulkInteractionContext != null) {
+                            bulkInteractionContext.setIndex(i++);
+                        }
+                        lastReturnedAdapter = objectAction.execute(adapter, new ObjectAdapter[]{});
                     }
                     
                     model.clearToggleMementosList();
@@ -119,6 +130,14 @@ final class BulkActionsLinkFactory implements ActionLinkFactory {
                     } else {
                         model.setObject(persistentAdaptersWithin(model.getObject()));
                     }
+                    
+                    if(lastReturnedAdapter != null) {
+                        final ActionResultResponse resultResponse = 
+                                ActionResultResponseType.determineAndInterpretResult(actionModelHint, lastReturnedAdapter);
+                        if(resultResponse.isToPage()) {
+                            setResponsePage(resultResponse.getToPage());
+                        }
+                    }
 
                 } catch(final ConcurrencyException ex) {
                     

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index d6bfac4..1112199 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -79,6 +79,7 @@ public class CollectionContentsAsAjaxTablePanel extends PanelAbstract<EntityColl
     private static final String ID_ENTITY_ACTIONS = "entityActions";
     private static final String ID_ACTION_PROMPT_MODAL_WINDOW = "actionPromptModalWindow";
     
+    @SuppressWarnings("deprecation")
     private static final Predicate<ObjectAction> BULK = Filters.asPredicate(ObjectAction.Filters.bulk());
     
     private IsisAjaxFallbackDataTable<ObjectAdapter,String> dataTable;

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
index 5d5ea6c..70d4f57 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/header/EntityHeaderPanel.java
@@ -30,6 +30,7 @@ import org.apache.wicket.Component;
 import org.apache.wicket.Page;
 import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
 
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
 import org.apache.isis.applib.filter.Filters;
@@ -41,6 +42,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.core.progmodel.facets.actions.bulk.BulkFacet;
 import org.apache.isis.core.runtime.system.DeploymentType;
 import org.apache.isis.core.runtime.system.context.IsisContext;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
@@ -135,12 +137,16 @@ public class EntityHeaderPanel extends PanelAbstract<EntityModel> implements Act
 
     private void addTopLevelActions(final ObjectAdapter adapter, ActionType actionType, final List<ObjectAction> topLevelActions) {
         final ObjectSpecification adapterSpec = adapter.getSpecification();
-        @SuppressWarnings("unchecked")
-        final List<ObjectAction> userActions = adapterSpec.getObjectActions(actionType, Contributed.INCLUDED, 
-                Filters.and(memberOrderNameNotAssociation(adapterSpec), dynamicallyVisibleFor(adapter)));
+        @SuppressWarnings({ "unchecked", "deprecation" })
+        Filter<ObjectAction> filter = Filters.and(
+                memberOrderNameNotAssociation(adapterSpec), 
+                dynamicallyVisibleFor(adapter), 
+                ObjectAction.Filters.notBulkOnly());
+        final List<ObjectAction> userActions = adapterSpec.getObjectActions(actionType, Contributed.INCLUDED, filter);
         topLevelActions.addAll(userActions);
     }
     
+    @SuppressWarnings("deprecation")
     private static Filter<ObjectAction> memberOrderNameNotAssociation(final ObjectSpecification adapterSpec) {
 
         final List<ObjectAssociation> associations = adapterSpec.getAssociations(Contributed.INCLUDED);
@@ -162,6 +168,7 @@ public class EntityHeaderPanel extends PanelAbstract<EntityModel> implements Act
     }
     
 
+    @SuppressWarnings("deprecation")
     protected Filter<ObjectAction> dynamicallyVisibleFor(final ObjectAdapter adapter) {
         return ObjectAction.Filters.dynamicallyVisible(getAuthenticationSession(), adapter, Where.ANYWHERE);
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
index 377be19..8cf7c9e 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/cssmenu/ActionLinkFactoryAbstract.java
@@ -184,8 +184,7 @@ public abstract class ActionLinkFactoryAbstract implements ActionLinkFactory {
     // adapted from similar code in ActionPanel :-(
     private static ObjectAdapter executeActionHandlingApplicationExceptions(final ActionModel actionModel) {
         try {
-            ObjectAdapter resultAdapter = actionModel.getObject();
-            return resultAdapter;
+            return actionModel.getObject();
 
         } catch (RuntimeException ex) {
             

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/applib/pom.xml
----------------------------------------------------------------------
diff --git a/core/applib/pom.xml b/core/applib/pom.xml
index c79682d..7f8c669 100644
--- a/core/applib/pom.xml
+++ b/core/applib/pom.xml
@@ -95,7 +95,10 @@
             <groupId>javax.validation</groupId>
             <artifactId>validation-api</artifactId>
         </dependency>
-
+        <dependency>
+            <groupId>org.apache.geronimo.specs</groupId>
+            <artifactId>geronimo-jcdi_1.0_spec</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.isis.core</groupId>
             <artifactId>isis-core-unittestsupport</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/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 8a35466..07f12e1 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
@@ -25,8 +25,11 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
+import javax.enterprise.context.RequestScoped;
+
 /**
  * Indicates the (entity) action should be used only against many objects
  * in a collection.
@@ -49,44 +52,120 @@ import java.util.List;
 @Retention(RetentionPolicy.RUNTIME)
 public @interface Bulk {
     
+    public static enum AppliesTo {
+        BULK_AND_REGULAR,
+        BULK_ONLY
+    }
+    
+    AppliesTo value() default AppliesTo.BULK_AND_REGULAR;
+    
+    /**
+     * Register this as a service in order to access context information about a bulk action invocation.
+     */
+    @RequestScoped
     public static class InteractionContext {
 
+        public static enum InvokedAs {
+            BULK,
+            REGULAR
+        }
+
         /**
          * 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.
+         * @deprecated - now a {@link RequestScoped} service
          */
+        @Deprecated
         public static final ThreadLocal<InteractionContext> current = new ThreadLocal<InteractionContext>();
 
-        private final List<Object> domainObjects;
-        private final int size;
+        /**
+         * @deprecated - now a {@link RequestScoped} service
+         */
+        @Deprecated
+        public static void with(final Runnable runnable, final Object... domainObjects) {
+            throw new RuntimeException("No longer supported - instead inject Bulk.InteractionContext as service");
+        }
+
+        /**
+         * @deprecated - now a {@link RequestScoped} service
+         */
+        @Deprecated
+        public static void with(final Runnable runnable, final InvokedAs invokedAs, final Object... domainObjects) {
+            throw new RuntimeException("No longer supported - instead inject Bulk.InteractionContext as service");
+        }
+        
+        // //////////////////////////////////////
+        
+        /**
+         * Intended only to support unit testing.
+         */
+        public static InteractionContext regularAction(Object domainObject) {
+            return new InteractionContext(InvokedAs.REGULAR, Collections.singletonList(domainObject));
+        }
+        
+        /**
+         * Intended only to support unit testing.
+         */
+        public static InteractionContext bulkAction(Object... domainObjects) {
+            return bulkAction(Arrays.asList(domainObjects));
+        }
+
+        /**
+         * Intended only to support unit testing.
+         */
+        public static InteractionContext bulkAction(List<Object> domainObjects) {
+            return new InteractionContext(InvokedAs.BULK, domainObjects);
+        }
         
+        // //////////////////////////////////////
+
+        private InvokedAs invokedAs;
+        private List<Object> domainObjects;
+        private int size;
+
         private int index;
 
-        public InteractionContext(Object... domainObjects) {
-            this(Arrays.asList(domainObjects));
+        // //////////////////////////////////////
+
+        
+        public InteractionContext() {
+        }
+
+        /**
+         * @deprecated - now a {@link RequestScoped} service
+         */
+        @Deprecated
+        public InteractionContext(final InvokedAs invokedAs, final Object... domainObjects) {
+            this(invokedAs, Arrays.asList(domainObjects));
         }
 
-        public InteractionContext(List<Object> domainObjects) {
+        /**
+         * @deprecated - now a {@link RequestScoped} service
+         */
+        @Deprecated
+        public InteractionContext(final InvokedAs invokedAs, final List<Object> domainObjects) {
+            this.invokedAs = invokedAs;
             this.domainObjects = domainObjects;
             this.size = domainObjects.size();
         }
 
-        public List<Object> getDomainObjects() {
-            return domainObjects;
+        // //////////////////////////////////////
+
+        /**
+         * <b>NOT API</b>: intended to be called only by the framework.
+         */
+        public void setInvokedAs(InvokedAs invokedAs) {
+            this.invokedAs = invokedAs;
         }
         
         /**
-         * Will be a value in range [0, {@link #getSize() size}).
+         * <b>NOT API</b>: intended to be called only by the framework.
          */
-        public int getIndex() {
-            return index;
+        public void setDomainObjects(List<Object> domainObjects) {
+            this.domainObjects = domainObjects;
         }
         
         /**
@@ -96,29 +175,63 @@ public @interface Bulk {
             this.index = index;
         }
         
+        // //////////////////////////////////////
+
+        
+        /**
+         * Whether this particular {@link InteractionContext} was applied as a {@link InvokedAs#BULK bulk} action 
+         * (against each domain object in a list of domain objects) or as a {@link InvokedAs#REGULAR regular} 
+         * action (against a single domain object).
+         */
+        @Programmatic
+        public InvokedAs getInvokedAs() {
+            return invokedAs;
+        }
+        
+        /**
+         * The list of domain objects which are being acted upon.
+         */
+        @Programmatic
+        public List<Object> getDomainObjects() {
+            return domainObjects;
+        }
+        
+        /**
+         * The number of {@link #domainObjects domain objects} being acted upon.
+         */
+        @Programmatic
         public int getSize() {
-            return size;
+            return domainObjects.size();
         }
 
+        /**
+         * The 0-based index to the object being acted upon.
+         * 
+         * <p>
+         * Will be a value in range [0, {@link #getSize() size}).
+         */
+        @Programmatic
+        public int getIndex() {
+            return index;
+        }
+
+        /**
+         * Whether this object being acted upon is the first such.
+         */
+        @Programmatic
         public boolean isFirst() {
             return this.index == 0;
         }
         
-        public boolean isLast() {
-            return this.index == (size-1);
-        }
-
         /**
-         * @param runnable
+         * Whether this object being acted upon is the last such.
          */
-        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);
-            }
+        @Programmatic
+        public boolean isLast() {
+            return this.index == (getSize()-1);
         }
 
+
     }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java b/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
new file mode 100644
index 0000000..d3b351a
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/scratchpad/Scratchpad.java
@@ -0,0 +1,67 @@
+/*
+ *  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.isis.applib.services.scratchpad;
+
+import java.util.Map;
+
+import javax.enterprise.context.RequestScoped;
+
+import com.google.common.collect.Maps;
+
+import org.apache.isis.applib.annotation.Bulk.InteractionContext;
+import org.apache.isis.applib.annotation.Programmatic;
+
+@RequestScoped
+public class Scratchpad {
+    
+    /**
+     * Provides a mechanism for each object being acted upon to pass
+     * data to the next object.
+     */
+    private final Map<Object, Object> userData = Maps.newHashMap();
+    
+    /**
+     * Obtain user-data, as set by a previous object being acted upon.
+     */
+    @Programmatic
+    public Object get(Object key) {
+        return userData.get(key);
+    }
+    /**
+     * Set user-data, for the use of a subsequent object being acted upon.
+     */
+    @Programmatic
+    public void put(Object key, Object value) {
+        userData.put(key, value);
+    }
+    
+    /**
+     * Clear any user data.
+     * 
+     * <p>
+     * Note that a new instance of {@link InteractionContext} is created for
+     * any given bulk action, and so it isn't required for the user data to be
+     * cleared down.
+     */
+    @Programmatic
+    public void clear() {
+        userData.clear();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/bytecode-javassist/pom.xml
----------------------------------------------------------------------
diff --git a/core/bytecode-javassist/pom.xml b/core/bytecode-javassist/pom.xml
index 1ca86e0..c65a861 100644
--- a/core/bytecode-javassist/pom.xml
+++ b/core/bytecode-javassist/pom.xml
@@ -83,7 +83,7 @@
 		</dependency>
 
         <dependency>
-            <groupId>javassist</groupId>
+            <groupId>org.javassist</groupId>
             <artifactId>javassist</artifactId>
         </dependency>
 	</dependencies>

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistClassSubstitutor.java
----------------------------------------------------------------------
diff --git a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistClassSubstitutor.java b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistClassSubstitutor.java
index aecb166..cabad16 100644
--- a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistClassSubstitutor.java
+++ b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistClassSubstitutor.java
@@ -19,27 +19,12 @@
 
 package org.apache.isis.core.bytecode.javassist;
 
-import org.apache.isis.core.commons.lang.ClassUtil;
 import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutorAbstract;
 
+/**
+ * @deprecated - moved to core
+ */
+@Deprecated
 public class JavassistClassSubstitutor extends ClassSubstitutorAbstract {
 
-    public JavassistClassSubstitutor() {
-        ignore("javassist.util.proxy.ProxyObject");
-        ignore("javassist.util.proxy.MethodHandler");
-    }
-
-    /**
-     * If {@link JavassistEnhanced} then return superclass, else as per
-     * {@link ClassSubstitutorAbstract#getClass(Class) superclass'}
-     * implementation.
-     */
-    @Override
-    public Class<?> getClass(final Class<?> cls) {
-        if (ClassUtil.directlyImplements(cls, JavassistEnhanced.class)) {
-            return getClass(cls.getSuperclass());
-        }
-        return super.getClass(cls);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistEnhanced.java
----------------------------------------------------------------------
diff --git a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistEnhanced.java b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistEnhanced.java
index ada3e1e..a140522 100644
--- a/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistEnhanced.java
+++ b/core/bytecode-javassist/src/main/java/org/apache/isis/core/bytecode/javassist/JavassistEnhanced.java
@@ -23,7 +23,10 @@ package org.apache.isis.core.bytecode.javassist;
 /**
  * Marker interface that we make entities implement so easy to spot in the
  * {@link JavassistClassSubstitutor}.
+ * 
+ * @deprecated - moved into core
  */
-public interface JavassistEnhanced {
+@Deprecated
+public interface JavassistEnhanced extends org.apache.isis.core.metamodel.specloader.classsubstitutor.JavassistEnhanced{
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index d29a202..4efb3f0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -24,6 +24,7 @@ import java.util.List;
 import com.google.common.base.Strings;
 
 import org.apache.isis.applib.annotation.ActionSemantics;
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
@@ -150,7 +151,8 @@ public interface ObjectAction extends ObjectMember {
      * 
      * @return
      */
-    List<ObjectActionParameter> getParameters(Filter<ObjectActionParameter> filter);
+    List<ObjectActionParameter> getParameters(
+            @SuppressWarnings("deprecation") Filter<ObjectActionParameter> filter);
 
     /**
      * Returns the parameter with provided id.
@@ -210,6 +212,7 @@ public interface ObjectAction extends ObjectMember {
         
         private Filters(){}
         
+        @SuppressWarnings("deprecation")
         public static final Filter<ObjectAction> VISIBLE_AT_LEAST_SOMETIMES = new Filter<ObjectAction>() {
             @Override
             public boolean accept(final ObjectAction action) {
@@ -218,6 +221,7 @@ public interface ObjectAction extends ObjectMember {
             }
         };
 
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> dynamicallyVisible(final AuthenticationSession session, final ObjectAdapter target, final Where where) {
             return new Filter<ObjectAction>() {
                 @Override
@@ -228,6 +232,7 @@ public interface ObjectAction extends ObjectMember {
             };
         }
 
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> withId(final String actionId) {
             return new Filter<ObjectAction>(){
                 @Override
@@ -237,6 +242,7 @@ public interface ObjectAction extends ObjectMember {
             };
         }
 
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> withNoValidationRules() {
             return new Filter<ObjectAction>(){
                 @Override
@@ -246,6 +252,7 @@ public interface ObjectAction extends ObjectMember {
                 }};
         }
 
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> ofType(final ActionType type) {
             return new Filter<ObjectAction>(){
                 @Override
@@ -255,6 +262,7 @@ public interface ObjectAction extends ObjectMember {
             };
         }
 
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> bulk() {
             return new Filter<ObjectAction>(){
 
@@ -264,6 +272,19 @@ public interface ObjectAction extends ObjectMember {
                 }};
         }
         
+        @SuppressWarnings("deprecation")
+        public static Filter<ObjectAction> notBulkOnly() {
+            return new Filter<ObjectAction>(){
+
+                @Override
+                public boolean accept(ObjectAction t) {
+                    BulkFacet facet = t.getFacet(BulkFacet.class);
+                    return facet == null || facet.value() != Bulk.AppliesTo.BULK_ONLY;
+                }};
+        }
+
+
+        @SuppressWarnings("deprecation")
         public static Filter<ObjectAction> memberOrderOf(ObjectAssociation association) {
             final String assocName = association.getName();
             final String assocId = association.getId();

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorAbstract.java
index a391b83..761d64f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/ClassSubstitutorAbstract.java
@@ -24,6 +24,7 @@ import java.util.Set;
 import com.google.common.collect.Sets;
 
 import org.apache.isis.applib.DomainObjectContainer;
+import org.apache.isis.core.commons.lang.ClassUtil;
 
 public abstract class ClassSubstitutorAbstract implements ClassSubstitutor {
 
@@ -86,6 +87,9 @@ public abstract class ClassSubstitutorAbstract implements ClassSubstitutor {
         if(superclass != null && superclass.isEnum()) {
             return superclass;
         }
+        if (ClassUtil.directlyImplements(cls, JavassistEnhanced.class)) {
+            return getClass(cls.getSuperclass());
+        }
         return cls;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/JavassistEnhanced.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/JavassistEnhanced.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/JavassistEnhanced.java
new file mode 100644
index 0000000..1dcb573
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/classsubstitutor/JavassistEnhanced.java
@@ -0,0 +1,28 @@
+/*
+ *  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.isis.core.metamodel.specloader.classsubstitutor;
+
+/**
+ * Marker interface for entities/services that have been enhanced with
+ * javassist.
+ */
+public interface JavassistEnhanced {
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacet.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacet.java
index fd3d284..4b71149 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacet.java
@@ -19,7 +19,8 @@
 
 package org.apache.isis.core.progmodel.facets.actions.bulk;
 
-import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.applib.annotation.Bulk;
+import org.apache.isis.core.metamodel.facets.SingleValueFacet;
 
 /**
  * Indicates that the action (entity or service) can also be used as a bulk
@@ -29,6 +30,7 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
  * In the standard Apache Isis Programming Model, corresponds to annotating the
  * action method using <tt>@Bulk</tt>.
  */
-public interface BulkFacet extends Facet {
+public interface BulkFacet extends SingleValueFacet<Bulk.AppliesTo> {
 
+    public Bulk.AppliesTo value();
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacetAbstract.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacetAbstract.java
index 3cd7452..685a775 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/BulkFacetAbstract.java
@@ -19,18 +19,19 @@
 
 package org.apache.isis.core.progmodel.facets.actions.bulk;
 
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facets.MarkerFacetAbstract;
+import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract;
 
-public abstract class BulkFacetAbstract extends MarkerFacetAbstract implements BulkFacet {
+public abstract class BulkFacetAbstract extends SingleValueFacetAbstract<Bulk.AppliesTo> implements BulkFacet {
 
     public static Class<? extends Facet> type() {
         return BulkFacet.class;
     }
 
-    public BulkFacetAbstract(final FacetHolder holder) {
-        super(type(), holder);
+    public BulkFacetAbstract(Bulk.AppliesTo appliesTo, final FacetHolder holder) {
+        super(type(), appliesTo, holder);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkAnnotationFacetFactory.java
index d16fcb6..f00e8ef 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkAnnotationFacetFactory.java
@@ -47,7 +47,7 @@ public class BulkAnnotationFacetFactory extends FacetFactoryAbstract {
     }
 
     private BulkFacet create(final Bulk annotation, final FacetHolder holder) {
-        return annotation == null ? null : new BulkFacetAnnotation(holder);
+        return annotation == null ? null : new BulkFacetAnnotation(annotation.value(), holder);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkFacetAnnotation.java
index 3e4b3ee..5b3da72 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkFacetAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/actions/bulk/annotation/BulkFacetAnnotation.java
@@ -19,13 +19,14 @@
 
 package org.apache.isis.core.progmodel.facets.actions.bulk.annotation;
 
+import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.progmodel.facets.actions.bulk.BulkFacetAbstract;
 
 public class BulkFacetAnnotation extends BulkFacetAbstract {
 
-    public BulkFacetAnnotation(final FacetHolder holder) {
-        super(holder);
+    public BulkFacetAnnotation(Bulk.AppliesTo value, final FacetHolder holder) {
+        super(value, holder);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/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 7a9ab55..9dba6e8 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
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
 
 import org.apache.isis.applib.annotation.Bulk;
 import org.apache.isis.applib.annotation.Bulk.InteractionContext;
+import org.apache.isis.applib.annotation.Bulk.InteractionContext.InvokedAs;
 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;
@@ -97,19 +98,15 @@ public class ActionInvocationFacetViaMethod extends ActionInvocationFacetAbstrac
             final Object object = unwrap(inObject);
             
             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);
+            if(bulkFacet != null) {
+                Bulk.InteractionContext bulkInteractionContext = Bulk.InteractionContext.current.get();
+                if (bulkInteractionContext != null && bulkInteractionContext.getInvokedAs() == null) {
+                    bulkInteractionContext.setInvokedAs(InvokedAs.REGULAR);
+                    bulkInteractionContext.setDomainObjects(Collections.singletonList(object));
                 }
-            } else {
-                result = method.invoke(object, executionParameters);
             }
+            result = method.invoke(object, executionParameters);
             
             if (LOG.isDebugEnabled()) {
                 LOG.debug(" action result " + result);

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/pom.xml
----------------------------------------------------------------------
diff --git a/core/pom.xml b/core/pom.xml
index eb881ab..cb1b6cb 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -1261,9 +1261,9 @@ ${license.additional-notes}
                 <version>2.2.2</version>
             </dependency>
             <dependency>
-                <groupId>javassist</groupId>
+                <groupId>org.javassist</groupId>
                 <artifactId>javassist</artifactId>
-                <version>3.12.1.GA</version>
+                <version>3.18.1-GA</version>
             </dependency>
 
             <!-- XML libraries -->
@@ -1501,6 +1501,12 @@ ${license.additional-notes}
                 <version>1.1.0.Final</version>
             </dependency>
 
+            <dependency>
+                <groupId>org.apache.geronimo.specs</groupId>
+                <artifactId>geronimo-jcdi_1.0_spec</artifactId>
+                <version>1.0</version>
+            </dependency>
+
            <dependency>
                <groupId>org.picocontainer</groupId>
                <artifactId>picocontainer</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/runtime/pom.xml
----------------------------------------------------------------------
diff --git a/core/runtime/pom.xml b/core/runtime/pom.xml
index 60ab785..67d0541 100644
--- a/core/runtime/pom.xml
+++ b/core/runtime/pom.xml
@@ -126,6 +126,11 @@
 			<scope>test</scope>
 		</dependency>
 
+        <dependency>
+            <groupId>org.javassist</groupId>
+            <artifactId>javassist</artifactId>
+        </dependency>
+
 	    <dependency>
             <groupId>org.apache.geronimo.specs</groupId>
             <artifactId>geronimo-servlet_2.5_spec</artifactId>

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ClassSubstitutorDefault.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ClassSubstitutorDefault.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ClassSubstitutorDefault.java
new file mode 100644
index 0000000..05ef574
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ClassSubstitutorDefault.java
@@ -0,0 +1,29 @@
+/*
+ *  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.isis.core.runtime.bytecode.dflt;
+
+import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutorAbstract;
+
+public class ClassSubstitutorDefault extends ClassSubstitutorAbstract {
+
+    public ClassSubstitutorDefault() {
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ObjectFactoryBasic.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ObjectFactoryBasic.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ObjectFactoryBasic.java
new file mode 100644
index 0000000..7ad7742
--- /dev/null
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/dflt/ObjectFactoryBasic.java
@@ -0,0 +1,54 @@
+/*
+ *  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.isis.core.runtime.bytecode.dflt;
+
+import java.lang.reflect.Modifier;
+
+import org.apache.isis.core.metamodel.spec.ObjectInstantiationException;
+import org.apache.isis.core.runtime.persistence.objectfactory.ObjectFactoryAbstract;
+
+public class ObjectFactoryBasic extends ObjectFactoryAbstract {
+
+    public ObjectFactoryBasic() {
+    }
+
+    public ObjectFactoryBasic(final Mode mode) {
+        super(mode);
+    }
+
+    /**
+     * Simply instantiates reflectively, does not enhance bytecode etc in any
+     * way.
+     */
+    @Override
+    protected <T> T doInstantiate(final Class<T> cls) throws ObjectInstantiationException {
+        if (Modifier.isAbstract(cls.getModifiers())) {
+            throw new ObjectInstantiationException("Cannot create an instance of an abstract class: " + cls);
+        }
+        try {
+            return cls.newInstance();
+        } catch (final IllegalAccessException e) {
+            throw new ObjectInstantiationException(e);
+        } catch (final InstantiationException e) {
+            throw new ObjectInstantiationException(e);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/e7f97df5/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/identity/ClassSubstitutorIdentity.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/identity/ClassSubstitutorIdentity.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/identity/ClassSubstitutorIdentity.java
deleted file mode 100644
index 6da6df8..0000000
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/bytecode/identity/ClassSubstitutorIdentity.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *  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.isis.core.runtime.bytecode.identity;
-
-import org.apache.isis.core.metamodel.specloader.classsubstitutor.ClassSubstitutorAbstract;
-
-public class ClassSubstitutorIdentity extends ClassSubstitutorAbstract {
-
-    public ClassSubstitutorIdentity() {
-        
-
-    }
-
-}