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/09/20 01:22:07 UTC

git commit: ISIS-539, ISIS-503: @Disabled(reason=...), contributed associations always disabled

Updated Branches:
  refs/heads/master 9197e40c9 -> 6490b19a9


ISIS-539, ISIS-503: @Disabled(reason=...), contributed associations always disabled

In addition
* some of the wicket widgets now correctly add a title attribute if they are disabled
* minor fixes to ToDo example app


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

Branch: refs/heads/master
Commit: 6490b19a95efe6c7b24a583fc1d8bc4c98301c3f
Parents: 9197e40
Author: Dan Haywood <da...@apache.org>
Authored: Fri Sep 20 00:21:47 2013 +0100
Committer: Dan Haywood <da...@apache.org>
Committed: Fri Sep 20 00:21:47 2013 +0100

----------------------------------------------------------------------
 .../scalars/ScalarPanelTextFieldAbstract.java   |  2 --
 .../scalars/reference/ReferencePanel.java       |  6 ++++
 .../valuechoices/ValueChoicesSelect2Panel.java  | 13 ++++++++
 .../apache/isis/applib/annotation/Disabled.java |  1 +
 .../OneToManyAssociationContributee.java        | 31 ++++++++++++------
 .../OneToOneAssociationContributee.java         | 33 +++++++++++++++-----
 .../members/disabled/DisabledFacetImpl.java     | 21 ++++++++++---
 .../DisabledAnnotationFacetFactory.java         |  2 +-
 .../annotation/DisabledFacetAnnotation.java     |  4 +--
 .../DisabledAnnotationFacetFactoryTest.java     | 33 ++++++++++++++++++++
 .../dom/src/main/java/dom/todo/ToDoItem.java    | 17 +++++++---
 .../java/dom/todo/ToDoItemContributions.java    |  2 ++
 .../tests/actions/ToDoItemTest_duplicate.java   |  2 +-
 .../ToDoItemContributionsTest_priority.java     |  2 +-
 .../tests/props/ToDoItemTest_category.java      |  6 ++--
 .../tests/props/ToDoItemTest_cost.java          |  4 +--
 .../tests/props/ToDoItemTest_subcategory.java   |  6 ++--
 17 files changed, 142 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
index 4f21325..71b436f 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelTextFieldAbstract.java
@@ -49,8 +49,6 @@ public abstract class ScalarPanelTextFieldAbstract<T extends Serializable> exten
     
     protected static final String ID_SCALAR_VALUE = "scalarValue";
 
-    private static final String ID_FEEDBACK = "feedback";
-
     protected static final String ID_SCALAR_IF_COMPACT = "scalarIfCompact";
 
     protected final Class<T> cls;

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
index c15bd1d..9ce98d7 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
@@ -76,9 +76,15 @@ public class ReferencePanel extends ScalarPanelAbstract {
         final EntityModel entityLinkModel = (EntityModel) entityLink.getModel();
         entityLinkModel.toViewMode();
         
+        setTitleAttribute(disableReason);
+
         entityLink.syncVisibilityAndUsability();
     }
 
+    private void setTitleAttribute(final String titleAttribute) {
+        entityLink.add(new AttributeModifier("title", Model.of(titleAttribute)));
+    }
+
     @Override
     protected FormComponentLabel addComponentForRegular() {
         final ScalarModel scalarModel = getModel();

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
index f2cdf6a..aa876e4 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/valuechoices/ValueChoicesSelect2Panel.java
@@ -40,6 +40,7 @@ import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager.ConcurrencyChec
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOidDefault;
 import org.apache.isis.viewer.wicket.model.mementos.ObjectAdapterMemento;
+import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.models.ModelAbstract;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModelWithPending;
@@ -172,6 +173,16 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
         select2Field.setEnabled(true);
     }
 
+    @Override
+    protected void onBeforeRenderWhenDisabled(final String disableReason) {
+        super.onBeforeRenderWhenDisabled(disableReason);
+        setTitleAttribute(disableReason);
+    }
+
+    private void setTitleAttribute(final String titleAttribute) {
+        getComponentForRegular().add(new AttributeModifier("title", Model.of(titleAttribute)));
+    }
+
     
     @Override
     protected void addFormComponentBehavior(Behavior behavior) {
@@ -209,6 +220,8 @@ public class ValueChoicesSelect2Panel extends ScalarPanelAbstract implements Sca
     }
 
     
+
+    
     // //////////////////////////////////////
 
     public ObjectAdapterMemento getPending() {

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/applib/src/main/java/org/apache/isis/applib/annotation/Disabled.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Disabled.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Disabled.java
index 36cc7c5..f0ebd01 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Disabled.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Disabled.java
@@ -34,4 +34,5 @@ import java.lang.annotation.Target;
 public @interface Disabled {
     When when() default When.ALWAYS;
     Where where() default Where.ANYWHERE;
+    String reason() default "";
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationContributee.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationContributee.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationContributee.java
index 4c66147..203f0af 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationContributee.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationContributee.java
@@ -20,6 +20,8 @@ import java.util.List;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.applib.annotation.Render;
+import org.apache.isis.applib.annotation.When;
+import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -36,15 +38,14 @@ import org.apache.isis.core.metamodel.facets.typeof.TypeOfFacetAbstract;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMemberContext;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacetImpl;
 
 public class OneToManyAssociationContributee extends OneToManyAssociationImpl implements ContributeeMember {
 
     private final ObjectAdapter serviceAdapter;
     private final ObjectAction objectAction;
     
-    private final RenderFacet renderFacet;
-    private final NotPersistedFacet notPersistedFacet;
-    private final TypeOfFacet typeOfFacet; 
 
     /**
      * Hold facets rather than delegate to the contributed action (different types might
@@ -67,16 +68,18 @@ public class OneToManyAssociationContributee extends OneToManyAssociationImpl im
         super(serviceAction.getFacetedMethod(), typeOfSpec(serviceAction, objectMemberContext), objectMemberContext);
         this.serviceAdapter = serviceAdapter;
         this.objectAction = serviceAction;
-        
-        renderFacet = new RenderFacetAbstract(Render.Type.EAGERLY, this) {};
-        notPersistedFacet = new NotPersistedFacetAbstract(this) {};
-        typeOfFacet = new TypeOfFacetAbstract(getSpecification().getCorrespondingClass(), this, objectMemberContext.getSpecificationLookup()) {};
-        
+
         // copy over facets from contributed to own.
         FacetUtil.copyFacets(serviceAction.getFacetedMethod(), facetHolder);
         
+        final RenderFacet renderFacet = new RenderFacetAbstract(Render.Type.EAGERLY, this) {};
+        final NotPersistedFacet notPersistedFacet = new NotPersistedFacetAbstract(this) {};
+        final DisabledFacet disabledFacet = disabledFacet();
+        final TypeOfFacet typeOfFacet = new TypeOfFacetAbstract(getSpecification().getCorrespondingClass(), this, objectMemberContext.getSpecificationLookup()) {}; 
+        
         FacetUtil.addFacet(renderFacet);
         FacetUtil.addFacet(notPersistedFacet);
+        FacetUtil.addFacet(disabledFacet);
         FacetUtil.addFacet(typeOfFacet);
         
         // calculate the identifier
@@ -87,7 +90,17 @@ public class OneToManyAssociationContributee extends OneToManyAssociationImpl im
         identifier = Identifier.actionIdentifier(contributeeType.getCorrespondingClass().getName(), memberName, memberParameterNames);
     }
 
-    
+    private DisabledFacet disabledFacet() {
+        final DisabledFacet originalFacet = facetHolder.getFacet(DisabledFacet.class);
+        if( originalFacet != null && 
+            originalFacet.when() == When.ALWAYS && 
+            originalFacet.where() == Where.ANYWHERE) {
+            return originalFacet;
+        }
+        // ensure that the contributed association is always disabled
+        return new DisabledFacetImpl(When.ALWAYS, Where.ANYWHERE, "Contributed collection", this);
+    }
+
     @Override
     public ObjectAdapter get(final ObjectAdapter ownerAdapter) {
         return objectAction.execute(serviceAdapter, new ObjectAdapter[]{ownerAdapter});

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationContributee.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationContributee.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationContributee.java
index 5d21f60..1d1ec01 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationContributee.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationContributee.java
@@ -19,6 +19,8 @@ package org.apache.isis.core.metamodel.specloader.specimpl;
 import java.util.List;
 
 import org.apache.isis.applib.Identifier;
+import org.apache.isis.applib.annotation.When;
+import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.filter.Filter;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 import org.apache.isis.core.metamodel.facetapi.Facet;
@@ -31,13 +33,14 @@ import org.apache.isis.core.metamodel.facets.notpersisted.NotPersistedFacetAbstr
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMemberContext;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacet;
+import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacetImpl;
 
 public class OneToOneAssociationContributee extends OneToOneAssociationImpl implements ContributeeMember {
 
     private final ObjectAdapter serviceAdapter;
     private final ObjectAction objectAction;
     
-    private final NotPersistedFacet notPersistedFacet;
 
     /**
      * Hold facets rather than delegate to the contributed action (different types might
@@ -49,27 +52,41 @@ public class OneToOneAssociationContributee extends OneToOneAssociationImpl impl
 
     public OneToOneAssociationContributee(
             final ObjectAdapter serviceAdapter, 
-            final ObjectActionImpl servceAction, 
+            final ObjectActionImpl serviceAction, 
             final ObjectSpecification contributeeType,
             final ObjectMemberContext objectMemberContext) {
-        super(servceAction.getFacetedMethod(), servceAction.getReturnType(), objectMemberContext);
+        super(serviceAction.getFacetedMethod(), serviceAction.getReturnType(), objectMemberContext);
         this.serviceAdapter = serviceAdapter;
-        this.objectAction = servceAction;
+        this.objectAction = serviceAction;
         
-        notPersistedFacet = new NotPersistedFacetAbstract(this) {};
-
         // copy over facets from contributed to own.
-        FacetUtil.copyFacets(servceAction.getFacetedMethod(), facetHolder);
+        FacetUtil.copyFacets(serviceAction.getFacetedMethod(), facetHolder);
+        
+        final NotPersistedFacet notPersistedFacet = new NotPersistedFacetAbstract(this) {};
+        final DisabledFacet disabledFacet = disabledFacet();
+        
         FacetUtil.addFacet(notPersistedFacet);
+        FacetUtil.addFacet(disabledFacet);
         
         // calculate the identifier
-        final Identifier contributorIdentifier = servceAction.getFacetedMethod().getIdentifier();
+        final Identifier contributorIdentifier = serviceAction.getFacetedMethod().getIdentifier();
         final String memberName = contributorIdentifier.getMemberName();
         List<String> memberParameterNames = contributorIdentifier.getMemberParameterNames();
         
         identifier = Identifier.actionIdentifier(contributeeType.getCorrespondingClass().getName(), memberName, memberParameterNames);
     }
 
+    private DisabledFacet disabledFacet() {
+        final DisabledFacet originalFacet = facetHolder.getFacet(DisabledFacet.class);
+        if( originalFacet != null && 
+            originalFacet.when() == When.ALWAYS && 
+            originalFacet.where() == Where.ANYWHERE) {
+            return originalFacet;
+        }
+        // ensure that the contributed association is always disabled
+        return new DisabledFacetImpl(When.ALWAYS, Where.ANYWHERE, "Contributed property", this);
+    }
+
     @Override
     public ObjectAdapter get(final ObjectAdapter ownerAdapter) {
         return objectAction.execute(serviceAdapter, new ObjectAdapter[]{ownerAdapter});

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/DisabledFacetImpl.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/DisabledFacetImpl.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/DisabledFacetImpl.java
index 4425d36..225aee1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/DisabledFacetImpl.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/DisabledFacetImpl.java
@@ -19,6 +19,8 @@
 
 package org.apache.isis.core.progmodel.facets.members.disabled;
 
+import com.google.common.base.Strings;
+
 import org.apache.isis.applib.annotation.When;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
@@ -26,14 +28,21 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 
 public class DisabledFacetImpl extends DisabledFacetAbstract {
 
-    public DisabledFacetImpl(final When when, Where where, final FacetHolder holder) {
+    private final String reason;
+
+    public DisabledFacetImpl(final When when, final Where where, final FacetHolder holder) {
+        this(when, where, null, holder);
+    }
+
+    public DisabledFacetImpl(final When when, final Where where, final String reason, final FacetHolder holder) {
         super(when, where, holder);
+        this.reason = reason;
     }
 
     @Override
     public String disabledReason(final ObjectAdapter targetAdapter) {
         if (when() == When.ALWAYS) {
-            return "Always disabled";
+            return disabledReasonElse("Always disabled");
         } else if (when() == When.NEVER) {
             return null;
         }
@@ -44,11 +53,15 @@ public class DisabledFacetImpl extends DisabledFacetAbstract {
         }
 
         if (when() == When.UNTIL_PERSISTED) {
-            return targetAdapter.isTransient() ? "Disabled until persisted" : null;
+            return targetAdapter.isTransient() ? disabledReasonElse("Disabled until persisted") : null;
         } else if (when() == When.ONCE_PERSISTED) {
-            return targetAdapter.representsPersistent() ? "Disabled once persisted" : null;
+            return targetAdapter.representsPersistent() ? disabledReasonElse("Disabled once persisted") : null;
         }
         return null;
     }
 
+    private String disabledReasonElse(final String defaultReason) {
+        return !Strings.isNullOrEmpty(reason) ? reason : defaultReason;
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledAnnotationFacetFactory.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledAnnotationFacetFactory.java
index d387f31..ff13a12 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledAnnotationFacetFactory.java
@@ -40,7 +40,7 @@ public class DisabledAnnotationFacetFactory extends FacetFactoryAbstract {
     }
 
     private DisabledFacet create(final Disabled annotation, final FacetHolder holder) {
-        return annotation == null ? null : new DisabledFacetAnnotation(annotation.when(), annotation.where(), holder);
+        return annotation == null ? null : new DisabledFacetAnnotation(annotation.when(), annotation.where(), annotation.reason(), holder);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledFacetAnnotation.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledFacetAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledFacetAnnotation.java
index 1dd9353..03a929c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledFacetAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/progmodel/facets/members/disabled/annotation/DisabledFacetAnnotation.java
@@ -26,8 +26,8 @@ import org.apache.isis.core.progmodel.facets.members.disabled.DisabledFacetImpl;
 
 public class DisabledFacetAnnotation extends DisabledFacetImpl {
 
-    public DisabledFacetAnnotation(final When when, Where where, final FacetHolder holder) {
-        super(when, where, holder);
+    public DisabledFacetAnnotation(final When when, Where where, String reason, final FacetHolder holder) {
+        super(when, where, reason, holder);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/core/metamodel/src/test/java/org/apache/isis/core/progmodel/facets/disabled/DisabledAnnotationFacetFactoryTest.java
----------------------------------------------------------------------
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/progmodel/facets/disabled/DisabledAnnotationFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/core/progmodel/facets/disabled/DisabledAnnotationFacetFactoryTest.java
index 7156647..1e7ab80 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/progmodel/facets/disabled/DisabledAnnotationFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/progmodel/facets/disabled/DisabledAnnotationFacetFactoryTest.java
@@ -19,6 +19,9 @@
 
 package org.apache.isis.core.progmodel.facets.disabled;
 
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertThat;
+
 import java.lang.reflect.Method;
 import java.util.Collection;
 
@@ -64,6 +67,9 @@ public class DisabledAnnotationFacetFactoryTest extends AbstractFacetFactoryTest
         assertNotNull(facet);
         assertTrue(facet instanceof DisabledFacetAbstract);
 
+        final DisabledFacet disabledFacet = (DisabledFacet) facet;
+        assertThat(disabledFacet.disabledReason(null), is("Always disabled"));
+        
         assertNoMethodsRemoved();
     }
 
@@ -82,6 +88,9 @@ public class DisabledAnnotationFacetFactoryTest extends AbstractFacetFactoryTest
         assertNotNull(facet);
         assertTrue(facet instanceof DisabledFacetAbstract);
 
+        final DisabledFacet disabledFacet = (DisabledFacet) facet;
+        assertThat(disabledFacet.disabledReason(null), is("Always disabled"));
+
         assertNoMethodsRemoved();
     }
 
@@ -102,6 +111,27 @@ public class DisabledAnnotationFacetFactoryTest extends AbstractFacetFactoryTest
         assertNoMethodsRemoved();
     }
 
+    public void testDisabledAnnotationWithReason() {
+        class Customer {
+            @Disabled(reason="Oh no you don't!")
+            public int getNumberOfOrders() {
+                return 0;
+            }
+        }
+        final Method actionMethod = findMethod(Customer.class, "getNumberOfOrders");
+
+        facetFactory.process(new ProcessMethodContext(Customer.class, null, null, actionMethod, methodRemover, facetedMethod));
+
+        final Facet facet = facetedMethod.getFacet(DisabledFacet.class);
+        assertNotNull(facet);
+        assertTrue(facet instanceof DisabledFacetAbstract);
+
+        final DisabledFacet disabledFacet = (DisabledFacet) facet;
+        assertThat(disabledFacet.disabledReason(null), is("Oh no you don't!"));
+        
+        assertNoMethodsRemoved();
+    }
+
     public void testDisabledWhenAlwaysAnnotationPickedUpOn() {
         class Customer {
             @Disabled(when = When.ALWAYS)
@@ -115,6 +145,9 @@ public class DisabledAnnotationFacetFactoryTest extends AbstractFacetFactoryTest
         final Facet facet = facetedMethod.getFacet(DisabledFacet.class);
         final DisabledFacetAbstract disabledFacetAbstract = (DisabledFacetAbstract) facet;
 
+        final DisabledFacet disabledFacet = (DisabledFacet) facet;
+        assertThat(disabledFacet.disabledReason(null), is("Always disabled"));
+
         assertEquals(When.ALWAYS, disabledFacetAbstract.when());
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
index 0d00408..58f306f 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItem.java
@@ -213,7 +213,7 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     private Category category;
 
     @javax.jdo.annotations.Column(allowsNull="false")
-    @Disabled
+    @Disabled(reason="Use action to update both category and subcategory")
     public Category getCategory() {
         return category;
     }
@@ -227,7 +227,7 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     private Subcategory subcategory;
 
     @javax.jdo.annotations.Column(allowsNull="false")
-    @Disabled
+    @Disabled(reason="Use action to update both category and subcategory")
     public Subcategory getSubcategory() {
         return subcategory;
     }
@@ -301,25 +301,32 @@ public class ToDoItem implements Comparable<ToDoItem> /*, Locatable*/ { // GMAP3
     private BigDecimal cost;
 
     @javax.jdo.annotations.Column(allowsNull="true", scale=2)
+    @Disabled(reason="Update using action")
     public BigDecimal getCost() {
         return cost;
     }
 
     public void setCost(final BigDecimal cost) {
-        this.cost = cost;
+        this.cost = cost!=null?cost.setScale(2):null;
     }
     
     @Named("Update")
-    public ToDoItem updateCost(@Named("New cost") final BigDecimal cost) {
+    public ToDoItem updateCost(@Named("New cost") @Optional final BigDecimal cost) {
         LOG.debug("%s: cost updated: %s -> %s", this.container.titleOf(this), getCost(), cost);
         setCost(cost);
         return this;
     }
 
-    // provide a default value
+    // provide a default value for argument #0
     public BigDecimal default0UpdateCost() {
         return getCost();
     }
+    
+    // validate action arguments
+    public String validateUpdateCost(final BigDecimal proposedCost) {
+        if(proposedCost == null) { return null; }
+        return proposedCost.compareTo(BigDecimal.ZERO) < 0? "Cost must be positive": null;
+    }
 
     // //////////////////////////////////////
     // Notes (property)

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
index 75531c5..c0c96d0 100644
--- a/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
+++ b/example/application/quickstart_wicket_restful_jdo/dom/src/main/java/dom/todo/ToDoItemContributions.java
@@ -36,6 +36,7 @@ import org.apache.isis.applib.AbstractFactoryAndRepository;
 import org.apache.isis.applib.annotation.ActionSemantics;
 import org.apache.isis.applib.annotation.ActionSemantics.Of;
 import org.apache.isis.applib.annotation.DescribedAs;
+import org.apache.isis.applib.annotation.Disabled;
 import org.apache.isis.applib.annotation.Hidden;
 import org.apache.isis.applib.annotation.Named;
 import org.apache.isis.applib.annotation.NotContributed;
@@ -56,6 +57,7 @@ public class ToDoItemContributions extends AbstractFactoryAndRepository {
     @ActionSemantics(Of.SAFE)
     @NotContributed(As.ACTION)
     @Hidden(where=Where.ALL_TABLES)
+    @Disabled(reason="Relative priority, derived from due date")
     public Integer priority(final ToDoItem toDoItem) {
         if(toDoItem.isComplete()) {
             return null;

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemTest_duplicate.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemTest_duplicate.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemTest_duplicate.java
index c280aaa..3f85fb1 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemTest_duplicate.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/actions/ToDoItemTest_duplicate.java
@@ -54,7 +54,7 @@ public class ToDoItemTest_duplicate extends ToDoIntegTest {
         // given
         final LocalDate todaysDate = Clock.getTimeAsLocalDate();
         toDoItem.setDueBy(todaysDate);
-        toDoItem.setCost(new BigDecimal("123.45"));
+        toDoItem.updateCost(new BigDecimal("123.45"));
         
         duplicateToDoItem = toDoItem.duplicate(
                 unwrap(toDoItem).default0Duplicate(), 

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemContributionsTest_priority.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemContributionsTest_priority.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemContributionsTest_priority.java
index 9df9784..8fba902 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemContributionsTest_priority.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemContributionsTest_priority.java
@@ -43,7 +43,7 @@ public class ToDoItemContributionsTest_priority extends ToDoIntegTest {
         scenarioExecution().install(new ToDoItemsFixture());
 
         final ToDoItems toDoItems = wrap(service(ToDoItems.class));
-        toDoItemContributions = wrap(service(ToDoItemContributions.class));
+        toDoItemContributions = service(ToDoItemContributions.class);
         notYetComplete = toDoItems.notYetComplete();
     }
 

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_category.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_category.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_category.java
index 119b2e9..0c12ce7 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_category.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_category.java
@@ -47,9 +47,7 @@ public class ToDoItemTest_category extends ToDoIntegTest {
     public void cannotModify() throws Exception {
         
         // when, then
-        expectedExceptions.expectMessage(containsString("Always disabled"));
+        expectedExceptions.expectMessage(containsString("Reason: Use action to update both category and subcategory."));
         toDoItem.setCategory(Category.Professional);
     }
-
-
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_cost.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_cost.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_cost.java
index 664d7a3..ebc7ce2 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_cost.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_cost.java
@@ -53,7 +53,7 @@ public class ToDoItemTest_cost extends ToDoIntegTest {
         final BigDecimal newCost = new BigDecimal("123.45");
         
         // when
-        toDoItem.setCost(newCost);
+        toDoItem.updateCost(newCost);
         
         // then
         assertThat(toDoItem.getCost(), is(newCost));
@@ -75,7 +75,7 @@ public class ToDoItemTest_cost extends ToDoIntegTest {
     public void canBeNull() throws Exception {
         
         // when
-        toDoItem.setCost((BigDecimal)null);
+        toDoItem.updateCost((BigDecimal)null);
         
         // then
         assertThat(toDoItem.getCost(), is((BigDecimal)null));

http://git-wip-us.apache.org/repos/asf/isis/blob/6490b19a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_subcategory.java
----------------------------------------------------------------------
diff --git a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_subcategory.java b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_subcategory.java
index 2df8358..c8142bf 100644
--- a/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_subcategory.java
+++ b/example/application/quickstart_wicket_restful_jdo/integtests/src/test/java/integration/tests/props/ToDoItemTest_subcategory.java
@@ -47,9 +47,7 @@ public class ToDoItemTest_subcategory extends ToDoIntegTest {
     public void cannotModify() throws Exception {
         
         // when, then
-        expectedExceptions.expectMessage(containsString("Always disabled"));
+        expectedExceptions.expectMessage(containsString("Reason: Use action to update both category and subcategory."));
         toDoItem.setSubcategory(Subcategory.Chores);
     }
-
-
-}
\ No newline at end of file
+}