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/11 14:15:11 UTC

git commit: ISIS-401: reinstated and refined concurrency checking for invoking actions

Updated Branches:
  refs/heads/master e57e4281d -> bda2045b3


ISIS-401: reinstated and refined concurrency checking for invoking actions

specifically
- if invoking an action with "safe" semantics, then no concurrency checking is performed
- if invoke a no-arg action, and detect change, then render the entity
  and pop up a warning
- if invoke an action with args, and detect change, then render the entity (rather than
  the action prompt form) and pop up a warning


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

Branch: refs/heads/master
Commit: bda2045b34fc7a7392f6fce68031bee7d500ccac
Parents: e57e428
Author: Dan Haywood <da...@apache.org>
Authored: Fri Oct 11 13:14:06 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Oct 11 13:14:06 2013 +0100

----------------------------------------------------------------------
 .../model/mementos/ObjectAdapterMemento.java    | 14 ++++++---
 .../viewer/wicket/model/models/ActionModel.java |  1 -
 .../ui/components/actions/ActionPanel.java      | 33 +++++++++++++++-----
 .../entity/EntityActionLinkFactory.java         | 13 ++++----
 .../metamodel/adapter/mgr/AdapterManager.java   |  6 ++++
 .../DeveloperUtilitiesServiceDefault.java       |  1 -
 .../dom/src/main/java/dom/todo/ToDoItems.java   |  6 ++--
 7 files changed, 51 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
index 0193a7e..af0dc41 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/mementos/ObjectAdapterMemento.java
@@ -102,12 +102,18 @@ public class ObjectAdapterMemento implements Serializable {
             @Override
             ObjectAdapter recreateAdapter(final ObjectAdapterMemento oam, ConcurrencyChecking concurrencyChecking) {
                 TypedOid oid = getOidMarshaller().unmarshal(oam.persistentOidStr, TypedOid.class);
-                final ObjectAdapter adapter = getAdapterManager().adapterFor(oid, concurrencyChecking);
-                // reset version
-                if(concurrencyChecking == ConcurrencyChecking.NO_CHECK) {
+                try {
+                    final ObjectAdapter adapter = getAdapterManager().adapterFor(oid, concurrencyChecking);
+                    return adapter;
+                    
+                } finally {
+                    // a side-effect of AdapterManager#adapterFor(...) is that it will update the oid
+                    // with the correct version, even when there is a concurrency exception
+                    // we copy this updated oid string into our memento so that, if we retry, 
+                    // we will succeed second time around
+                    
                     oam.persistentOidStr = oid.enString(getOidMarshaller());
                 }
-                return adapter;
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index 672bb53..0ecd130 100644
--- a/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/component/viewer/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -117,7 +117,6 @@ public class ActionModel extends BookmarkableModel<ObjectAdapter> {
         final Mode actionMode = determineActionMode(objectAction, contextAdapter);
         PageParameterNames.ACTION_MODE.addEnumTo(pageParameters, actionMode);
 
-        //addActionParamContextIfPossible(objectAction, contextAdapter, pageParameters);
         return pageParameters;
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/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 756b53c..fafe250 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
@@ -108,12 +108,33 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
     }
 
     private void buildGuiForParameters(ActionModel actionModel) {
-        hideAllBut(ComponentType.PARAMETERS, ComponentType.ENTITY_ICON_AND_TITLE);
-        getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.PARAMETERS, getActionModel());
-        getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.ENTITY_ICON_AND_TITLE, new EntityModel(getActionModel().getTargetAdapter()));
 
-        final String actionName = getActionModel().getActionMemento().getAction().getName();
-        addOrReplace(new Label(ID_ACTION_NAME, Model.of(actionName)));
+
+        ObjectAdapter targetAdapter = null;
+        try {
+            targetAdapter = getActionModel().getTargetAdapter();
+            
+            hideAllBut(ComponentType.PARAMETERS, ComponentType.ENTITY_ICON_AND_TITLE);
+            getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.PARAMETERS, getActionModel());
+            getComponentFactoryRegistry().addOrReplaceComponent(this, ComponentType.ENTITY_ICON_AND_TITLE, new EntityModel(targetAdapter));
+
+            final String actionName = getActionModel().getActionMemento().getAction().getName();
+            addOrReplace(new Label(ID_ACTION_NAME, Model.of(actionName)));
+            
+        } catch (final ConcurrencyException ex) {
+
+            // second attempt should succeed, because the Oid would have
+            // been updated in the attempt
+            if (targetAdapter == null) {
+                targetAdapter = getModel().getTargetAdapter();
+            }
+            
+            // forward onto the target page with the concurrency exception
+            ResultType.OBJECT.addResults(this, targetAdapter, ex);
+
+            getMessageBroker().addWarning(ex.getMessage());
+
+        }
     }
 
     protected void bookmarkPage(BookmarkableModel<?> model) {
@@ -153,8 +174,6 @@ public class ActionPanel extends PanelAbstract<ActionModel> implements ActionExe
 
                 
                 // forward onto the target page with the concurrency exception
-                
-                // REVIEW: doesn't seem to get rendered
                 ResultType.OBJECT.addResults(this, targetAdapter, ex);
 
                 getMessageBroker().addWarning(ex.getMessage());

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
index 1dde6e8..89cb386 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/EntityActionLinkFactory.java
@@ -25,6 +25,7 @@ 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.ActionSemantics;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.commons.authentication.AuthenticationSession;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -102,13 +103,11 @@ public final class EntityActionLinkFactory implements CssMenuLinkFactory {
         final ObjectAdapter adapter = adapterMemento.getObjectAdapter(ConcurrencyChecking.NO_CHECK);
         final ObjectAdapter contextAdapter = entityModel.getObject();
 
-        // use NO concurrency checking because the link is rendered on the entity page.
-        
-        // REVIEW: is this good enough?  
-        // - On the one hand we need it because otherwise a change done by this user basically prevents all actions from working
-        // - on the other hand, if a change were made by some other user, then this user would want to know...
-        //   perhaps the generated bookmarks need to subscribe to the EntityModel that backs the page?
-        final PageParameters pageParameters = ActionModel.createPageParameters(adapter, action, contextAdapter, ActionModel.SingleResultsMode.REDIRECT, ConcurrencyChecking.NO_CHECK);
+        // use the action semantics to determine whether invoking this action will require a concurrency check or not
+        // if it's "safe", then we'll just continue without any checking. 
+        final ConcurrencyChecking concurrencyChecking = 
+                action.getSemantics() == ActionSemantics.Of.SAFE? ConcurrencyChecking.NO_CHECK: ConcurrencyChecking.CHECK;
+        final PageParameters pageParameters = ActionModel.createPageParameters(adapter, action, contextAdapter, ActionModel.SingleResultsMode.REDIRECT, concurrencyChecking);
         final Class<? extends Page> pageClass = getPageClassRegistry().getPageClass(PageType.ACTION);
         return Links.newBookmarkablePageLink(linkId, pageParameters, pageClass);
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
index 2634a65..28fc618 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/mgr/AdapterManager.java
@@ -28,6 +28,7 @@ import org.apache.isis.core.metamodel.adapter.ResolveState;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.TypedOid;
 import org.apache.isis.core.metamodel.adapter.version.ConcurrencyException;
+import org.apache.isis.core.metamodel.adapter.version.Version;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
@@ -154,6 +155,11 @@ public interface AdapterManager extends Injectable {
      * of the {@link TypedOid oid} of the recreated adapter is the same as that of the provided {@link TypedOid oid}.
      * If the version differs, then a {@link ConcurrencyException} is thrown.
      * 
+     * <p>
+     * ALSO, even if a {@link ConcurrencyException}, then the provided {@link TypedOid oid}'s {@link Version version}
+     * will be {@link TypedOid#setVersion(org.apache.isis.core.metamodel.adapter.version.Version) set} to the current 
+     * value.  This allows the client to retry if they wish.
+     * 
      * @throws {@link ObjectNotFoundException} if the object does not exist.
      */
     ObjectAdapter adapterFor(TypedOid oid, ConcurrencyChecking concurrencyChecking);

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
index 47cbee7..1c13ab6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/devutils/DeveloperUtilitiesServiceDefault.java
@@ -43,7 +43,6 @@ import org.apache.isis.applib.value.Clob;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
 import org.apache.isis.core.metamodel.adapter.mgr.AdapterManagerAware;
-import org.apache.isis.core.metamodel.facets.actions.homepage.HomePageFacet;
 import org.apache.isis.core.metamodel.layoutmetadata.json.LayoutMetadataReaderFromJson;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.SpecificationLoaderSpi;

http://git-wip-us.apache.org/repos/asf/isis/blob/bda2045b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
index 1d9b7fb..57e7dfc 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItems.java
@@ -141,15 +141,15 @@ public class ToDoItems {
         final String ownedBy = currentUserName();
         return newToDo(description, category, subcategory, ownedBy, dueBy, cost);
     }
-    public LocalDate default3NewToDo() {
-        return new LocalDate(Clock.getTime()).plusDays(14);
-    }
     public Category default1NewToDo() {
         return Category.Professional;
     }
     public Subcategory default2NewToDo() {
         return Category.Professional.subcategories().get(0);
     }
+    public LocalDate default3NewToDo() {
+        return clockService.now().plusDays(14);
+    }
     public List<Subcategory> choices2NewToDo(
             final String description, final Category category) {
         return Subcategory.listFor(category);