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 2020/08/21 07:49:10 UTC

[isis] 02/02: ISIS-2222: wip for @DomainObject#publishing (demo now works, just docs to tidy up).

This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/isis.git

commit f16da7fe6714cdf516fb9e84b366932569ed0337
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Aug 21 08:24:43 2020 +0100

    ISIS-2222: wip for @DomainObject#publishing (demo now works, just docs to tidy up).
---
 .../demoapp/dom/_infra/samples/NameSamples.java    |  12 +++
 .../ActionPublishingJdo-description.adoc           |   7 +-
 .../annotDomain/DomainObject/DomainObjectMenu.java |  12 ++-
 ...ainObjectPublishingDisabledJdo-description.adoc |   1 +
 ...java => DomainObjectPublishingDisabledJdo.java} |  52 +++--------
 ...> DomainObjectPublishingDisabledJdo.layout.xml} |   8 +-
 ...DomainObjectPublishingDisabledJdoEntities.java} |  16 ++--
 ...ainObjectPublishingDisabledJdoSeedService.java} |  10 +--
 ...mainObjectPublishingEnabledJdo-description.adoc |   1 +
 ....java => DomainObjectPublishingEnabledJdo.java} |  48 +++-------
 ...=> DomainObjectPublishingEnabledJdo.layout.xml} |   8 +-
 .../DomainObjectPublishingEnabledJdoEntities.java  |  40 +++++++++
 ...mainObjectPublishingEnabledJdoSeedService.java} |   6 +-
 .../DomainObjectPublishingJdo-description.adoc     |  74 ---------------
 .../publishing/DomainObjectPublishingJdo.java      |  63 +++----------
 ...ectPublishingJdo_updatePropertyUsingAction.java |  51 +++++++++++
 .../DomainObjectPublishingVm-description.adoc      | 100 +++++++++++++++++++++
 .../publishing/DomainObjectPublishingVm.java       |  57 ++++++++++++
 ...out.xml => DomainObjectPublishingVm.layout.xml} |  13 ++-
 .../DomainObjectPublishingVm_create.java           |  43 +++++++++
 .../DomainObjectPublishingVm_delete.java           |  41 +++++++++
 ...ectPublishingVm_publishingDisabledEntities.java |  24 +++++
 ...jectPublishingVm_publishingEnabledEntities.java |  24 +++++
 .../DomainObjectPublishingVm_updateAll.java        |  48 ++++++++++
 ...nObjectPublishingVm_clearPublishedObjects.java} |  15 ++--
 ...DomainObjectPublishingVm_publishedObjects.java} |  11 +--
 .../PropertyPublishingJdo-description.adoc         |   8 +-
 27 files changed, 534 insertions(+), 259 deletions(-)

diff --git a/examples/demo/domain/src/main/java/demoapp/dom/_infra/samples/NameSamples.java b/examples/demo/domain/src/main/java/demoapp/dom/_infra/samples/NameSamples.java
index 0d69bc5..3ef1de1 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/_infra/samples/NameSamples.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/_infra/samples/NameSamples.java
@@ -18,12 +18,18 @@
  */
 package demoapp.dom._infra.samples;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
 import javax.inject.Named;
 
 import org.springframework.stereotype.Service;
 
+import lombok.val;
+
 import demoapp.dom.types.Samples;
 
 @Service
@@ -38,4 +44,10 @@ public class NameSamples implements Samples<String> {
         );
     }
 
+    public String random() {
+        val names = new ArrayList<String>();
+        stream().forEach(names::add);
+        Collections.shuffle(names);
+        return names.stream().findFirst().orElse(null);
+    }
 }
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo-description.adoc
index dfe075d..8071721 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Action/publishing/ActionPublishingJdo-description.adoc
@@ -2,12 +2,13 @@ The `publishing` semantic specifies that the invocation of an object action shou
 This is performed _after_ the action has been invoked.
 
 The publishing from the framework to the SPI is in-memory.
-A typical SPI implementation would then publish over the network, or perhaps store in a database as per the link:https://microservices.io/patterns/data/transactional-outbox.html[outbox pattern].
-
-TIP: The framework provides an link:https://isis.apache.org/mappings/2.0.0-M3/outbox-publisher/about.html[out-of-the-box implementation] of the outbox pattern.
+A typical SPI implementation would then publish over the network, or perhaps store in a database.
+(Note that the framework provides an link:https://isis.apache.org/mappings/2.0.0-M3/outbox-publisher/about.html[out-of-the-box implementation] of the link:https://microservices.io/patterns/data/transactional-outbox.html[outbox pattern]).
 
 The semantic can be specified using either the `@Action` annotation, or through a meta-annotation.
 
+NOTE: The demo shows publishing of entities, as this is much more common use case than publishing a view model.
+
 == Annotated
 
 The `publisher` semantic can be specified explicitly using an annotation through `@Action#publishing()`:
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/DomainObjectMenu.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/DomainObjectMenu.java
index 8df34bc..58099a2 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/DomainObjectMenu.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/DomainObjectMenu.java
@@ -28,8 +28,9 @@ import org.apache.isis.applib.annotation.SemanticsOf;
 
 import lombok.extern.log4j.Log4j2;
 
-import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingJdo;
-import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingJdoEntities;
+import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingEnabledJdo;
+import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingEnabledJdoEntities;
+import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingVm;
 
 @DomainService(nature=NatureOfService.VIEW, objectType = "demo.DomainObjectMenu")
 @Log4j2
@@ -37,11 +38,8 @@ public class DomainObjectMenu {
 
     @Action(semantics = SemanticsOf.SAFE)
     @ActionLayout(cssClassFa="fa-book", describedAs = "Object changed events as XML")
-    public DomainObjectPublishingJdo publishing(){
-        return domainObjectPublishingJdoEntities.first();
+    public DomainObjectPublishingVm publishing(){
+        return new DomainObjectPublishingVm();
     }
 
-    @Inject
-    DomainObjectPublishingJdoEntities domainObjectPublishingJdoEntities;
-
 }
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo-description.adoc
new file mode 100644
index 0000000..d5b090d
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo-description.adoc
@@ -0,0 +1 @@
+CAUTION: TODO
\ No newline at end of file
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.java
similarity index 61%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.java
index eecb228..7b3d486 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.java
@@ -18,29 +18,22 @@
  */
 package demoapp.dom.annotDomain.DomainObject.publishing;
 
-import java.net.URI;
-
-import javax.inject.Inject;
 import javax.jdo.annotations.DatastoreIdentity;
 import javax.jdo.annotations.IdGeneratorStrategy;
 import javax.jdo.annotations.IdentityType;
 import javax.jdo.annotations.PersistenceCapable;
-import javax.xml.bind.annotation.XmlElement;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.Bounding;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.PropertyLayout;
 import org.apache.isis.applib.annotation.Publishing;
-import org.apache.isis.applib.annotation.Redirect;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.applib.services.linking.DeepLinkService;
-import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.annotation.Title;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -52,48 +45,31 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
 @DatastoreIdentity(strategy = IdGeneratorStrategy.IDENTITY, column = "id")
 @DomainObject(
         nature=Nature.JDO_ENTITY
-        , objectType = "demo.DomainObjectPublishingJdo"
-        , editing = Editing.ENABLED
-        , publishing = Publishing.ENABLED          // <.>
+        , objectType = "demo.DomainObjectPublishingDisabledJdo"
+        , publishing = Publishing.DISABLED          // <.>
+        , bounding = Bounding.BOUNDED
 )
 @DomainObjectLayout(
         describedAs =
-                "@DomainObject(publishing=ENABLED)"
+                "@DomainObject(publishing=DISABLED)"
 )
-public class DomainObjectPublishingJdo implements HasAsciiDocDescription {
+public class DomainObjectPublishingDisabledJdo implements DomainObjectPublishingJdo {
     // ...
 //end::class[]
 
-    public DomainObjectPublishingJdo(String initialValue) {
+    public DomainObjectPublishingDisabledJdo(String initialValue) {
         this.property = initialValue;
+        this.propertyUpdatedByAction = initialValue;
     }
 
-    public String title() {
-        return "DomainObject#publishing";
-    }
-
-//tag::property[]
-    @Property()
-    @MemberOrder(name = "general", sequence = "1")
+//tag::class[]
+    @Title(sequence = "1.0")
     @Getter @Setter
     private String property;
-//end::property[]
 
-//tag::action[]
-    @Action(
-        semantics = SemanticsOf.IDEMPOTENT
-        , associateWith = "property"
-    )
-    @MemberOrder(name = "annotation", sequence = "1")
-    public DomainObjectPublishingJdo updateProperty(final String value) {
-        setProperty(value);
-        return this;
-    }
-    public String default0UpdateProperty() {
-        return getProperty();
-    }
-//end::action[]
+    @Getter @Setter
+    @Title(sequence = "2.0", prepend = " / ")
+    private String propertyUpdatedByAction;
 
-//tag::class[]
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.layout.xml
similarity index 91%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.layout.xml
index cc21592..0e97d84 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdo.layout.xml
@@ -19,12 +19,8 @@
 		<bs3:col span="6">
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:fieldSet name="General" id="general"/>
-				</bs3:col>
-			</bs3:row>
-			<bs3:row>
-				<bs3:col span="12">
-					<cpt:collection id="publishedObjects"/>
+					<cpt:fieldSet name="Property edits" id="property"/>
+					<cpt:fieldSet name="Action invocations" id="action"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoEntities.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoEntities.java
similarity index 53%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoEntities.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoEntities.java
index f0194b1..d7d714b 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoEntities.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoEntities.java
@@ -11,20 +11,24 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.services.repository.RepositoryService;
 
 @Service
-public class DomainObjectPublishingJdoEntities {
+public class DomainObjectPublishingDisabledJdoEntities {
 
-    public Optional<DomainObjectPublishingJdo> find(final String value) {
-        return repositoryService.firstMatch(DomainObjectPublishingJdo.class, x -> Objects.equals(x.getProperty(), value));
+    public Optional<DomainObjectPublishingDisabledJdo> find(final String value) {
+        return repositoryService.firstMatch(DomainObjectPublishingDisabledJdo.class, x -> Objects.equals(x.getProperty(), value));
     }
 
-    public List<DomainObjectPublishingJdo> all() {
-        return repositoryService.allInstances(DomainObjectPublishingJdo.class);
+    public List<DomainObjectPublishingDisabledJdo> all() {
+        return repositoryService.allInstances(DomainObjectPublishingDisabledJdo.class);
     }
 
-    public DomainObjectPublishingJdo first() {
+    public DomainObjectPublishingDisabledJdo first() {
         return all().stream().findFirst().get();
     }
 
+    public void remove(DomainObjectPublishingDisabledJdo disabledJdo) {
+        repositoryService.removeAndFlush(disabledJdo);
+    }
+
     @Inject
     RepositoryService repositoryService;
 
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoSeedService.java
similarity index 70%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoSeedService.java
index 27ef179..34b0fe9 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingDisabledJdoSeedService.java
@@ -11,18 +11,18 @@ import demoapp.dom._infra.seed.SeedServiceAbstract;
 import demoapp.dom.types.Samples;
 
 @Service
-public class DomainObjectPublishingJdoSeedService extends SeedServiceAbstract {
+public class DomainObjectPublishingDisabledJdoSeedService extends SeedServiceAbstract {
 
-    public DomainObjectPublishingJdoSeedService() {
-        super(PropertyPublishingJdoEntityFixture::new);
+    public DomainObjectPublishingDisabledJdoSeedService() {
+        super(PropertyPublishingNotJdoEntityFixture::new);
     }
 
-    static class PropertyPublishingJdoEntityFixture extends FixtureScript {
+    static class PropertyPublishingNotJdoEntityFixture extends FixtureScript {
 
         @Override
         protected void execute(ExecutionContext executionContext) {
             samples.stream()
-                    .map(DomainObjectPublishingJdo::new)
+                    .map(DomainObjectPublishingDisabledJdo::new)
                     .forEach(domainObject -> {
                         repositoryService.persist(domainObject);
                         executionContext.addResult(this, domainObject);
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo-description.adoc
new file mode 100644
index 0000000..d5b090d
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo-description.adoc
@@ -0,0 +1 @@
+CAUTION: TODO
\ No newline at end of file
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.java
similarity index 64%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.java
index eecb228..0e8c341 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.java
@@ -18,29 +18,22 @@
  */
 package demoapp.dom.annotDomain.DomainObject.publishing;
 
-import java.net.URI;
-
-import javax.inject.Inject;
 import javax.jdo.annotations.DatastoreIdentity;
 import javax.jdo.annotations.IdGeneratorStrategy;
 import javax.jdo.annotations.IdentityType;
 import javax.jdo.annotations.PersistenceCapable;
-import javax.xml.bind.annotation.XmlElement;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.Bounding;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.PropertyLayout;
 import org.apache.isis.applib.annotation.Publishing;
-import org.apache.isis.applib.annotation.Redirect;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.applib.services.linking.DeepLinkService;
-import org.apache.isis.applib.services.message.MessageService;
+import org.apache.isis.applib.annotation.Title;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -52,48 +45,31 @@ import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
 @DatastoreIdentity(strategy = IdGeneratorStrategy.IDENTITY, column = "id")
 @DomainObject(
         nature=Nature.JDO_ENTITY
-        , objectType = "demo.DomainObjectPublishingJdo"
-        , editing = Editing.ENABLED
+        , objectType = "demo.DomainObjectPublishingEnabledJdo"
         , publishing = Publishing.ENABLED          // <.>
+        , bounding = Bounding.BOUNDED
 )
 @DomainObjectLayout(
         describedAs =
                 "@DomainObject(publishing=ENABLED)"
 )
-public class DomainObjectPublishingJdo implements HasAsciiDocDescription {
+public class DomainObjectPublishingEnabledJdo implements DomainObjectPublishingJdo {
     // ...
 //end::class[]
 
-    public DomainObjectPublishingJdo(String initialValue) {
+    public DomainObjectPublishingEnabledJdo(String initialValue) {
         this.property = initialValue;
+        this.propertyUpdatedByAction = initialValue;
     }
 
-    public String title() {
-        return "DomainObject#publishing";
-    }
-
-//tag::property[]
-    @Property()
-    @MemberOrder(name = "general", sequence = "1")
+//tag::class[]
+    @Title(sequence = "1.0")
     @Getter @Setter
     private String property;
-//end::property[]
 
-//tag::action[]
-    @Action(
-        semantics = SemanticsOf.IDEMPOTENT
-        , associateWith = "property"
-    )
-    @MemberOrder(name = "annotation", sequence = "1")
-    public DomainObjectPublishingJdo updateProperty(final String value) {
-        setProperty(value);
-        return this;
-    }
-    public String default0UpdateProperty() {
-        return getProperty();
-    }
-//end::action[]
+    @Getter @Setter
+    @Title(sequence = "2.0", prepend = " / ")
+    private String propertyUpdatedByAction;
 
-//tag::class[]
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.layout.xml
similarity index 91%
copy from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
copy to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.layout.xml
index cc21592..0e97d84 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdo.layout.xml
@@ -19,12 +19,8 @@
 		<bs3:col span="6">
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:fieldSet name="General" id="general"/>
-				</bs3:col>
-			</bs3:row>
-			<bs3:row>
-				<bs3:col span="12">
-					<cpt:collection id="publishedObjects"/>
+					<cpt:fieldSet name="Property edits" id="property"/>
+					<cpt:fieldSet name="Action invocations" id="action"/>
 				</bs3:col>
 			</bs3:row>
 			<bs3:row>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoEntities.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoEntities.java
new file mode 100644
index 0000000..f224f69
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoEntities.java
@@ -0,0 +1,40 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import javax.inject.Inject;
+
+import org.springframework.stereotype.Service;
+
+import org.apache.isis.applib.services.repository.RepositoryService;
+
+@Service
+public class DomainObjectPublishingEnabledJdoEntities {
+
+    public Optional<DomainObjectPublishingEnabledJdo> find(final String value) {
+        return repositoryService.firstMatch(DomainObjectPublishingEnabledJdo.class, x -> Objects.equals(x.getProperty(), value));
+    }
+
+    public List<DomainObjectPublishingEnabledJdo> all() {
+        return repositoryService.allInstances(DomainObjectPublishingEnabledJdo.class);
+    }
+
+    public DomainObjectPublishingEnabledJdo first() {
+        return all().stream().findFirst().get();
+    }
+
+    public DomainObjectPublishingEnabledJdo cloneAndPersist(DomainObjectPublishingEnabledJdo original) {
+        return repositoryService.persistAndFlush(
+                new DomainObjectPublishingEnabledJdo(original.getProperty()));
+    }
+
+    public void remove(DomainObjectPublishingEnabledJdo enabledJdo) {
+        repositoryService.removeAndFlush(enabledJdo);
+    }
+
+    @Inject
+    RepositoryService repositoryService;
+
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoSeedService.java
similarity index 82%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoSeedService.java
index 27ef179..3880748 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdoSeedService.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingEnabledJdoSeedService.java
@@ -11,9 +11,9 @@ import demoapp.dom._infra.seed.SeedServiceAbstract;
 import demoapp.dom.types.Samples;
 
 @Service
-public class DomainObjectPublishingJdoSeedService extends SeedServiceAbstract {
+public class DomainObjectPublishingEnabledJdoSeedService extends SeedServiceAbstract {
 
-    public DomainObjectPublishingJdoSeedService() {
+    public DomainObjectPublishingEnabledJdoSeedService() {
         super(PropertyPublishingJdoEntityFixture::new);
     }
 
@@ -22,7 +22,7 @@ public class DomainObjectPublishingJdoSeedService extends SeedServiceAbstract {
         @Override
         protected void execute(ExecutionContext executionContext) {
             samples.stream()
-                    .map(DomainObjectPublishingJdo::new)
+                    .map(DomainObjectPublishingEnabledJdo::new)
                     .forEach(domainObject -> {
                         repositoryService.persist(domainObject);
                         executionContext.addResult(this, domainObject);
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo-description.adoc
deleted file mode 100644
index c62d177..0000000
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo-description.adoc
+++ /dev/null
@@ -1,74 +0,0 @@
-CAUTION: todo - to update.
-
-//The `editing` semantic specifies that a property's value can be changed through the UI:
-//
-//* for properties, the semantic can be specified using either the `@Property` annotation, or a meta-annotation
-//
-//There is no corresponding semantic for parameters, parameters are implicitly editable.
-//
-//== Class Level
-//
-//Usually editing of properties is discouraged; it is usually better to modify state through an explicit action instead.
-//For that reason, editing of properties is disabled by default (though that can be changed globally if necessary using the `isis.applib.annotation.domain-object.editing` configuration property).
-//
-//Editing can also be specified at the class level.
-//This will override any configured defaults, but just for the properties of that class:
-//
-//[source,java,indent=0]
-//----
-//include::PropertyEditingVm.java[tags=class]
-//----
-//
-//The property-level semantic can, in turn, overrides the configured or class-level default.
-//
-//
-//== Annotated
-//
-//The `editing` semantic can be specified explicitly using an annotation:
-//
-//* for properties, using `@Property#editing()`:
-//+
-//[source,java,indent=0]
-//----
-//include::PropertyEditingVm.java[tags=annotation]
-//----
-//<.> explicitly specifies the maximum length that can be entered for the property
-//
-//The annotation could also be applied to a mixin, but would have little effect because mixin properties are always read-only.
-//
-//== Meta-annotated
-//
-//The `editing` semantic can also be specified using a custom meta-annotation:
-//
-//* the meta-annotation is defined as:
-//+
-//[source,java]
-//----
-//include::EditingEnabledMetaAnnotation.java[tags=class]
-//----
-//<.> annotated for a property
-//<.> annotation can be applied to a property (either its getter or the field directly)
-//
-//* and can be applied to a property:
-//+
-//[source,java,indent=0]
-//----
-//include::PropertyEditingVm.java[tags=meta-annotated]
-//----
-//<.> semantic is inherited from the meta-annotation
-//
-//
-//
-//=== Meta-annotated Overridden
-//
-//The meta-annotation can itself be overridden:
-//
-//* in a property:
-//+
-//[source,java,indent=0]
-//----
-//include::PropertyEditingVm.java[tags=meta-annotated-overridden]
-//----
-//<.> semantic from meta-annotation ...
-//<.> \... is overridden by the `@Property` annotation
-//
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
index eecb228..7c3650c 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.java
@@ -18,29 +18,21 @@
  */
 package demoapp.dom.annotDomain.DomainObject.publishing;
 
-import java.net.URI;
-
-import javax.inject.Inject;
 import javax.jdo.annotations.DatastoreIdentity;
 import javax.jdo.annotations.IdGeneratorStrategy;
 import javax.jdo.annotations.IdentityType;
 import javax.jdo.annotations.PersistenceCapable;
-import javax.xml.bind.annotation.XmlElement;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.Bounding;
 import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.applib.annotation.DomainObjectLayout;
 import org.apache.isis.applib.annotation.Editing;
 import org.apache.isis.applib.annotation.MemberOrder;
 import org.apache.isis.applib.annotation.Nature;
 import org.apache.isis.applib.annotation.Property;
-import org.apache.isis.applib.annotation.PropertyLayout;
 import org.apache.isis.applib.annotation.Publishing;
-import org.apache.isis.applib.annotation.Redirect;
 import org.apache.isis.applib.annotation.SemanticsOf;
-import org.apache.isis.applib.services.linking.DeepLinkService;
-import org.apache.isis.applib.services.message.MessageService;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -48,52 +40,17 @@ import lombok.Setter;
 import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
 
 //tag::class[]
-@PersistenceCapable(identityType = IdentityType.DATASTORE, schema = "demo")
-@DatastoreIdentity(strategy = IdGeneratorStrategy.IDENTITY, column = "id")
-@DomainObject(
-        nature=Nature.JDO_ENTITY
-        , objectType = "demo.DomainObjectPublishingJdo"
-        , editing = Editing.ENABLED
-        , publishing = Publishing.ENABLED          // <.>
-)
-@DomainObjectLayout(
-        describedAs =
-                "@DomainObject(publishing=ENABLED)"
-)
-public class DomainObjectPublishingJdo implements HasAsciiDocDescription {
-    // ...
-//end::class[]
-
-    public DomainObjectPublishingJdo(String initialValue) {
-        this.property = initialValue;
-    }
+public interface DomainObjectPublishingJdo extends HasAsciiDocDescription {
 
-    public String title() {
-        return "DomainObject#publishing";
-    }
+    @Property(editing = Editing.ENABLED)
+    @MemberOrder(name = "property", sequence = "1")
+    String getProperty();
+    void setProperty(String value);
 
-//tag::property[]
-    @Property()
-    @MemberOrder(name = "general", sequence = "1")
-    @Getter @Setter
-    private String property;
-//end::property[]
+    @Property(editing = Editing.DISABLED)
+    @MemberOrder(name = "action", sequence = "1")
+    String getPropertyUpdatedByAction();
+    void setPropertyUpdatedByAction(String value);
 
-//tag::action[]
-    @Action(
-        semantics = SemanticsOf.IDEMPOTENT
-        , associateWith = "property"
-    )
-    @MemberOrder(name = "annotation", sequence = "1")
-    public DomainObjectPublishingJdo updateProperty(final String value) {
-        setProperty(value);
-        return this;
-    }
-    public String default0UpdateProperty() {
-        return getProperty();
-    }
-//end::action[]
-
-//tag::class[]
 }
 //end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo_updatePropertyUsingAction.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo_updatePropertyUsingAction.java
new file mode 100644
index 0000000..de63d3a
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo_updatePropertyUsingAction.java
@@ -0,0 +1,51 @@
+/*
+ *  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 demoapp.dom.annotDomain.DomainObject.publishing;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.SemanticsOf;
+
+import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+
+//tag::class[]
+@Action(
+    semantics = SemanticsOf.IDEMPOTENT
+    , associateWith = "propertyUpdatedByAction"
+)
+public class DomainObjectPublishingJdo_updatePropertyUsingAction implements HasAsciiDocDescription {
+    // ...
+//end::class[]
+    private final DomainObjectPublishingJdo domainObjectPublishingJdo;
+
+    public DomainObjectPublishingJdo_updatePropertyUsingAction(DomainObjectPublishingJdo domainObjectPublishingJdo) {
+        this.domainObjectPublishingJdo = domainObjectPublishingJdo;
+    }
+
+//tag::class[]
+    public DomainObjectPublishingJdo_updatePropertyUsingAction updateProperty(final String value) {
+        domainObjectPublishingJdo.setPropertyUpdatedByAction(value);
+        return this;
+    }
+    public String default0UpdateProperty() {
+        return domainObjectPublishingJdo.getPropertyUpdatedByAction();
+    }
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc
new file mode 100644
index 0000000..38bc66f
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm-description.adoc
@@ -0,0 +1,100 @@
+The `publishing` semantic for a domain object means that all registered implementation(s) of link:https://isis.apache.org/refguide/2.0.0-M3/applib-svc/PublisherService.html#spi[`PublisherService` SPI] will be notified of the identity and nature of change (created/updated/deleted) of the domain object.
+This is done _after_ the interaction in which the object(s) was changed has completed.
+
+This notification is done only once per interaction, so will include _all_ domain objects that were changed.
+The event object can be converted to type xref:https://isis.apache.org/refguide/2.0.0-M3/schema/chg.html[ChangesDto].
+
+NOTE: This is only supported for domain entities, not view models.
+
+Common use cases are to replicate data to another system, or for gathering metrics (which objects are changed the most?).
+A typical SPI implementation could publish the event over the network, or perhaps store in a database.
+(Note that the framework provides an link:https://isis.apache.org/mappings/2.0.0-M3/outbox-publisher/about.html[out-of-the-box implementation] of the link:https://microservices.io/patterns/data/transactional-outbox.html[outbox pattern]).
+
+The semantic can be specified using either the `@Property` annotation, or through a meta-annotation.
+
+NOTE: The demo shows publishing of entities, as this is much more common use case than publishing a view model.
+
+CAUTION: TODO
+
+//== Annotated
+//
+//The `publisher` semantic can be specified explicitly using an annotation through `@Property#publishing()`:
+//
+//[source,java,indent=0]
+//----
+//include::PropertyPublishingJdo.java[tags=annotation]
+//----
+//<.> explicitly specifies that modifying the property should be published.
+//
+//The annotation could also be applied to a mixin, but would have little effect because mixin properties are always read-only.
+//
+//== Meta-annotated
+//
+//The `publishing` semantic can also be specified using a custom meta-annotation:
+//
+//* the meta-annotation is defined as:
+//+
+//[source,java]
+//----
+//include::PropertyPublishingEnabledMetaAnnotation.java[tags=class]
+//----
+//<.> annotated for a property
+//<.> annotation can be applied to a property (either its getter or the field directly)
+//
+//* and can be applied to a property:
+//+
+//[source,java,indent=0]
+//----
+//include::PropertyPublishingJdo.java[tags=meta-annotated]
+//----
+//<.> semantic is inherited from the meta-annotation
+//
+//
+//
+//=== Meta-annotated Overridden
+//
+//The meta-annotation can itself be overridden:
+//
+//* in a property:
+//+
+//[source,java,indent=0]
+//----
+//include::PropertyPublishingJdo.java[tags=meta-annotated-overridden]
+//----
+//<.> semantic from meta-annotation ...
+//<.> \... is overridden by the `@Property` annotation
+//
+//
+//== PublisherService
+//
+//The demo provides a simple implementation of `PublisherService` that just stores the DTOs in memory:
+//
+//[source,java]
+//----
+//include::spiimpl/PublisherServiceSpiForProperties.java[tags=class]
+//----
+//<.> serializes to `InteractionDto`, as defined by the link:https://isis.apache.org/refguide/2.0.0-M3/schema/ixn.html[Apache Isis schema].
+//
+//The demo implementation also provides a way to query these executions:
+//
+//[source,java,indent=0]
+//----
+//include::spiimpl/PublisherServiceSpiForProperties.java[tags=demo]
+//----
+//
+//Supporting mixins surface this list as contributions on the object:
+//
+//* `interactionExecutions` collection:
+//+
+//[source,java,indent=0]
+//----
+//include::spiimpl/PropertyPublishingJdo_interactionExecutions.java[tags=class]
+//----
+//
+//* `clearInteractionExecutions` action:
+//+
+//[source,java,indent=0]
+//----
+//include::spiimpl/PropertyPublishingJdo_clearInteractionExecutions.java[tags=class]
+//----
+//
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.java
new file mode 100644
index 0000000..fa3c6c0
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.java
@@ -0,0 +1,57 @@
+/*
+ *  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 demoapp.dom.annotDomain.DomainObject.publishing;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+import org.apache.isis.applib.annotation.DomainObject;
+import org.apache.isis.applib.annotation.Editing;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.Nature;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Property;
+import org.apache.isis.applib.annotation.PropertyLayout;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription;
+import demoapp.dom.annotLayout.PropertyLayout.cssClass.CssClassRedMetaAnnotation;
+
+//tag::class[]
+@XmlRootElement(name = "root")
+@XmlType
+@XmlAccessorType(XmlAccessType.FIELD)
+@DomainObject(
+        nature=Nature.VIEW_MODEL,
+        objectType = "demo.DomainObjectPublishingVm"
+)
+public class DomainObjectPublishingVm implements HasAsciiDocDescription {
+
+    public String title() {
+        return "DomainObject#publishing";
+    }
+
+
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.layout.xml
similarity index 86%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.layout.xml
index cc21592..6126994 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingJdo.layout.xml
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm.layout.xml
@@ -8,7 +8,9 @@
 	<bs3:row>
 		<bs3:col span="10" unreferencedActions="true">
 			<cpt:domainObject />
-			<cpt:action id="rebuildMetamodel"/>
+			<cpt:action id="create"/>
+			<cpt:action id="updateAll"/>
+			<cpt:action id="delete"/>
 		</bs3:col>
 		<bs3:col span="2">
 			<cpt:fieldSet name="" id="sources" />
@@ -19,11 +21,8 @@
 		<bs3:col span="6">
 			<bs3:row>
 				<bs3:col span="12">
-					<cpt:fieldSet name="General" id="general"/>
-				</bs3:col>
-			</bs3:row>
-			<bs3:row>
-				<bs3:col span="12">
+					<cpt:collection id="publishingEnabledEntities"/>
+					<cpt:collection id="publishingDisabledEntities"/>
 					<cpt:collection id="publishedObjects"/>
 				</bs3:col>
 			</bs3:row>
@@ -35,9 +34,9 @@
 		</bs3:col>
 		<bs3:col span="6">
 			<cpt:fieldSet name="Description" id="description" >
+				<cpt:action id="rebuildMetamodel" position="PANEL"/>
 				<cpt:action id="clearHints" position="PANEL" />
 				<cpt:action id="downloadLayoutXml"  position="PANEL_DROPDOWN"/>
-				<cpt:action id="rebuildMetamodel" position="PANEL_DROPDOWN"/>
 				<cpt:action id="downloadMetamodelXml"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="inspectMetamodel"  position="PANEL_DROPDOWN"/>
 				<cpt:action id="downloadJdoMetadata"  position="PANEL_DROPDOWN"/>
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_create.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_create.java
new file mode 100644
index 0000000..a045fa6
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_create.java
@@ -0,0 +1,43 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.repository.RepositoryService;
+
+import lombok.val;
+
+import demoapp.dom._infra.samples.NameSamples;
+import demoapp.dom.types.Samples;
+
+//tag::class[]
+@Action(semantics = SemanticsOf.NON_IDEMPOTENT)
+@ActionLayout(
+        describedAs = "Creates one publishing enabled entity and one publishing disabled entity"
+)
+public class DomainObjectPublishingVm_create {
+
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+    public DomainObjectPublishingVm_create(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
+    }
+
+    @MemberOrder(sequence = "1.0")
+    public DomainObjectPublishingVm act(String newValue) {
+        repositoryService.persistAndFlush(new DomainObjectPublishingEnabledJdo(newValue));
+        repositoryService.persistAndFlush(new DomainObjectPublishingDisabledJdo(newValue));
+        return domainObjectPublishingVm;
+    }
+    public String default0Act() {
+        return nameSamples.random();
+    }
+
+    @Inject
+    RepositoryService repositoryService;
+    @Inject
+    NameSamples nameSamples;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_delete.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_delete.java
new file mode 100644
index 0000000..02a2e82
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_delete.java
@@ -0,0 +1,41 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.repository.RepositoryService;
+
+//tag::class[]
+@Action(semantics = SemanticsOf.IDEMPOTENT)
+@ActionLayout(
+    describedAs = "Deletes one publishing enabled entity and one publishing disabled entity"
+)
+public class DomainObjectPublishingVm_delete {
+
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+    public DomainObjectPublishingVm_delete(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
+    }
+
+    @MemberOrder(sequence = "3.0")
+    public DomainObjectPublishingVm act(DomainObjectPublishingEnabledJdo enabledJdo, DomainObjectPublishingDisabledJdo disabledJdo) {
+        enabledJdoEntities.remove(enabledJdo);
+        disabledJdoEntities.remove(disabledJdo);
+        return domainObjectPublishingVm;
+    }
+    public DomainObjectPublishingEnabledJdo default0Act() {
+        return enabledJdoEntities.first();
+    }
+    public DomainObjectPublishingDisabledJdo default1Act() {
+        return disabledJdoEntities.first();
+    }
+
+    @Inject
+    DomainObjectPublishingEnabledJdoEntities enabledJdoEntities;
+    @Inject
+    DomainObjectPublishingDisabledJdoEntities disabledJdoEntities;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingDisabledEntities.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingDisabledEntities.java
new file mode 100644
index 0000000..9c00c4b
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingDisabledEntities.java
@@ -0,0 +1,24 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+
+@Collection()
+public class DomainObjectPublishingVm_publishingDisabledEntities {
+
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+
+    public DomainObjectPublishingVm_publishingDisabledEntities(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
+    }
+
+    public List<DomainObjectPublishingDisabledJdo> coll() {
+        return publishingDisabledJdoEntities.all();
+    }
+
+    @Inject
+    DomainObjectPublishingDisabledJdoEntities publishingDisabledJdoEntities;
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingEnabledEntities.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingEnabledEntities.java
new file mode 100644
index 0000000..d0bc170
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_publishingEnabledEntities.java
@@ -0,0 +1,24 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Collection;
+
+@Collection()
+public class DomainObjectPublishingVm_publishingEnabledEntities {
+
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+
+    public DomainObjectPublishingVm_publishingEnabledEntities(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
+    }
+
+    public List<DomainObjectPublishingEnabledJdo> coll() {
+        return publishingEnabledJdoEntities.all();
+    }
+
+    @Inject
+    DomainObjectPublishingEnabledJdoEntities publishingEnabledJdoEntities;
+}
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_updateAll.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_updateAll.java
new file mode 100644
index 0000000..c719744
--- /dev/null
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/DomainObjectPublishingVm_updateAll.java
@@ -0,0 +1,48 @@
+package demoapp.dom.annotDomain.DomainObject.publishing;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.SemanticsOf;
+import org.apache.isis.applib.services.repository.RepositoryService;
+
+import lombok.val;
+
+//tag::class[]
+@Action(semantics = SemanticsOf.IDEMPOTENT)
+@ActionLayout(
+    describedAs = "Updates all publishing enabled entities and all publishing disabled entities"
+)
+public class DomainObjectPublishingVm_updateAll {
+
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+    public DomainObjectPublishingVm_updateAll(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
+    }
+
+    @MemberOrder(sequence = "2.0")
+    public DomainObjectPublishingVm act() {
+
+        renumber((List)publishingEnabledJdoEntities.all());
+        renumber((List)publishingDisabledJdoEntities.all());
+
+        return domainObjectPublishingVm;
+    }
+
+    private static void renumber(List<DomainObjectPublishingJdo> all) {
+        val ai = new AtomicInteger(0);
+        all.forEach(x -> x.setPropertyUpdatedByAction("Object #" + ai.incrementAndGet()));
+    }
+
+    @Inject
+    DomainObjectPublishingDisabledJdoEntities publishingDisabledJdoEntities;
+
+    @Inject
+    DomainObjectPublishingEnabledJdoEntities publishingEnabledJdoEntities;
+}
+//end::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_clearPublishedObjects.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java
similarity index 58%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_clearPublishedObjects.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java
index 05be0a8..d33097d 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_clearPublishedObjects.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_clearPublishedObjects.java
@@ -5,27 +5,28 @@ import javax.inject.Inject;
 import org.apache.isis.applib.annotation.Action;
 import org.apache.isis.applib.annotation.SemanticsOf;
 
-import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingJdo;
+import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingVm;
 
 //tag::class[]
 @Action(
     semantics = SemanticsOf.IDEMPOTENT
     , associateWith = "publishedObjects"
 )
-public class DomainObjectPublishingJdo_clearPublishedObjects {
+public class DomainObjectPublishingVm_clearPublishedObjects {
     // ...
 //end::class[]
 
-    private final DomainObjectPublishingJdo domainObjectPublishingJdo;
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
 
-    public DomainObjectPublishingJdo_clearPublishedObjects(DomainObjectPublishingJdo domainObjectPublishingJdo) {
-        this.domainObjectPublishingJdo = domainObjectPublishingJdo;
+    public DomainObjectPublishingVm_clearPublishedObjects(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
     }
 
+
     //tag::class[]
-    public DomainObjectPublishingJdo act() {
+    public DomainObjectPublishingVm act() {
         publisherServiceSpiForDomainObject.clear();
-        return domainObjectPublishingJdo;
+        return domainObjectPublishingVm;
     }
 
     @Inject
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_publishedObjects.java b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
similarity index 70%
rename from examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_publishedObjects.java
rename to examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
index 5dbe083..d03ea3e 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingJdo_publishedObjects.java
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/DomainObject/publishing/spiimpl/DomainObjectPublishingVm_publishedObjects.java
@@ -10,17 +10,18 @@ import org.apache.isis.schema.chg.v2.ChangesDto;
 
 import lombok.val;
 
-import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingJdo;
+import demoapp.dom.annotDomain.DomainObject.publishing.DomainObjectPublishingVm;
 
 //tag::class[]
 @Collection
-public class DomainObjectPublishingJdo_publishedObjects {
+public class DomainObjectPublishingVm_publishedObjects {
     // ...
 //end::class[]
 
-    private final DomainObjectPublishingJdo domainObjectPublishingJdo;
-    public DomainObjectPublishingJdo_publishedObjects(DomainObjectPublishingJdo domainObjectPublishingJdo) {
-        this.domainObjectPublishingJdo = domainObjectPublishingJdo;
+    private final DomainObjectPublishingVm domainObjectPublishingVm;
+
+    public DomainObjectPublishingVm_publishedObjects(DomainObjectPublishingVm domainObjectPublishingVm) {
+        this.domainObjectPublishingVm = domainObjectPublishingVm;
     }
 
 //tag::class[]
diff --git a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo-description.adoc
index f12e92f..6d1403f 100644
--- a/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo-description.adoc
+++ b/examples/demo/domain/src/main/java/demoapp/dom/annotDomain/Property/publishing/PropertyPublishingJdo-description.adoc
@@ -2,12 +2,14 @@ The `publishing` semantic specifies that the editing of an object property shoul
 This is performed _after_ the property has been changed.
 
 The publishing from the framework to the SPI is in-memory.
-A typical SPI implementation would then publish over the network, or perhaps store in a database as per the link:https://microservices.io/patterns/data/transactional-outbox.html[outbox pattern].
-
-TIP: The framework provides an link:https://isis.apache.org/mappings/2.0.0-M3/outbox-publisher/about.html[out-of-the-box implementation] of the outbox pattern.
+A typical SPI implementation would then publish over the network, or perhaps store in a database.
+(Note that the framework provides an link:https://isis.apache.org/mappings/2.0.0-M3/outbox-publisher/about.html[out-of-the-box implementation] of the link:https://microservices.io/patterns/data/transactional-outbox.html[outbox pattern]).
 
 The semantic can be specified using either the `@Property` annotation, or through a meta-annotation.
 
+NOTE: The demo shows publishing of entities, as this is much more common use case than publishing a view model.
+
+
 == Annotated
 
 The `publisher` semantic can be specified explicitly using an annotation through `@Property#publishing()`: