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 2021/02/09 22:35:27 UTC

[isis] 02/02: ISIS-2444: more docs for domain services.

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

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

commit 9d0a34fc4d1d86f173a5b71106054fe0c66fc802
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Tue Feb 9 22:34:58 2021 +0000

    ISIS-2444: more docs for domain services.
---
 .../applib/services/eventbus/EventBusService.adoc  |  17 +-
 .../services/exceprecog/ExceptionRecognizer.adoc   |   6 +-
 .../exceprecog/ExceptionRecognizerService.adoc     |   2 +
 .../publishing/spi/EntityChangesSubscriber.adoc    |  10 +-
 .../spi/EntityPropertyChangeSubscriber.adoc        |  10 +-
 .../modules/generated/pages/system-overview.adoc   | 249 ++++-----------------
 .../applib-svc/pages/ExceptionRecognizer.adoc      | 101 ---------
 .../hooks/examples_and_usage.adoc                  |  17 ++
 .../ExceptionRecognizer/hooks/implementation.adoc  |  51 +++++
 .../pages/ExceptionRecognizerService.adoc          |  30 +--
 .../hooks/implementation.adoc                      |   2 +
 .../applib-svc/pages/ExecutionSubscriber.adoc      | 143 +-----------
 .../hooks/examples_and_usage.adoc                  |  31 +++
 .../ExecutionSubscriber/hooks/implementation.adoc  |  26 ++-
 .../modules/applib-svc/pages/FactoryService.adoc   |  74 +-----
 .../FactoryService/hooks/examples_and_usage.adoc   |  30 +++
 .../pages/FactoryService/hooks/implementation.adoc |   2 +
 .../applib-svc/pages/GridLoaderService.adoc        |  44 +---
 .../GridLoaderService/hooks/implementation.adoc    |   6 +-
 .../isis/applib/services/command/Command.java      |   4 +-
 .../exceprecog/ExceptionRecognizerService.java     |   3 +
 .../applib/services/exceprecog/Recognition.java    |   8 +
 .../applib/services/factory/FactoryService.java    |  15 ++
 .../applib/services/grid/GridLoaderService.java    |  27 ++-
 .../services/publishing/spi/EntityChanges.java     |  63 +++++-
 .../publishing/spi/EntityChangesSubscriber.java    |  10 +-
 .../publishing/spi/ExecutionSubscriber.java        |  47 +++-
 build-tooling.sh                                   |  32 +++
 .../ExceptionRecognizerServiceDefault.java         |  30 +--
 .../ExceptionRecognizerForDataAccessException.java |   5 +-
 .../ExceptionRecognizerForDataAlreadyExists.java   |  11 +-
 .../impl/ExceptionRecognizerForObjectNotFound.java |   5 +-
 ...ceptionRecognizerForOtherDataAccessProblem.java |  19 +-
 .../ExceptionRecognizerForRelatedDataExists.java   |   5 +-
 .../ExceptionRecognizerForUnableToSaveData.java    |   3 +-
 .../metamodel/facets/entity/JdoEntityFacet.java    |   3 +-
 preview.sh                                         |  10 +-
 stty.exe.stackdump                                 |  11 +
 38 files changed, 501 insertions(+), 661 deletions(-)

diff --git a/antora/components/system/modules/generated/pages/index/applib/services/eventbus/EventBusService.adoc b/antora/components/system/modules/generated/pages/index/applib/services/eventbus/EventBusService.adoc
index 2051579..ecbf198 100644
--- a/antora/components/system/modules/generated/pages/index/applib/services/eventbus/EventBusService.adoc
+++ b/antora/components/system/modules/generated/pages/index/applib/services/eventbus/EventBusService.adoc
@@ -10,7 +10,22 @@ Events are delivered synchronously to event subscribers (domain services).
 .EventBusService.java
 ----
 interface EventBusService {
-  void post(Object event)
+  void post(Object event)     // <.>
 }
 ----
 
+<.> xref:#post[post]
++
+--
+Post an event (of any class) to the in-memory event bus.
+--
+
+== Members
+
+[#post]
+=== post
+
+Post an event (of any class) to the in-memory event bus.
+
+The event will be delivered synchronously (within the same transactional boundary) to all subscribers of that event type (with subscribers as domain services with public method annotated using Spring's _org.springframework.context.event.EventListener_ annotation.
+
diff --git a/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizer.adoc b/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizer.adoc
index c945cc8..c572d1c 100644
--- a/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizer.adoc
+++ b/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizer.adoc
@@ -4,9 +4,11 @@ Domain service to (attempt) to recognize certain exceptions, and return user-fri
 
 Rather than redirecting to a general-purpose error page, the message (corresponding to the recognized exception) is rendered as a regular validation message.
 
-More than one implementation of xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer] can be registered; they will all be consulted (in the order as specified by the @Order annotation) to determine if they recognize the exception. The message returned by the first service recognizing the exception is used.
+For example, a set of recognizers are provided for the JPA and JDO persistence mechanisms in order to recognize and handle SQL constraint exceptions such as uniqueness violations. These can then be rendered back to the user as expected errors, rather than fatal stacktraces.
 
-The Isis framework also provides a default implementation of this service that recognizes any _org.apache.isis.applib.exceptions.RecoverableException_ , simply returning the exception's _org.apache.isis.applib.exceptions.RecoverableException#getMessage() message_ . This allows any component or domain object to throw this exception with the knowledge that it will be handled appropriately.
+More than one implementation of xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer] can be registered; they will all be consulted (in the order as specified by Spring's _org.springframework.core.annotation.Order_ annotation) to determine if they recognize the exception. The message returned by the first service recognizing the exception is used.
+
+The framework also provides a default implementation of this service that recognizes any _org.apache.isis.applib.exceptions.RecoverableException_ , simply returning the exception's _org.apache.isis.applib.exceptions.RecoverableException#getMessage() message_ . This allows any component or domain object to throw this exception with the knowledge that it will be handled appropriately.
 
 Initially introduced for the Wicket viewer; check the documentation of other viewers to determine whether they also support this service.
 
diff --git a/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizerService.adoc b/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizerService.adoc
index 4a72e47..3ef44bb 100644
--- a/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizerService.adoc
+++ b/antora/components/system/modules/generated/pages/index/applib/services/exceprecog/ExceptionRecognizerService.adoc
@@ -1,5 +1,7 @@
 :Notice: 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 ag [...]
 
+Used by the framework to iterate over all registered xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer] s in the correct order.
+
 == API
 
 [source,java]
diff --git a/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityChangesSubscriber.adoc b/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityChangesSubscriber.adoc
index 82576f9..47d917b 100644
--- a/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityChangesSubscriber.adoc
+++ b/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityChangesSubscriber.adoc
@@ -1,6 +1,8 @@
 :Notice: 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 ag [...]
 
-Part of the _Publishing SPI_ . A component to receive the entire set of entities (with publishing enabled) that are about to change, serializable as ChangesDto.
+SPI to receive the entire set of entities that are about to change as the result of a transaction.
+
+Only those entities that have publishing enabled (using * _DomainObject#entityChangePublishing()_ ) are included.
 
 == API
 
@@ -15,7 +17,7 @@ interface EntityChangesSubscriber {
 <.> xref:#onChanging[onChanging]
 +
 --
-Receives all changing entities (with publishing enabled) at then end of the a transaction during the pre-commit phase.
+Receives all changing entities (with publishing enabled using _DomainObject#entityChangePublishing()_ ) as an instance of xref:system:generated:index/applib/services/publishing/spi/EntityChanges.adoc[EntityChanges] .
 --
 
 == Members
@@ -23,5 +25,7 @@ Receives all changing entities (with publishing enabled) at then end of the a tr
 [#onChanging]
 === onChanging
 
-Receives all changing entities (with publishing enabled) at then end of the a transaction during the pre-commit phase.
+Receives all changing entities (with publishing enabled using _DomainObject#entityChangePublishing()_ ) as an instance of xref:system:generated:index/applib/services/publishing/spi/EntityChanges.adoc[EntityChanges] .
+
+The callback is called at the end of the transaction, during the pre-commit phase.
 
diff --git a/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc b/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc
index 7158037..7ababd3 100644
--- a/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc
+++ b/antora/components/system/modules/generated/pages/index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc
@@ -1,6 +1,8 @@
 :Notice: 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 ag [...]
 
-Part of the _Publishing SPI_ . A component to receive pre-post property values for each changed entity (with publishing enabled).
+SPI called for each pre-post change to a property of a domain entity during a result of the transaction. The callback is therefore quite fine-grained and will be called many (many) times for within any given transaction.
+
+Only those properties of entities that have publishing enabled (using * _DomainObject#entityChangePublishing()_ ) are included.
 
 == API
 
@@ -15,7 +17,7 @@ interface EntityPropertyChangeSubscriber {
 <.> xref:#onChanging[onChanging]
 +
 --
-Receives all pre-post property values for entities (with publishing enabled) at then end of the transaction during the pre-commit phase.
+Receives a single property change event for changing entities (with publishing enabled using _DomainObject#entityChangePublishing()_ ) as an instance of xref:system:generated:index/applib/services/publishing/spi/EntityPropertyChange.adoc[EntityPropertyChange] .
 --
 
 == Members
@@ -23,5 +25,7 @@ Receives all pre-post property values for entities (with publishing enabled) at
 [#onChanging]
 === onChanging
 
-Receives all pre-post property values for entities (with publishing enabled) at then end of the transaction during the pre-commit phase.
+Receives a single property change event for changing entities (with publishing enabled using _DomainObject#entityChangePublishing()_ ) as an instance of xref:system:generated:index/applib/services/publishing/spi/EntityPropertyChange.adoc[EntityPropertyChange] .
+
+The callback is called (multiple times) at the end of the transaction, during the pre-commit phase.
 
diff --git a/antora/components/system/modules/generated/pages/system-overview.adoc b/antora/components/system/modules/generated/pages/system-overview.adoc
index 5bf03b4..3f096ae 100644
--- a/antora/components/system/modules/generated/pages/system-overview.adoc
+++ b/antora/components/system/modules/generated/pages/system-overview.adoc
@@ -222,6 +222,7 @@ Folder: \core\config
 * o.a.i.core.config.beans.IsisBeanFactoryPostProcessorForSpring
 * o.a.i.core.config.beans.IsisBeanTypeRegistryDefault
 * o.a.i.core.config.converters.PatternsConverter
+* o.a.i.core.config.datasources.DataSourceIntrospectionService
 * o.a.i.core.config.environment.IsisLocaleInitializer
 * o.a.i.core.config.environment.IsisSystemEnvironment
 * o.a.i.core.config.environment.IsisTimeZoneInitializer
@@ -365,7 +366,7 @@ Folder: \core\runtime
 [%collapsible]
 .Components
 ====
-* o.a.i.core.runtime.events.AppLifecycleEventService
+* o.a.i.core.runtime.events.MetamodelEventService
 * o.a.i.core.runtime.events.TransactionEventEmitter
 ====
 [%collapsible]
@@ -397,12 +398,11 @@ Folder: \core\runtimeservices
 * o.a.i.core.runtimeservices.confmenu.ConfigurationViewServiceDefault
 * o.a.i.core.runtimeservices.email.EmailServiceDefault
 * o.a.i.core.runtimeservices.eventbus.EventBusServiceSpring
-* o.a.i.core.runtimeservices.exceprecog.ExceptionRecognizerServiceDefault
 * o.a.i.core.runtimeservices.executor.MemberExecutorServiceDefault
 * o.a.i.core.runtimeservices.factory.FactoryServiceDefault
 * o.a.i.core.runtimeservices.homepage.HomePageResolverServiceDefault
 * o.a.i.core.runtimeservices.i18n.po.TranslationServicePo
-* o.a.i.core.runtimeservices.ixn.InteractionDtoServiceInternalDefault
+* o.a.i.core.runtimeservices.interaction.InteractionDtoServiceInternalDefault
 * o.a.i.core.runtimeservices.jaxb.JaxbServiceDefault
 * o.a.i.core.runtimeservices.menubars.MenuBarsLoaderServiceDefault
 * o.a.i.core.runtimeservices.menubars.bootstrap3.MenuBarsServiceBS3
@@ -412,17 +412,23 @@ Folder: \core\runtimeservices
 * o.a.i.core.runtimeservices.publish.EntityPropertyChangePublisherDefault
 * o.a.i.core.runtimeservices.publish.ExecutionPublisherDefault
 * o.a.i.core.runtimeservices.queryresultscache.QueryResultsCacheDefault
+* o.a.i.core.runtimeservices.recognizer.ExceptionRecognizerServiceDefault
+* o.a.i.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForDataAlreadyExists
+* o.a.i.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForObjectNotFound
+* o.a.i.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForOtherDataAccessProblem
+* o.a.i.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForRelatedDataExists
+* o.a.i.core.runtimeservices.recognizer.dae.impl.ExceptionRecognizerForUnableToSaveData
 * o.a.i.core.runtimeservices.repository.RepositoryServiceDefault
 * o.a.i.core.runtimeservices.routing.RoutingServiceDefault
 * o.a.i.core.runtimeservices.scratchpad.ScratchpadDefault
 * o.a.i.core.runtimeservices.session.InteractionFactoryDefault
 * o.a.i.core.runtimeservices.sudo.SudoServiceDefault
+* o.a.i.core.runtimeservices.transaction.TransactionServiceSpring
 * o.a.i.core.runtimeservices.urlencoding.UrlEncodingServiceWithCompression
 * o.a.i.core.runtimeservices.user.UserServiceDefault
 * o.a.i.core.runtimeservices.userprof.UserProfileServiceDefault
 * o.a.i.core.runtimeservices.userreg.EmailNotificationServiceDefault
 * o.a.i.core.runtimeservices.wrapper.WrapperFactoryDefault
-* o.a.i.core.runtimeservices.xactn.TransactionServiceSpring
 * o.a.i.core.runtimeservices.xml.XmlServiceDefault
 * o.a.i.core.runtimeservices.xmlsnapshot.XmlSnapshotServiceDefault
 ====
@@ -639,32 +645,32 @@ skinparam rectangle<<116>> {
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<90>> {
+skinparam rectangle<<117>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<117>> {
+skinparam rectangle<<90>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<118>> {
+skinparam rectangle<<91>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<91>> {
+skinparam rectangle<<118>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<92>> {
+skinparam rectangle<<119>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<119>> {
+skinparam rectangle<<92>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
@@ -799,12 +805,12 @@ skinparam rectangle<<4>> {
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<5>> {
+skinparam rectangle<<126>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<126>> {
+skinparam rectangle<<5>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
@@ -819,12 +825,12 @@ skinparam rectangle<<6>> {
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<7>> {
+skinparam rectangle<<128>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<128>> {
+skinparam rectangle<<7>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
@@ -1389,22 +1395,22 @@ skinparam rectangle<<107>> {
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<108>> {
+skinparam rectangle<<81>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<81>> {
+skinparam rectangle<<108>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<109>> {
+skinparam rectangle<<82>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
 }
-skinparam rectangle<<82>> {
+skinparam rectangle<<109>> {
   BackgroundColor #438dd5
   FontColor #fffffe
   BorderColor #2E6295
@@ -1909,170 +1915,6 @@ Type: jar
 Folder: \examples\demo\domain
 ----
 |[%collapsible]
-.Components
-====
-* demoapp.dom.AppConfiguration
-* demoapp.dom._infra.DefaultTitleProvider
-* demoapp.dom._infra.LibraryPreloadingService
-* demoapp.dom._infra.fixtures.DemoFixtureScriptSpecificationProvider
-* demoapp.dom._infra.resources.AsciiDocConverterService
-* demoapp.dom._infra.resources.AsciiDocReaderService
-* demoapp.dom._infra.resources.MarkdownReaderService
-* demoapp.dom._infra.resources.MarkupReaderService
-* demoapp.dom._infra.resources.MarkupVariableResolverService
-* demoapp.dom._infra.resources.ResourceReaderService
-* demoapp.dom._infra.samples.NameSamples
-* demoapp.dom._infra.urlencoding.UrlEncodingServiceNaiveInMemory
-* demoapp.dom.domain._changes.EntityChangesSubscriberToCaptureChangesInMemory
-* demoapp.dom.domain._commands.ExposePersistedCommands$TableColumnOrderDefault
-* demoapp.dom.domain._interactions.ExecutionListenerToCaptureInteractionsInMemory
-* demoapp.dom.domain.actions.Action.commandPublishing.ActionCommandPublishingJdoEntities
-* demoapp.dom.domain.actions.Action.commandPublishing.ActionCommandPublishingJdoSeedService
-* demoapp.dom.domain.actions.Action.executionPublishing.ActionExecutionPublishingJdoEntities
-* demoapp.dom.domain.actions.Action.executionPublishing.ActionExecutionPublishingJdoSeedService
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.annotated.disabled.DomainObjectEntityChangePublishingDisabledJdoEntities
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.annotated.disabled.DomainObjectEntityChangePublishingDisabledJdoSeedService
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.annotated.enabled.DomainObjectAuditingEnabledJdoEntities
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.annotated.enabled.DomainObjectAuditingEnabledJdoSeedService
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.metaAnnot.enabled.DomainObjectEntityChangePublishingEnabledMetaAnnotatedJdoEntities
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.metaAnnot.enabled.DomainObjectEntityChangePublishingEnabledMetaAnnotatedJdoSeedService
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.metaAnnotOverridden.enabled.DomainObjectEntityChangePublishingEnabledMetaAnnotOverriddenJdoEntities
-* demoapp.dom.domain.objects.DomainObject.entityChangePublishing.metaAnnotOverridden.enabled.DomainObjectEntityChangePublishingEnabledMetaAnnotOverriddenJdoSeedService
-* demoapp.dom.domain.objects.DomainObject.nature.viewmodels.jaxbrefentity.ChildJdoEntities
-* demoapp.dom.domain.objects.DomainObject.nature.viewmodels.jaxbrefentity.seed.ChildJdoSeedService
-* demoapp.dom.domain.objects.other.embedded.NumberConstantJdoRepository
-* demoapp.dom.domain.properties.Property.commandPublishing.PropertyCommandPublishingJdoEntities
-* demoapp.dom.domain.properties.Property.commandPublishing.PropertyCommandPublishingJdoSeedService
-* demoapp.dom.domain.properties.Property.executionPublishing.PropertyExecutionPublishingJdoEntities
-* demoapp.dom.domain.properties.Property.executionPublishing.PropertyExecutionPublishingJdoSeedService
-* demoapp.dom.domain.properties.Property.projecting.jdo.PropertyProjectingChildJdoEntities
-* demoapp.dom.domain.properties.Property.projecting.jdo.PropertyProjectingChildJdoSeedService
-* demoapp.dom.domain.properties.PropertyLayout.navigable.FileTreeNodeService
-* demoapp.dom.domain.properties.PropertyLayout.repainting.PdfJsViewerAdvisorFallback
-* demoapp.dom.featured.customui.geocoding.GeoapifyClient
-* demoapp.dom.services.core.errorreportingservice.ErrorReportingServiceDemoImplementation
-* demoapp.dom.services.core.eventbusservice.EventLogEntryJdoRepository
-* demoapp.dom.services.core.eventbusservice.EventSubscriberDemoImplementation
-* demoapp.dom.services.core.wrapperFactory.WrapperFactoryJdoEntities
-* demoapp.dom.services.core.wrapperFactory.WrapperFactoryJdoSeedService
-* demoapp.dom.services.extensions.secman.apptenancy.ApplicationTenancyEvaluatorForDemo
-* demoapp.dom.services.extensions.secman.apptenancy.entities.TenantedJdoEntities
-* demoapp.dom.services.extensions.secman.apptenancy.entities.seed.TenantedJdoSeedService
-* demoapp.dom.types.isis.blobs.jdo.IsisBlobJdoEntities
-* demoapp.dom.types.isis.blobs.jdo.IsisBlobJdoSeedService
-* demoapp.dom.types.isis.blobs.samples.IsisBlobsSamples
-* demoapp.dom.types.isis.clobs.jdo.IsisClobJdoEntities
-* demoapp.dom.types.isis.clobs.jdo.IsisClobJdoSeedService
-* demoapp.dom.types.isis.clobs.samples.IsisClobsSamples
-* demoapp.dom.types.isis.localresourcepaths.jdo.IsisLocalResourcePathJdoEntities
-* demoapp.dom.types.isis.localresourcepaths.jdo.IsisLocalResourcePathJdoSeedService
-* demoapp.dom.types.isis.localresourcepaths.samples.IsisLocalResourcePathsSamples
-* demoapp.dom.types.isis.markups.jdo.IsisMarkupJdoEntities
-* demoapp.dom.types.isis.markups.jdo.IsisMarkupJdoSeedService
-* demoapp.dom.types.isis.markups.samples.IsisMarkupSamples
-* demoapp.dom.types.isis.passwords.jdo.IsisPasswordJdoEntities
-* demoapp.dom.types.isis.passwords.jdo.IsisPasswordJdoSeedService
-* demoapp.dom.types.isis.passwords.samples.IsisPasswordsSamples
-* demoapp.dom.types.isisext.asciidocs.jdo.IsisAsciiDocJdoEntities
-* demoapp.dom.types.isisext.asciidocs.jdo.IsisAsciiDocJdoSeedService
-* demoapp.dom.types.isisext.asciidocs.samples.IsisAsciiDocSamples
-* demoapp.dom.types.isisext.markdowns.jdo.IsisMarkdownJdoEntities
-* demoapp.dom.types.isisext.markdowns.jdo.IsisMarkdownJdoSeedService
-* demoapp.dom.types.isisext.markdowns.samples.IsisMarkdownSamples
-* demoapp.dom.types.javaawt.images.jdo.JavaAwtImageJdoEntities
-* demoapp.dom.types.javaawt.images.jdo.JavaAwtImageJdoSeedService
-* demoapp.dom.types.javaawt.images.samples.JavaAwtImageService
-* demoapp.dom.types.javaawt.images.samples.JavaAwtImagesSamples
-* demoapp.dom.types.javalang.booleans.jdo.WrapperBooleanJdoEntities
-* demoapp.dom.types.javalang.booleans.jdo.WrapperBooleanJdoSeedService
-* demoapp.dom.types.javalang.booleans.samples.WrapperBooleanSamples
-* demoapp.dom.types.javalang.bytes.jdo.WrapperByteJdoEntities
-* demoapp.dom.types.javalang.bytes.jdo.WrapperByteJdoSeedService
-* demoapp.dom.types.javalang.bytes.samples.WrapperByteSamples
-* demoapp.dom.types.javalang.characters.jdo.WrapperCharacterJdoEntities
-* demoapp.dom.types.javalang.characters.jdo.WrapperCharacterJdoSeedService
-* demoapp.dom.types.javalang.characters.samples.WrapperCharacterSamples
-* demoapp.dom.types.javalang.doubles.jdo.WrapperDoubleJdoEntities
-* demoapp.dom.types.javalang.doubles.jdo.WrapperDoubleJdoSeedService
-* demoapp.dom.types.javalang.doubles.samples.WrapperDoubleSamples
-* demoapp.dom.types.javalang.floats.jdo.WrapperFloatJdoEntities
-* demoapp.dom.types.javalang.floats.jdo.WrapperFloatJdoSeedService
-* demoapp.dom.types.javalang.floats.samples.WrapperFloatSamples
-* demoapp.dom.types.javalang.integers.jdo.WrapperIntegerJdoEntities
-* demoapp.dom.types.javalang.integers.jdo.WrapperIntegerJdoSeedService
-* demoapp.dom.types.javalang.integers.samples.WrapperIntegerSamples
-* demoapp.dom.types.javalang.longs.jdo.WrapperLongJdoEntities
-* demoapp.dom.types.javalang.longs.jdo.WrapperLongJdoSeedService
-* demoapp.dom.types.javalang.longs.samples.WrapperLongSamples
-* demoapp.dom.types.javalang.shorts.jdo.WrapperShortJdoEntities
-* demoapp.dom.types.javalang.shorts.jdo.WrapperShortJdoSeedService
-* demoapp.dom.types.javalang.shorts.samples.WrapperShortSamples
-* demoapp.dom.types.javalang.strings.jdo.JavaLangStringJdoEntities
-* demoapp.dom.types.javalang.strings.jdo.JavaLangStringJdoSeedService
-* demoapp.dom.types.javalang.strings.samples.JavaLangStringSamples
-* demoapp.dom.types.javamath.bigdecimals.jdo.JavaMathBigDecimalJdoEntities
-* demoapp.dom.types.javamath.bigdecimals.jdo.JavaMathBigDecimalJdoSeedService
-* demoapp.dom.types.javamath.bigdecimals.samples.JavaMathBigDecimalSamples
-* demoapp.dom.types.javamath.bigintegers.jdo.JavaMathBigIntegerJdoEntities
-* demoapp.dom.types.javamath.bigintegers.jdo.JavaMathBigIntegerJdoSeedService
-* demoapp.dom.types.javamath.bigintegers.samples.JavaMathBigIntegerSamples
-* demoapp.dom.types.javanet.urls.jdo.JavaNetUrlJdoEntities
-* demoapp.dom.types.javanet.urls.jdo.JavaNetUrlJdoSeedService
-* demoapp.dom.types.javanet.urls.samples.JavaNetUrlSamples
-* demoapp.dom.types.javasql.javasqldate.jdo.JavaSqlDateJdoEntities
-* demoapp.dom.types.javasql.javasqldate.jdo.JavaSqlDateJdoSeedService
-* demoapp.dom.types.javasql.javasqldate.samples.JavaSqlDateSamples
-* demoapp.dom.types.javasql.javasqltimestamp.jdo.JavaSqlTimestampJdoEntities
-* demoapp.dom.types.javasql.javasqltimestamp.jdo.JavaSqlTimestampJdoSeedService
-* demoapp.dom.types.javasql.javasqltimestamp.samples.JavaSqlTimestampSamples
-* demoapp.dom.types.javatime.javatimelocaldate.jdo.JavaTimeLocalDateJdoEntities
-* demoapp.dom.types.javatime.javatimelocaldate.jdo.JavaTimeLocalDateJdoSeedService
-* demoapp.dom.types.javatime.javatimelocaldate.samples.JavaTimeLocalDateSamples
-* demoapp.dom.types.javatime.javatimelocaldatetime.jdo.JavaTimeLocalDateTimeJdoEntities
-* demoapp.dom.types.javatime.javatimelocaldatetime.jdo.JavaTimeLocalDateTimeJdoSeedService
-* demoapp.dom.types.javatime.javatimelocaldatetime.samples.JavaTimeLocalDateTimeSamples
-* demoapp.dom.types.javatime.javatimeoffsetdatetime.jdo.JavaTimeOffsetDateTimeJdoEntities
-* demoapp.dom.types.javatime.javatimeoffsetdatetime.jdo.JavaTimeOffsetDateTimeJdoSeedService
-* demoapp.dom.types.javatime.javatimeoffsetdatetime.samples.JavaTimeOffsetDateTimeSamples
-* demoapp.dom.types.javatime.javatimeoffsettime.jdo.JavaTimeOffsetTimeJdoEntities
-* demoapp.dom.types.javatime.javatimeoffsettime.jdo.JavaTimeOffsetTimeJdoSeedService
-* demoapp.dom.types.javatime.javatimeoffsettime.samples.JavaTimeOffsetTimeSamples
-* demoapp.dom.types.javatime.javatimezoneddatetime.jdo.JavaTimeZonedDateTimeJdoEntities
-* demoapp.dom.types.javatime.javatimezoneddatetime.jdo.JavaTimeZonedDateTimeJdoSeedService
-* demoapp.dom.types.javatime.javatimezoneddatetime.samples.JavaTimeZonedDateTimeSamples
-* demoapp.dom.types.javautil.javautildate.jdo.JavaUtilDateJdoEntities
-* demoapp.dom.types.javautil.javautildate.jdo.JavaUtilDateJdoSeedService
-* demoapp.dom.types.javautil.javautildate.samples.JavaUtilDateSamples
-* demoapp.dom.types.javautil.uuids.jdo.JavaUtilUuidJdoEntities
-* demoapp.dom.types.javautil.uuids.jdo.JavaUtilUuidJdoSeedService
-* demoapp.dom.types.javautil.uuids.samples.JavaUtilUuidSamples
-* demoapp.dom.types.jodatime.jodadatetime.jdo.JodaDateTimeJdoEntities
-* demoapp.dom.types.jodatime.jodadatetime.jdo.JodaDateTimeJdoSeedService
-* demoapp.dom.types.jodatime.jodadatetime.samples.JodaDateTimeSamples
-* demoapp.dom.types.jodatime.jodalocaldate.jdo.JodaLocalDateJdoEntities
-* demoapp.dom.types.jodatime.jodalocaldate.jdo.JodaLocalDateJdoSeedService
-* demoapp.dom.types.jodatime.jodalocaldate.samples.JodaLocalDateSamples
-* demoapp.dom.types.jodatime.jodalocaldatetime.jdo.JodaLocalDateTimeJdoEntities
-* demoapp.dom.types.jodatime.jodalocaldatetime.jdo.JodaLocalDateTimeJdoSeedService
-* demoapp.dom.types.jodatime.jodalocaldatetime.samples.JodaLocalDateTimeSamples
-* demoapp.dom.types.primitive.booleans.jdo.PrimitiveBooleanJdoEntities
-* demoapp.dom.types.primitive.booleans.jdo.PrimitiveBooleanJdoSeedService
-* demoapp.dom.types.primitive.bytes.jdo.PrimitiveByteJdoEntities
-* demoapp.dom.types.primitive.bytes.jdo.PrimitiveByteJdoSeedService
-* demoapp.dom.types.primitive.chars.jdo.PrimitiveCharJdoEntities
-* demoapp.dom.types.primitive.chars.jdo.PrimitiveCharJdoSeedService
-* demoapp.dom.types.primitive.doubles.jdo.PrimitiveDoubleJdoEntities
-* demoapp.dom.types.primitive.doubles.jdo.PrimitiveDoubleJdoSeedService
-* demoapp.dom.types.primitive.floats.jdo.PrimitiveFloatJdoEntities
-* demoapp.dom.types.primitive.floats.jdo.PrimitiveFloatJdoSeedService
-* demoapp.dom.types.primitive.ints.jdo.PrimitiveIntJdoEntities
-* demoapp.dom.types.primitive.ints.jdo.PrimitiveIntJdoSeedService
-* demoapp.dom.types.primitive.longs.jdo.PrimitiveLongJdoEntities
-* demoapp.dom.types.primitive.longs.jdo.PrimitiveLongJdoSeedService
-* demoapp.dom.types.primitive.shorts.jdo.PrimitiveShortJdoEntities
-* demoapp.dom.types.primitive.shorts.jdo.PrimitiveShortJdoSeedService
-====
-[%collapsible]
 .Dependencies
 ====
 * com.h2database:h2:jar:<managed>
@@ -2741,6 +2583,15 @@ Type: jar
 Folder: \extensions\security\secman\persistence-jpa
 ----
 |[%collapsible]
+.Components
+====
+* o.a.i.extensions.secman.jpa.dom.permission.ApplicationPermissionRepository
+* o.a.i.extensions.secman.jpa.dom.role.ApplicationRoleRepository
+* o.a.i.extensions.secman.jpa.dom.tenancy.ApplicationTenancyRepository
+* o.a.i.extensions.secman.jpa.dom.user.ApplicationUserRepository
+* o.a.i.extensions.secman.jpa.seed.SeedSecurityModuleService
+====
+[%collapsible]
 .Dependencies
 ====
 * org.apache.isis.core:isis-core-runtime:jar:<managed>
@@ -3406,12 +3257,9 @@ Folder: \persistence\jdo\datanucleus
 .Components
 ====
 * o.a.i.persistence.jdo.datanucleus.config.DnEntityDiscoveryListener
-* o.a.i.persistence.jdo.datanucleus.config.DnSettings
 * o.a.i.persistence.jdo.datanucleus.entities.DnEntityStateProvider
-* o.a.i.persistence.jdo.datanucleus.exceptions.recognizers.ExceptionRecognizerForJDODataStoreException
-* o.a.i.persistence.jdo.datanucleus.exceptions.recognizers.ExceptionRecognizerForJDODataStoreExceptionIntegrityConstraintViolationForeignKeyNoActionException
-* o.a.i.persistence.jdo.datanucleus.exceptions.recognizers.ExceptionRecognizerForJDOObjectNotFoundException
-* o.a.i.persistence.jdo.datanucleus.exceptions.recognizers.ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException
+* o.a.i.persistence.jdo.datanucleus.jdosupport.JdoSupportServiceDefault
+* o.a.i.persistence.jdo.datanucleus.metamodel.JdoDataNucleusProgrammingModel
 ====
 [%collapsible]
 .Dependencies
@@ -3446,13 +3294,6 @@ Folder: \persistence\jdo\integration
 |JDO Integration (powered by DataNucleus)
 
 [%collapsible]
-.Components
-====
-* o.a.i.persistence.jdo.integration.jdosupport.IsisJdoSupportDN5
-* o.a.i.persistence.jdo.integration.metamodel.JdoIntegrationProgrammingModel
-* o.a.i.persistence.jdo.integration.schema.JdoSchemaService
-====
-[%collapsible]
 .Dependencies
 ====
 * org.apache.isis.commons:isis-commons:jar:<managed>
@@ -3629,6 +3470,11 @@ Folder: \persistence\jpa\metamodel
 |JPA Metamodel Facets / Programming Model
 
 [%collapsible]
+.Components
+====
+* o.a.i.persistence.jpa.metamodel.JpaProgrammingModel
+====
+[%collapsible]
 .Dependencies
 ====
 * org.apache.isis.core:isis-core-internaltestsupport:jar:<managed>
@@ -3684,21 +3530,6 @@ Type: jar
 Folder: \regressiontests\stable
 ----
 |[%collapsible]
-.Components
-====
-* o.a.i.testdomain.applayer.ApplicationLayerTestFactory
-* o.a.i.testdomain.applayer.ApplicationLayerTestFactory$PreCommitListener
-* o.a.i.testdomain.applayer.publishing.CommandSubscriberForTesting
-* o.a.i.testdomain.applayer.publishing.EntityChangesSubscriberForTesting
-* o.a.i.testdomain.applayer.publishing.EntityPropertyChangeSubscriberForTesting
-* o.a.i.testdomain.applayer.publishing.ExecutionSubscriberForTesting
-* o.a.i.testdomain.conf.Configuration_headless$HeadlessCommandSupport
-* o.a.i.testdomain.jpa.springdata.EmployeeRepository
-* o.a.i.testdomain.util.interaction.InteractionBoundaryProbe
-* o.a.i.testdomain.util.kv.KVStoreForTesting
-* o.a.i.testdomain.util.rest.RestEndpointService
-====
-[%collapsible]
 .Dependencies
 ====
 * org.apache.isis.extensions:isis-extensions-cors-impl:jar:<managed>
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer.adoc
index 836064c..1f668cf 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer.adoc
@@ -6,109 +6,8 @@
 
 include::system:generated:page$index/applib/services/exceprecog/ExceptionRecognizer.adoc[leveloffset=+2]
 
-
 include::ExceptionRecognizer/hooks/implementation.adoc[]
 
 include::ExceptionRecognizer/hooks/examples_and_usage.adoc[]
 
 
-[source,java]
-----
-include::refguide:applib-svc:example$services/exceprecog/ExceptionRecognizer.java[tags="refguide-2",indent=0]
-----
-
-and `Category` in turn is an enumeration of the various types of exceptions that are recognised:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/exceprecog/ExceptionRecognizer.java[tags="refguide-1",indent=0]
-----
-<.> a violation of some declarative constraint (eg uniqueness or referential integrity) was detected.
-<.> the object to be acted upon cannot be found (404)
-<.> a concurrency exception, in other words some other user has changed this object.
-<.> recognized, but for some other reason... 40x error
-<.> 50x error
-<.> recognized, but uncategorized.
-
-
-In essence, if an exception is recognized then it is also categorized.
-This lets the viewer act accordingly.
-For example, if an exception is raised from the loading of an individual object, then this is passed by the registered ``ExceptionRecognizer``s.
-If any of these recognize the exception as representing a not-found exception, then an Apache Isis `ObjectNotFoundException` is raised.
-Both the viewers interprets this correctly (the xref:vw:ROOT:about.adoc[Wicket viewer] as a suitable error page, the xref:vro:ROOT:about.adoc[Restful Objects viewer] as a 404 status return code).
-
-
-If the implementation recognizes the exception then it returns a user-friendly message to be rendered (by the viewer) back to the user; otherwise it returns `null`.
-There is no need for the implementation to check for exception causes; the casual chain is unwrapped by Apache Isis core and each exception in the chain will also be passed through to the recognizer (from most specific to least).
-The recognizer implementation can therefore be as fine-grained or as coarse-grained as it wishes.
-
-
-
-
-
-================================
-
-== Implementation
-
-WARNING: TODO: v2 - this is out of date; we've teased apart ExceptionRecognizer from ExceptionRecognizerService.
-There is also ExceptionRecognizerForType as an impl.
-
-The framework provides two default implementations:
-
-* `o.a.i.core.metamodel.services.exceprecog.ExceptionRecognizerDocDefault` provided by Apache Isis core is itself an `ExceptionRecognizer`, and will handle ``ConcurrencyException``s.
-+
-It will also handle any application exceptions raised by the system (subclasses of `o.a.i.applib.RecoverableException`).
-
-* `o.a.i.applib.services.exceprecog.jdo.ExceptionRecognizerCompositeForJdoObjectStore`
-+
-which bundles up a number of more fine-grained implementations:
-+
-** `ExceptionRecognizerForSQLIntegrityConstraintViolationUniqueOrIndexException`
-** `ExceptionRecognizerForJDOObjectNotFoundException`
-** `ExceptionRecognizerForJDODataStoreException`
-
-
-If you want to recognize and handle additional exceptions (for example to capture error messages specific to the JDBC driver you might be using), then create a fine-grained implementation of `ExceptionRecognizer` for the particular error message (there are some convenience implementations of the interface that you can subclass from if required) and annotated with `@DomainService` in the usual way.
-Make sure that the service resides under a module registered in `AppManifest`.
-
-
-
-=== Configuration Properties
-
-The following configuration properties are relevant:
-
-[cols="2a,1,3a", options="header"]
-|===
-|Property
-|Value +
-(default value)
-|Description
-
-| `isis.services.` +
-`exceprecog.` +
-`logRecognized` +
-`Exceptions` +
-|`true`,`false` +
-(`false`)
-|whether recognized exceptions should also be logged. +
-
-Generally a recognized exception is one that is expected (for example a uniqueness constraint violated in the database) and which does not represent an error condition.
-This property logs the exception anyway, useful for debugging.
-
-This is recognised by all implementations that subclass `ExceptionRecognizerAbstract`.
-
-| `isis.services.` +
-`ExceptionRecognizer` +
-`CompositeFor` +
-`JdoObjectStore.` +
-`disable` +
-|`true`,`false` +
-(`false`)
-|whether to disable the default recognizers registered by `ExceptionRecognizerCompositeForJdoObjectStore`. +
-
-This implementation provides a default set of recognizers to convert RDBMS constraints into user-friendly messages.
-In the (probably remote) chance that this functionality isn't required, they can be disabled through this flag.
-
-
-|===
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/examples_and_usage.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/examples_and_usage.adoc
index fdc72ce..b945680 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/examples_and_usage.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/examples_and_usage.adoc
@@ -2,7 +2,24 @@
 :Notice: 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 ag [...]
 
 
+== Usage
+
+If you want to recognize and handle additional exceptions (for example to capture error messages specific to the JDBC driver you might be using), then create an implementation of this SPI for the particular error message, and annotate your implementation as a xref:system:generated:index/applib/annotation/DomainService.adoc[DomainService].
+
+There are some convenience implementations of the interface to subclass from if required.
+
+
 == See also
 
 * xref:system:generated:index/applib/services/exceprecog/Recognition.adoc[Recognition]
++
+Part of the SPI for xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer]
+
 * xref:system:generated:index/applib/services/exceprecog/Category.adoc[Category]
++
+Part of the SPI for xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer]
+
+* xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizerService.adoc[ExceptionRecognizerService]
++
+mediates access to xref:system:generated:index/applib/services/exceprecog/ExceptionRecognizer.adoc[ExceptionRecognizer]s in the correct order.
+
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/implementation.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/implementation.adoc
index 697f559..529c621 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/implementation.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizer/hooks/implementation.adoc
@@ -4,3 +4,54 @@
 
 
 == Implementation
+
+The framework provides a number of default implementations for JPA and JDO, to recognise:
+
+* data already exists (uniqueness constraints)
+* object not found
+* related data exists (foreign key constraints preventing change)
+* unable to save data (foreign key constraints not met)
+* other data access problem.
+
+
+// TODO: v2 - flesh this out once ISIS-2502 is complete.
+
+//=== Configuration Properties
+//
+//The following configuration properties are relevant:
+//
+//[cols="2a,1,3a", options="header"]
+//|===
+//|Property
+//|Value +
+//(default value)
+//|Description
+//
+//| `isis.services.` +
+//`exceprecog.` +
+//`logRecognized` +
+//`Exceptions` +
+//|`true`,`false` +
+//(`false`)
+//|whether recognized exceptions should also be logged. +
+//
+//Generally a recognized exception is one that is expected (for example a uniqueness constraint violated in the database) and which does not represent an error condition.
+//This property logs the exception anyway, useful for debugging.
+//
+//This is recognised by all implementations that subclass `ExceptionRecognizerAbstract`.
+//
+//| `isis.services.` +
+//`ExceptionRecognizer` +
+//`CompositeFor` +
+//`JdoObjectStore.` +
+//`disable` +
+//|`true`,`false` +
+//(`false`)
+//|whether to disable the default recognizers registered by `ExceptionRecognizerCompositeForJdoObjectStore`. +
+//
+//This implementation provides a default set of recognizers to convert RDBMS constraints into user-friendly messages.
+//In the (probably remote) chance that this functionality isn't required, they can be disabled through this flag.
+//
+//
+//|===
+
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService.adoc
index 452614c..b7bb04d 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService.adoc
@@ -4,36 +4,10 @@
 :Notice: 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 ag [...]
 
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
-
-The `ExceptionRecognizerService` domain service is used by the framework to iterate over all registered xref:refguide:applib-svc:ExceptionRecognizer.adoc[`ExceptionRecognizer`]s to attempt to recognise an exception.
-
-
-== API
 
 include::system:generated:page$index/applib/services/exceprecog/ExceptionRecognizerService.adoc[leveloffset=+2]
 
-TODO example migration
-
-.Deprecated Docs
-[WARNING]
-================================
-
-== PI
-
-The SPI defined by this service is:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/exceprecog/ExceptionRecognizerService.java[tags="refguide"]
-----
-
-
-
-
-================================
-
-== Implementation
+include::ExceptionRecognizerService/hooks/implementation.adoc[]
 
-The framework provides a default implementations, `o.a.i.core.runtimeservices.exceprecog.ExceptionRecognizerServiceDefault`.
+include::ExceptionRecognizerService/hooks/examples_and_usage.adoc[]
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService/hooks/implementation.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService/hooks/implementation.adoc
index 697f559..e87afc6 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService/hooks/implementation.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExceptionRecognizerService/hooks/implementation.adoc
@@ -4,3 +4,5 @@
 
 
 == Implementation
+
+The framework provides a default implementation of this service, `o.a.i.core.runtimeservices.recognizer.ExceptionRecognizerServiceDefault`.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber.adoc
index 9304e04..42d5526 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber.adoc
@@ -4,148 +4,11 @@
 :Notice: 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 ag [...]
 
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
 
-The `PublisherService` API is intended for coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system.
-Events that can be published are action invocations/property edits, and changed objects.
-A typical use case is to publish onto a pub/sub bus such as link:http://activemq.apache.org/[ActiveMQ] with link:http://camel.apache.org[Camel] to keep other systems up to date.
+include::system:generated:page$index/applib/services/publishing/spi/ExecutionSubscriber.adoc[leveloffset=+2]
 
-An alternative use is for profiling: for each execution (action invocation/property edit) the framework captures metrics of the number of objects loaded or dirtied as the result of that execution.
-If the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] is used to call other objects then the metrics are captured for each sub-execution.
-The framework provides a default implementation, `PublisherServiceLogging`, that will log these execution graphs (in XML form, per the xref:refguide:schema:ixn.adoc["ixn" schema]) to an SLF4J logger.
+include::ExecutionSubscriber/hooks/implementation.adoc[]
 
-Only actions/properties/domain objects annotated for publishing (using xref:refguide:applib-ant:Action.adoc#publishing[`@Action#publishing()`], xref:refguide:applib-ant:Property.adoc#publishing[`@Property#publishing()`] or xref:refguide:applib-ant:DomainObject.adoc#publishing[`@DomainObject#publishing()`]) are published.
+include::ExecutionSubscriber/hooks/examples_and_usage.adoc[]
 
 
-== API
-
-include::system:generated:page$index/PublishedObjects.adoc[leveloffset=+2]
-
-TODO example migration
-
-.Deprecated Docs
-[WARNING]
-================================
-
-== SPI
-
-The SPI defined by the service is:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/publish/PublisherService.java[tags="refguide"]
-----
-<.> to publish an individual action invocation or property edit, as captured within an `Interaction.Execution`.
-<.> to publish a set of changed objects.
-
-where `PublishedObjects` is provides statistics on the interaction execution (action invocation or property edit):
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/publish/PublishedObjects.java[tags="refguide"]
-----
-<.> inherited from `HasUniqueId`, correlates back to the unique identifier of the transaction in which these objects were changed.
-<.> inherited from `HasUsername`, is the user that initiated the transaction causing these objects to change
-<.> Time that the interaction execution completed
-<.> Number of domain objects loaded in this interaction
-<.> Number of domain objects created in this interaction
-<.> Number of domain objects updated in this interaction
-<.> Number of domain objects deleted in this interaction
-<.> Number of domain objects properties that were changed in this interaction
-<.> Same details, as per xref:refguide:schema:chg.adoc[`chg.xsd`] schema.
-This can be converted into a serializable XML representation using the `ChangesDtoUtils` utility class.
-
-The numbers of objects loaded, created, updated or deleted and the number of object properties modified (in other words the "size" or "weight" of the transaction).
-
-Each `Interaction.Execution` has an owning `Interaction`; this is the same object obtainable from xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`].
-Implementations that publish member executions can use `Interaction.Execution#getDto()` method to return a DTO (as per the xref:refguide:schema:ixn.adoc["ixn" schema]) which can be converted into a serializable XML representation using the `InteractionDtoUtils` utility class.
-The XML can either serialize a single execution, or can be a "deep" serialization of an execution and all sub-executions.
-
-
-
-
-================================
-
-== Implementations
-
-The framework allows multiple implementations of this service to be registered; all will be called.
-
-There are two implementations provided by the framework:
-
-* The core framework provides one implementation of its own, `PublisherServiceLogging` (in `o.a.i.applib.services.publish` package).
-This logs serializations to a link:https://logging.apache.org/log4j/log4j-2.2/manual/configuration.html[Log4j2] logger
-+
-[source,xml]
-.log4j2-spring.xml
-----
-<?xml version="1.0" encoding="UTF-8"?>
-<Configuration status="WARN">
-  <Properties> ... </Properties>
-  <Appenders> ... </Appenders>
-  <Loggers>
-    ...
-    <logger
-      name="org.apache.isis.applib.services.publish.PublisherServiceLogging"
-      level="debug"/>
-    ...
-  </Loggers>
-</Configuration>
-----
-+
-See the `log4j2-spring.xml` file in xref:docs:starters:simpleapp.adoc[simpleapp] for the omitted detail.
-
-* the xref:mappings:outbox-publisher:about.adoc[Outbox Publisher] in the xref:mappings:ROOT:about.adoc[Mappings catalog] persists each interaction into a link:https://microservices.io/patterns/data/transactional-outbox.html[outbox table] for subsequent processing.
-As its name implies, it uses xref:pjdo:ROOT:about.adoc[JDO/DataNucleus] to do this.
-+
-WARNING: TODO: v2 - need to migrate this across.
-Also, check the name is correct.
-
-
-
-
-== Usage
-
-To indicate that:
-
-* an action invocation should be published, annotate it with the xref:refguide:applib-ant:Action.adoc#publishing[`@Action#publishing()`] annotation.
-* an property edit should be published, annotate it with the xref:refguide:applib-ant:Property.adoc#publishing[`@Property#publishing()`] annotation.
-* a changed object should be published is to annotate it with the xref:refguide:applib-ant:DomainObject.adoc#publishing[`@DomainObject#publishing()`] annotation.
-
-The module also provide services that contribute to the UI.
-If contributions are not required in the UI, these can be suppressed either using security or by implementing a xref:userguide:btb:hints-and-tips/vetoing-visibility.adoc[vetoing subscriber].
-
-
-
-
-
-
-
-== Related Services
-
-This service supports two main use cases:
-
-* coarse-grained publish/subscribe for system-to-system interactions, from Apache Isis to some other system.
-
-* profiling of interactions/transactions, eg to diagnose response/throughput issues.
-
-
-To support these use cases several other services are involved:
-
-* the xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`] is used to obtain the `Interaction` from which the member executions are published.
-
-* the (internal) xref:core:runtime-services:ChangedObjectsService.adoc[`ChangedObjectsService`] domain service is used to obtain the set of objects modified throughout the transaction
-
-* the (internal) xref:core:runtime-services:EntityChangesPublisher.adoc[`EntityChangesPublisher`] domain service filters these down to those changed entities that have `entityChangePublishing` enabled (as per xref:refguide:applib-ant:DomainObject.adoc#entityChangePublishing[`@DomainObject#entityChangePublishing()`]) and publishes to any `EntityChangesSubscriber`.
-
-* the xref:refguide:applib-svc:MetricsService.adoc[`MetricsService`] is used to obtain the objects that are loaded throughout the transaction; this info is used in order to instantiate the `PublishedObjects` object passed through to the `PublisherService`.
-
-
-The services provided by this module combine very well with the xref:refguide:applib-svc:CommandSubscriber.adoc[`CommandServiceListener`] and with xref:refguide:applib-svc:AuditerService.adoc[`AuditerService`].
-The ``Command`` captures the __cause__ of an interaction (an action was invoked, a property was edited), while the `PublisherService` captures the __effect__ of that interaction in terms of events, and the `AuditerService` captures the effect of the interaction in terms of changed state.
-You may also want to configure the xref:refguide:applib-svc:ExecutionSubscriber.adoc[`PublisherService`], which also captures the effect of the interaction but as an event.
-All three of these services collaborate implicitly by way of the xref:applib-classes:roles-mixins-contributees/contributee.adoc#HasUniqueId[`HasUniqueId`] interface.
-
-The xref:refguide:applib-svc:EventBusService.adoc[`EventBusService`] differs from the `PublisherService` in that it is intended for fine-grained publish/subscribe for object-to-object interactions within an Apache Isis domain object model.
-The event propagation is strictly in-memory, and there are no restrictions on the object acting as the event; it need not be serializable, for example.
-That said, it is possible to obtain a serialization of the action invocation/property edit causing the current event to be raised using xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`] domain service.
-
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/examples_and_usage.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/examples_and_usage.adoc
index 21f4ba4..6eb0112 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/examples_and_usage.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/examples_and_usage.adoc
@@ -2,3 +2,34 @@
 :Notice: 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 ag [...]
 
 
+== Wrapper Factory
+
+If the xref:refguide:applib-svc:WrapperFactory.adoc[`WrapperFactory`] is used to call other objects then the metrics are captured for each sub-execution.
+
+
+
+
+
+== Related Services
+
+
+See also:
+
+* the xref:refguide:applib-svc:InteractionContext.adoc[`InteractionContext`] is used to obtain the `Interaction` from which the member executions are published.
+
+* the xref:system:generated:index/applib/services/publishing/spi/EntityChangesSubscriber.adoc[EntityChangesSubscriber] is used to obtain the set of objects modified within the interaction
+
+* the xref:refguide:applib-svc:MetricsService.adoc[`MetricsService`] is used to obtain the objects that are loaded throughout the transaction; this info is used in order to instantiate the xref:system:generated:index/applib/services/publishing/spi/EntityChanges.adoc[EntityChanges] object passed through to the xref:system:generated:index/applib/services/publishing/spi/EntityChangesSubscriber.adoc[EntityChangesSubscriber].
+
+* The services provided by this module combine very well with the xref:system:generated:index/applib/services/publishing/spi/CommandSubscriber.adoc[CommandSubscriber] and with xref:system:generated:index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc[EntityPropertyChangeSubscriber].
++
+The xref:system:generated:index/applib/services/command/Command.adoc[Command]  captures the __cause__ of an interaction (an action was invoked, a property was edited), while the xref:system:generated:index/applib/services/publishing/spi/ExecutionSubscriber.adoc[ExecutionSubscriber] captures the __effect__ of that interaction in terms of events, while the xref:system:generated:index/applib/services/publishing/spi/EntityPropertyChangeSubscriber.adoc[EntityPropertyChangeSubscriber] captures [...]
+
+All of these services collaborate implicitly by way of the xref:system:generated:index/commons/having/HasUniqueId.adoc[HasUniqueId] interface.
+
+In contrast:
+
+* The xref:system:generated:index/applib/services/eventbus/EventBusService.adoc[EventBusService] differs from the xref:system:generated:index/applib/services/publishing/spi/ExecutionSubscriber.adoc[ExecutionSubscriber] in that the former is intended for fine-grained publish/subscribe for object-to-object interactions _within_ an Apache Isis domain object model.
++
+The event propagation is strictly in-memory, and there are no restrictions on the object acting as the event; it need not be serializable, for example.
+
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/implementation.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/implementation.adoc
index fa61296..e1b9dbf 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/implementation.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ExecutionSubscriber/hooks/implementation.adoc
@@ -5,7 +5,29 @@
 
 == Implementation
 
-This is an SPI, but the framework provides a simple implementation, `o.a.i.applib.services.publishing.log.ExecutionLogger`, that just logs events as they are received.
-
+The framework allows multiple implementations of this service to be registered; all will be called.
 
+This is an SPI, but the framework provides a simple implementation, `o.a.i.applib.services.publishing.log.ExecutionLogger`, that just logs events as they are received.
 
+It can be configured using:
+
+[source,xml]
+.log4j2-spring.xml
+----
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="WARN">
+  <Properties> ... </Properties>
+  <Appenders> ... </Appenders>
+  <Loggers>
+    ...
+    <logger
+      name="org.apache.isis.applib.services.publishing.log.ExecutionLogger"
+      level="debug"/>
+    ...
+  </Loggers>
+</Configuration>
+----
+
+See the `log4j2-spring.xml` file in xref:docs:starters:simpleapp.adoc[simpleapp] for the omitted detail.
+
+//* the xref:mappings:outbox-publisher:about.adoc[Outbox Publisher] in the xref:mappings:ROOT:about.adoc[Mappings catalog] persists each interaction into a link:https://microservices.io/patterns/data/transactional-outbox.html[outbox table] for subsequent processing.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService.adoc
index 71ed3ae..5a18b9d 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService.adoc
@@ -4,81 +4,11 @@
 :Notice: 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 ag [...]
 
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
-
-
-The `FactoryService` collects together methods for instantiating domain objects.
-
-== API
 
 include::system:generated:page$index/applib/services/factory/FactoryService.adoc[leveloffset=+2]
 
-TODO example migration
-
-.Deprecated Docs
-[WARNING]
-================================
-
-== API
-
-The API of `FactoryService` is:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/factory/FactoryService.java[tags="refguide"]
-----
-<.> General purpose factory method, to automatically get or create an instance of the required type.
-Maps onto one of the specialized factory methods `#get(Class)` or `#create(Class)` based on the type's meta-data.
-<.> Gets an instance (possibly shared or independent) of the specified type, with injection points resolved and any life-cycle callback processed.
-<.> Creates a new detached (not yet persisted) entity instance, with injection points resolved and defaults applied.
-The class must have a no-arg constructor (for xref:pjdo:ROOT:about.adoc[JDO/DataNucleus], the enhancer adds this automatically).
-<.> Resolves injection points for given entity.
-<.> Creates a new Mixin instance, with injection points resolved.
-The class must have a 1-arg constructor of the appropriate type.
-<.> Creates a new ViewModel instance, with injection points resolved, and initialized according to the given memento string.
-<.> Creates a new ViewModel instance, with injection points resolved and defaults applied.
-<.> Resolves injection points for given ViewModel instance.
-<.> Creates a new instance of the specified class, with injection points resolved and defaults applied.
-
-
-
-The object is created in memory, but (if an entity) is not persisted.
-The benefits of using this method (instead of simply using the Java `new` keyword) are:
-
-* any services will be injected into the object immediately (otherwise they will not be injected until the frameworkbecomes aware of the object, typically when it is persisted through the xref:refguide:applib-svc:RepositoryService.adoc[`RepositoryService`]
-
-* the default value for any properties (usually as specified by `defaultXxx()` supporting methods) or from the value type itself will be set and the `created()` callback will be called.
-
-An alternative idiom is to just `new` up the object and then use  xref:refguide:applib-svc:ServiceInjector.adoc[`ServiceInjector`] domain service can be used to inject services into the domain object.
-Note though that no default values will be set on the created object.
-
-
-
-
-================================
-
-== Usage
-
-For example:
-
-[source,java]
-----
-Customer cust = factoryService.detachedEntity(Customer.class);
-cust.setFirstName("Freddie");
-cust.setLastName("Mercury");
-repositoryService.persist(cust);
-----
-
-
-== Implementation
-
-The core framework provides a default implementation of this service (`o.a.i.core.metamodel.services.factory.FactoryServiceDefault`).
-
-
-
+include::FactoryService/hooks/implementation.adoc[]
 
-== Related Services
+include::FactoryService/hooks/examples_and_usage.adoc[]
 
-The xref:refguide:applib-svc:RepositoryService.adoc[`RepositoryService`] is often used in conjunction with the `FactoryService`, to persist domain objects after they have been instantiated and populated.
 
-An alternative to using the factory service is to simply instantiate the object ("new is the new new") and then use the xref:refguide:applib-svc:ServiceRegistry.adoc[`ServiceRegistry`] service to inject other domain services into the instantiated object.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/examples_and_usage.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/examples_and_usage.adoc
index 21f4ba4..b61927b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/examples_and_usage.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/examples_and_usage.adoc
@@ -2,3 +2,33 @@
 :Notice: 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 ag [...]
 
 
+== Usage
+
+The benefits of using this method (instead of simply using the Java `new` keyword) are:
+
+* any services will be injected into the object immediately (otherwise they will not be injected until the framework becomes aware of the object, typically when it is persisted through the xref:system:generated:index/applib/services/repository/RepositoryService.adoc[`RepositoryService`]
+
+* the default value for any properties (usually as specified by `defaultXxx()` supporting methods) or from the value type itself will be set and the `created()` callback will be called.
+
+An alternative idiom is to just `new` up the object and then use xref:system:generated:index/applib/services/inject/ServiceInjector.adoc[ServiceInjector] domain service can be used to inject services into the domain object.
+Note though that no default values will be set on the created object.
+
+
+== Example
+
+For example:
+
+[source,java]
+----
+Customer cust = factoryService.detachedEntity(Customer.class);
+cust.setFirstName("Freddie");
+cust.setLastName("Mercury");
+repositoryService.persist(cust);
+----
+
+
+== Related Services
+
+See also:
+
+* The xref:system:generated:index/applib/services/repository/RepositoryService.adoc[RepositoryService] is often used in conjunction with the `FactoryService`, to persist domain objects after they have been instantiated and populated.
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/implementation.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/implementation.adoc
index 697f559..9755aa5 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/implementation.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/FactoryService/hooks/implementation.adoc
@@ -4,3 +4,5 @@
 
 
 == Implementation
+
+The core framework provides a default implementation of this service (`o.a.i.core.metamodel.services.factory.FactoryServiceDefault`).
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService.adoc
index b8a3daf..b71e46a 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService.adoc
@@ -4,47 +4,15 @@
 :Notice: 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 ag [...]
 
 
-WARNING: TODO: this content has not yet been reviewed/updated for v2.0
-
-The `GridLoaderService` provides the ability to load the XML layout (grid) for a domain class.
-
-== API
-
 include::system:generated:page$index/applib/services/grid/GridLoaderService.adoc[leveloffset=+2]
 
-TODO example migration
-
-.Deprecated Docs
-[WARNING]
-================================
-
-== SPI
-
-The SPI defined by this service is:
-
-[source,java]
-----
-include::refguide:applib-svc:example$services/grid/GridLoaderService.java[tags="refguide"]
-----
-<.> whether dynamic reloading of layouts is enabled.  The default implementation enables reloading for prototyping, disables in production
-<.> support metamodel invalidation/rebuilding of spec, eg as called by this xref:applib-classes:about.adoc#rebuildMetamodel[Object mixin] action.
-<.> whether any persisted layout metadata (eg a `.layout.xml` file) exists for this domain class.
-<.> returns a new instance of a xref:applib-classes:layout.adoc#component[`Grid`] for the specified domain class, eg as loaded from a `layout.xml` file.
-If none exists, will return null (and the calling xref:refguide:applib-svc:GridService.adoc[`GridService`] will use xref:refguide:applib-svc:GridSystemService.adoc[`GridSystemService`] to obtain a default grid for the domain class).
-<.> Load a specific layout alternative, eg if specified through a `layout()` supporting method of the domain object itself.
-
-
-================================
-
-== Implementation
-
-The framework provides a default implementation of this service, namely `GridLoaderServiceDefault`.  This implementation
-loads the grid from its serialized representation as a `.layout.xml` file, loaded from the classpath.
-
-For example, the layout for a domain class `com.mycompany.myapp.Customer` would be loaded from `com/mycompany/myapp/Customer.layout.xml`.
-
+include::GridLoaderService/hooks/implementation.adoc[]
 
+include::GridLoaderService/hooks/examples_and_usage.adoc[]
 
 == Related Services
 
-This service is used by xref:refguide:applib-svc:GridService.adoc[`GridService`].
+See also:
+
+* xref:system:generated:index/applib/services/grid/GridService.adoc[GridService]
+* xref:system:generated:index/applib/services/grid/GridLoaderService.adoc[GridLoaderService]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService/hooks/implementation.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService/hooks/implementation.adoc
index 697f559..67d2212 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService/hooks/implementation.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/GridLoaderService/hooks/implementation.adoc
@@ -1,6 +1,10 @@
-
 :Notice: 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 ag [...]
 
 
 
 == Implementation
+
+The framework provides a default implementation of this service, namely `GridLoaderServiceDefault`.
+This implementation loads the grid from its serialized representation as a `.layout.xml` file, loaded from the classpath.
+
+For example, the layout for a domain class `com.mycompany.myapp.Customer` would be loaded from `com/mycompany/myapp/Customer.layout.xml`.
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
index 51f874c..2faa4e9 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
@@ -313,8 +313,8 @@ public class Command implements HasUniqueId, HasUsername, HasCommandDto {
          */
         @Override
         public void setResult(final Result<Bookmark> resultBookmark) {
-            Command.this.result = resultBookmark.value().orElse(null);
-            Command.this.exception = resultBookmark.failure().orElse(null);
+            Command.this.result = resultBookmark.getValue().orElse(null);
+            Command.this.exception = resultBookmark.getFailure().orElse(null);
         }
 
         /**
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerService.java b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerService.java
index 9ef0ced..e9e2e5e 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/ExceptionRecognizerService.java
@@ -23,6 +23,9 @@ import java.util.Optional;
 import org.apache.isis.commons.collections.Can;
 
 /**
+ * Used by the framework to iterate over all registered
+ * {@link ExceptionRecognizer}s in the correct order.
+ *
  * @since 1.x {@index}
  */
 public interface ExceptionRecognizerService {
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/Recognition.java b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/Recognition.java
index 551d1e2..d345505 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/Recognition.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/exceprecog/Recognition.java
@@ -41,6 +41,14 @@ public class Recognition {
      * Categorises the exception as per {@link Category}.
      *
      * <p>
+     * In essence, if an exception is recognized then it is also categorized.
+     * This lets the viewer act accordingly.
+     *
+     * If the implementation recognizes the exception then it returns a user-friendly message to be rendered (by the viewer) back to the user; otherwise it returns `null`.
+     * There is no need for the implementation to check for exception causes; the casual chain is unwrapped by Apache Isis core and each exception in the chain will also be passed through to the recognizer (from most specific to least).
+     * The recognizer implementation can therefore be as fine-grained or as coarse-grained as it wishes.
+     * </p>
+     * <p>
      *     This category can also optionally be used in the translation of the
      *     {@link #getReason() reason} for the exception.
      * </p>
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java b/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
index 47cd730..665f96f 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/factory/FactoryService.java
@@ -29,6 +29,9 @@ import org.apache.isis.applib.services.repository.RepositoryService;
 import lombok.NonNull;
 
 /**
+ * Collects together methods for instantiating domain objects, also injecting
+ * them with any domain services and calling lifecycle methods if defined.
+ *
  * @since 1.x {@index}
  */
 public interface FactoryService {
@@ -51,6 +54,14 @@ public interface FactoryService {
      * @since 2.0
      *
      */
+
+    /**
+     * Gets an instance (possibly shared or independent) of the specified type, with injection points resolved and any
+     * life-cycle callback processed.
+     * @param requiredType
+     * @param <T>
+     * @return
+     */
     <T> T getOrCreate(@NonNull Class<T> requiredType);
 
     /**
@@ -75,6 +86,10 @@ public interface FactoryService {
      * Creates a new detached entity instance, with injection points resolved
      * and defaults applied.
      *
+     * <p>
+     *     The entity will be detacted, in other words not yet persisted.
+     * </p>
+     *
      * @param <T>
      * @param domainClass - only applicable to entity types
      * @throws IllegalArgumentException if domainClass is not an entity type
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridLoaderService.java b/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridLoaderService.java
index cf44e72..bb0230c 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridLoaderService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/grid/GridLoaderService.java
@@ -21,22 +21,38 @@ package org.apache.isis.applib.services.grid;
 import org.apache.isis.applib.layout.grid.Grid;
 
 /**
+ * Provides the ability to load the XML layout (grid) for a domain class.
+ *
  * @since 1.x {@index}
  */
 public interface GridLoaderService {
 
     /**
      * Whether dynamic reloading of layouts is enabled.
+     *
+     * <p>
+     *     The default implementation enables reloading for prototyping mode,
+     *     disables in production
+     * </p>
      */
     boolean supportsReloading();
 
     /**
      * To support metamodel invalidation/rebuilding of spec.
+     *
+     * <p>
+     *     This is called by the {@link org.apache.isis.applib.mixins.layout.Object_rebuildMetamodel} mixin action.
+     * </p>
      */
     void remove(Class<?> domainClass);
 
     /**
      * Whether any persisted layout metadata (eg a <code>.layout.xml</code> file) exists for this domain class.
+     *
+     * <p>
+     *     If none exists, will return null (and the calling {@link GridService}  will use {@link GridSystemService}
+     *     to obtain a default grid for the domain class).
+     * </p>
      */
     boolean existsFor(Class<?> domainClass);
 
@@ -49,8 +65,15 @@ public interface GridLoaderService {
     }
 
     /**
-     * Returns a new instance of a {@link Grid} for the specified domain class, eg from a
-     * <code>layout.xml</code> file, else <code>null</code>.
+     * Loads a specic alternative {@link Grid} layout for the specified domain
+     * class.
+     *
+     * <p>
+     *     The layout alternative will typically be specified through a
+     *     `layout()` method on the domain object, the value of which is used
+     *     for the suffix of the layout file (eg "Customer-layout.archived.xml"
+     *     to use a different layout for customers that have been archived).
+     * </p>
      */
     Grid load(
             final Class<?> domainClass,
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChanges.java b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChanges.java
index 6460c4f..ff772de 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChanges.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChanges.java
@@ -19,28 +19,87 @@
 package org.apache.isis.applib.services.publishing.spi;
 
 import java.sql.Timestamp;
+import java.util.UUID;
 
 import org.apache.isis.commons.having.HasUniqueId;
 import org.apache.isis.commons.having.HasUsername;
 import org.apache.isis.schema.chg.v2.ChangesDto;
 
 /**
- * 
+ * As used by {@link EntityChangesSubscriber}, provides metrics on the
+ * &quot;footprint&quot; of an interaction, in other words the number of
+ * objects accessed or changed.
+ *
+ * <p>
+ *  The numbers of objects loaded, created, updated or deleted and the number
+ *  of object properties modified (in other words the "size" or "weight" of the transaction).
+ * </p>
  * @since 2.0 {@index}
  */
 public interface EntityChanges
         extends HasUniqueId,
                 HasUsername {
 
+    /**
+     * inherited from {@link HasUniqueId}, correlates back to the unique
+     * identifier of the transaction in which these objects were changed.
+     */
+    @Override
+    UUID getUniqueId();
+
+    /**
+     * Inherited from {@link HasUsername}, is the user that initiated the
+     * transaction causing these objects to change.
+     * @return
+     */
+    @Override
+    String getUsername();
+
+    /**
+     * Time that the interaction execution completed
+     * @return
+     */
     Timestamp getCompletedAt();
 
+    /**
+     * Number of domain objects loaded in this interaction
+     * @return
+     */
     int getNumberLoaded();
+
+    /**
+     * Number of domain objects created in this interaction
+     * @return
+     */
     int getNumberCreated();
+
+    /**
+     * Number of domain objects updated in this interaction
+     * @return
+     */
     int getNumberUpdated();
+
+    /**
+     * Number of domain objects deleted in this interaction
+     * @return
+     */
     int getNumberDeleted();
 
+    /**
+     * Number of domain objects properties that were changed in this interaction
+     * @return
+     */
     int getNumberPropertiesModified();
 
+    /**
+     * Same details, but as an an instance of {@link ChangesDto}.
+     *
+     * <p>
+     * This can be converted into a serializable XML representation using the
+     * {@link org.apache.isis.applib.util.schema.ChangesDtoUtils} utility class.
+     * </p>
+     *
+     * @return
+     */
     ChangesDto getDto();
-
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChangesSubscriber.java b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChangesSubscriber.java
index 6e40a23..77c91f4 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChangesSubscriber.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/EntityChangesSubscriber.java
@@ -22,8 +22,14 @@ import org.apache.isis.applib.annotation.DomainObject;
 import org.apache.isis.commons.having.HasEnabling;
 
 /**
- * SPI to receive the entire set of entities that are about to change as the
- * result of a transaction.
+ * SPI to receive a summary of the number of entities that have changed as the
+ * result of an interaction (action invocation or property edit).
+ *
+ * <p>
+ * One use case is for performance profiling: to determine the
+ * &quot;footprint&quot; of an interaction, which will have a direct impact on
+ * the response time of that interaction.
+ * </p>
  *
  * <p>
  *     Only those entities that have publishing enabled (using
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/ExecutionSubscriber.java b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/ExecutionSubscriber.java
index 1b63ece..b141b31 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/ExecutionSubscriber.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/publishing/spi/ExecutionSubscriber.java
@@ -18,29 +18,54 @@
  */
 package org.apache.isis.applib.services.publishing.spi;
 
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.services.iactn.Interaction;
 import org.apache.isis.applib.util.schema.InteractionDtoUtils;
 import org.apache.isis.commons.having.HasEnabling;
 
 /**
- * SPI that allows individual interactions (action invocations or property edits) to be
- * {@link #onExecution(Interaction.Execution) published}.
- * Note that re-publishing is not part of this SPI.
- * 
+ * SPI that allows the execution of individual interactions (action invocations
+ * or property edits) to be subscribed to.
+ *
+ * <p>
+ *  The typical use case is to facilitate coarse-grained messaging for
+ *  system-to-system interactions, that is from an Apache Isis application to
+ *  some other system.  This could be done using a pub/sub bus such as
+ *  <a href="http://activemq.apache.org">Apache ActiveMQ</a> with
+ *  <a href="http://camel.apache.org">Apache Camel</a>.
+ * </p>
+ *
+ * <p>
+ *     Only actions/properties annotated for publishing (using
+ *     {@link Action#executionPublishing()} or
+ *     {@link Property#executionPublishing()} are published.
+ * </p>
+ *
  * @since 2.0 {@index}
  */
 public interface ExecutionSubscriber extends HasEnabling {
 
     /**
-     * Publish each {@link org.apache.isis.applib.services.iactn.Interaction.Execution} 
-     * immediately after it completes.
+     * Callback to notify that an interaction (an action invocation or property
+     * edit, as represented by
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution}) has
+     * completed.
+     *
      * <p>
-     * Most implementations are expected to use 
-     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getDto()} to create a serializable
-     * XML representation of the execution. The easiest way to do this is using 
+     *     This callback method is called by the framework immediately after
+     *     the interaction (not at the end of the transaction, unlike some of
+     *     the other subscribers).
+     * </p>
+     *
+     * <p>
+     * Most implementations are expected to use
+     * {@link org.apache.isis.applib.services.iactn.Interaction.Execution#getDto()}
+     * to create a serializable XML representation of the execution.
+     * The easiest way to do this is using
      * {@link InteractionDtoUtils#newInteractionDto(Interaction.Execution)}.
-     * There is some flexibility here, though.
+     * </p>
      */
     void onExecution(Interaction.Execution<?, ?> execution);
-    
+
 }
diff --git a/build-tooling.sh b/build-tooling.sh
new file mode 100644
index 0000000..9dd210d
--- /dev/null
+++ b/build-tooling.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+SKIP_TESTS=false
+
+while getopts 'th' opt
+do
+  case $opt in
+    t) export SKIP_TESTS=true
+       ;;
+    h) echo ""
+       echo "build-tooling.sh options:"
+       echo ""
+       echo "  Skip options:"
+       echo "  -t : skip tests"
+       echo ""
+       exit 1
+       ;;
+    *) echo "unknown option $opt - aborting" >&2
+       exit 1
+      ;;
+  esac
+done
+
+echo ""
+echo "SKIP_TESTS : $SKIP_TESTS"
+
+OPTS=""
+if [[ "$SKIP_TESTS" == "true" ]]; then
+  OPTS="$OPTS -DskipTests "
+fi
+
+mvnd -Dmodule-tooling -Dskip.essential $OPTS install
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/ExceptionRecognizerServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/ExceptionRecognizerServiceDefault.java
index 12a04b3..2b38779 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/ExceptionRecognizerServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/ExceptionRecognizerServiceDefault.java
@@ -30,7 +30,7 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
-import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer.Recognition;
+import org.apache.isis.applib.services.exceprecog.Recognition;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.commons.collections.Can;
@@ -41,7 +41,7 @@ import lombok.NonNull;
 import lombok.val;
 
 /**
- * 
+ *
  * @since 2.0
  *
  */
@@ -50,11 +50,11 @@ import lombok.val;
 @Order(OrderPrecedence.MIDPOINT)
 @Primary
 @Qualifier("Default")
-public class ExceptionRecognizerServiceDefault 
+public class ExceptionRecognizerServiceDefault
 implements ExceptionRecognizerService {
 
     @Inject private ServiceRegistry serviceRegistry;
-    
+
     @Override
     public Can<ExceptionRecognizer> getExceptionRecognizers() {
         return exceptionRecognizers.get();
@@ -64,42 +64,42 @@ implements ExceptionRecognizerService {
     public Optional<Recognition> recognizeFromSelected(
             @NonNull final Can<ExceptionRecognizer> recognizers,
             @NonNull final Throwable ex) {
-        
+
         return _Exceptions.streamCausalChain(ex)
         .map(nextEx->recognize(recognizers, nextEx))
         .filter(Optional::isPresent)
         .findFirst()
         .orElse(Optional.empty());
     }
-    
+
     // -- HELPER
-    
-    private final _Lazy<Can<ExceptionRecognizer>> exceptionRecognizers = 
+
+    private final _Lazy<Can<ExceptionRecognizer>> exceptionRecognizers =
             _Lazy.threadSafe(()->serviceRegistry.select(ExceptionRecognizer.class));
 
     private static Optional<Recognition> recognize(
-            final Can<ExceptionRecognizer> recognizers, 
+            final Can<ExceptionRecognizer> recognizers,
             final Throwable ex) {
-        
+
         return recognizers.stream()
         .map(recognizer->recognize(recognizer, ex))
         .filter(Optional::isPresent)
         .findFirst()
         .orElse(Optional.empty());
     }
-    
+
     /*
      * handle recognizers in a null-safe manner (might be third party contributed)
      */
     private static Optional<Recognition> recognize(
-            final ExceptionRecognizer recognizer, 
+            final ExceptionRecognizer recognizer,
             final Throwable ex) {
-        
+
         val recognized = recognizer.recognize(ex);
         return recognized==null
                 ? Optional.empty()
                 : recognized;
     }
-    
-    
+
+
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
index f86c298..857fd5d 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/ExceptionRecognizerForDataAccessException.java
@@ -21,13 +21,14 @@ package org.apache.isis.core.runtimeservices.recognizer.dae;
 import java.util.function.Function;
 import java.util.function.Predicate;
 
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerForType;
 import org.apache.isis.core.config.IsisConfiguration;
 
 /**
  * Common to those that can be disabled via IsisConfiguration.
  */
-public abstract class ExceptionRecognizerForDataAccessException 
+public abstract class ExceptionRecognizerForDataAccessException
 extends ExceptionRecognizerForType {
 
     protected ExceptionRecognizerForDataAccessException(
@@ -36,7 +37,7 @@ extends ExceptionRecognizerForType {
             final Predicate<Throwable> predicate,
             final Function<Throwable, String> rootCauseMessageFormatter) {
         super(category, predicate, rootCauseMessageFormatter);
-        
+
         super.setDisabled(
                 isisConfiguration.getCore().getRuntimeServices()
                 .getExceptionRecognizer().getDae().isDisable());
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForDataAlreadyExists.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForDataAlreadyExists.java
index 5b2aebe..cff5e5b 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForDataAlreadyExists.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForDataAlreadyExists.java
@@ -26,13 +26,14 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
 
 /**
- * Handles exceptions like {@literal org.springframework.dao.DataIntegrityViolationException: JDO operation: Insert of object "domainapp.modules.hello.dom.hwo.HelloWorldObject@6cad4834" using statement "INSERT INTO "hello"."HelloWorldObject" ("name","notes","version") VALUES (?,?,?)" failed : Unique index or primary key violation: "hello.HelloWorldObject_name_UNQ_INDEX_B ON hello.HelloWorldObject(name) VALUES 1"; SQL statement:} 
- * <p> 
- * TODO: should not be sensitive to 'NOT NULL check constraint' ... don't know whether this can ever happen 
+ * Handles exceptions like {@literal org.springframework.dao.DataIntegrityViolationException: JDO operation: Insert of object "domainapp.modules.hello.dom.hwo.HelloWorldObject@6cad4834" using statement "INSERT INTO "hello"."HelloWorldObject" ("name","notes","version") VALUES (?,?,?)" failed : Unique index or primary key violation: "hello.HelloWorldObject_name_UNQ_INDEX_B ON hello.HelloWorldObject(name) VALUES 1"; SQL statement:}
+ * <p>
+ * TODO: should not be sensitive to 'NOT NULL check constraint' ... don't know whether this can ever happen
  * @since 2.0
  */
 @Service
@@ -44,9 +45,9 @@ extends ExceptionRecognizerForDataAccessException {
 
     @Inject
     public ExceptionRecognizerForDataAlreadyExists(IsisConfiguration conf) {
-        //XXX used prefix could be made a config option 
+        //XXX used prefix could be made a config option
         // under isis.core.runtimeservices.exception-recognizers.dae
-        super(conf, 
+        super(conf,
                 Category.CONSTRAINT_VIOLATION,
                 ofType(org.springframework.dao.DataIntegrityViolationException.class)
                 .and(including("Unique index or primary key violation")),
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForObjectNotFound.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForObjectNotFound.java
index f6d8307..b73500c 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForObjectNotFound.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForObjectNotFound.java
@@ -26,6 +26,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
 
@@ -38,9 +39,9 @@ extends ExceptionRecognizerForDataAccessException {
 
     @Inject
     public ExceptionRecognizerForObjectNotFound(IsisConfiguration conf) {
-        //XXX used prefix could be made a config option 
+        //XXX used prefix could be made a config option
         // under isis.core.runtimeservices.exception-recognizers.dae
-        super(conf, 
+        super(conf,
                 Category.NOT_FOUND,
                 ofType(org.springframework.dao.DataAccessException.class)
                 .and(including("TODO")), //TODO add magic words
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
index f6fd0d5..7068973 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForOtherDataAccessProblem.java
@@ -29,6 +29,7 @@ import org.springframework.dao.DataAccessException;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
@@ -36,8 +37,8 @@ import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerFo
 import lombok.val;
 
 /**
- * Recognizes exceptions of type {@link DataAccessException} if no one else does (fallback). 
- *  
+ * Recognizes exceptions of type {@link DataAccessException} if no one else does (fallback).
+ *
  * @since 2.0 {@index}
  */
 @Service
@@ -49,22 +50,22 @@ extends ExceptionRecognizerForDataAccessException {
 
     @Inject
     public ExceptionRecognizerForOtherDataAccessProblem(IsisConfiguration conf) {
-        //XXX used prefix could be made a config option 
-        // under isis.core.runtimeservices.exception-recognizers.dae 
+        //XXX used prefix could be made a config option
+        // under isis.core.runtimeservices.exception-recognizers.dae
         super(conf,
                 Category.OTHER,
                 ofType(org.springframework.dao.DataAccessException.class),
-                rootCause->toMessage(rootCause)); 
+                rootCause->toMessage(rootCause));
     }
 
     private static String toMessage(Throwable rootCause) {
-        
+
         val causalInfo = _Exceptions.getCausalChain(rootCause)
         .stream()
         .skip(1L)
         .map(ex->String.format("%s: %s", ex.getClass().getSimpleName(), ex.getMessage()))
         .collect(Collectors.joining(", "));
-        
+
         return causalInfo.isEmpty()
                 ? String.format(
                         "An unrecognized data access problem has occurred: %s\ncaused by %s",
@@ -76,6 +77,6 @@ extends ExceptionRecognizerForDataAccessException {
                         rootCause.getMessage(),
                         causalInfo);
     }
-    
-    
+
+
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForRelatedDataExists.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForRelatedDataExists.java
index 8ca9297..7a0b18a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForRelatedDataExists.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForRelatedDataExists.java
@@ -26,6 +26,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
 
@@ -38,9 +39,9 @@ extends ExceptionRecognizerForDataAccessException {
 
     @Inject
     public ExceptionRecognizerForRelatedDataExists(final IsisConfiguration conf) {
-        //XXX used prefix could be made a config option 
+        //XXX used prefix could be made a config option
         // under isis.core.runtimeservices.exception-recognizers.dae
-        super(conf, 
+        super(conf,
                 Category.CONSTRAINT_VIOLATION,
                 ofType(org.springframework.dao.DataAccessException.class)
                 .and(including(
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForUnableToSaveData.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForUnableToSaveData.java
index 519765d..6913ec3 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForUnableToSaveData.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/recognizer/dae/impl/ExceptionRecognizerForUnableToSaveData.java
@@ -26,6 +26,7 @@ import org.springframework.core.annotation.Order;
 import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.OrderPrecedence;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.core.config.IsisConfiguration;
 import org.apache.isis.core.runtimeservices.recognizer.dae.ExceptionRecognizerForDataAccessException;
 
@@ -38,7 +39,7 @@ extends ExceptionRecognizerForDataAccessException {
 
     @Inject
     public ExceptionRecognizerForUnableToSaveData(IsisConfiguration conf) {
-        //XXX used prefix could be made a config option 
+        //XXX used prefix could be made a config option
         // under isis.core.runtimeservices.exception-recognizers.dae
         super(conf,
                 Category.SERVER_ERROR,
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
index b1e0656..4baf5a4 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
@@ -33,6 +33,7 @@ import org.apache.isis.applib.exceptions.unrecoverable.ObjectNotFoundException;
 import org.apache.isis.applib.query.AllInstancesQuery;
 import org.apache.isis.applib.query.NamedQuery;
 import org.apache.isis.applib.query.Query;
+import org.apache.isis.applib.services.exceprecog.Category;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
 import org.apache.isis.applib.services.repository.EntityState;
@@ -137,7 +138,7 @@ implements EntityFacet {
 
             val recognition = exceptionRecognizerService.recognize(e);
             if(recognition.isPresent()) {
-                if(recognition.get().getCategory() == ExceptionRecognizer.Category.NOT_FOUND) {
+                if(recognition.get().getCategory() == Category.NOT_FOUND) {
                     throw new ObjectNotFoundException(""+rootOid, e);
                 }
             }
diff --git a/preview.sh b/preview.sh
index ecf4332..5d2fc67 100644
--- a/preview.sh
+++ b/preview.sh
@@ -12,14 +12,14 @@ export ANTORA_TARGET_SITE=antora/target/site
 #
 PLAYBOOK_FILE=antora/playbooks/site.yml
 
-while getopts 'ECPAKSecpaksxyhf:' opt
+while getopts 'ECDAKSecdaksxyhf:' opt
 do
   case $opt in
     E) export SKIP_EXAMPLES=false
        forcing=true ;;
     C) export SKIP_CONFIGS=false
        forcing=true ;;
-    P) export SKIP_PROJDOC_GENERATION=false
+    D) export SKIP_PROJDOC_GENERATION=false
        forcing=true ;;
     A) export SKIP_ANTORA_GENERATION=false
        export SKIP_CLEAR_CACHE=false
@@ -32,7 +32,7 @@ do
 
     e) export SKIP_EXAMPLES=true ;;
     c) export SKIP_CONFIGS=true ;;
-    p) export SKIP_PROJDOC_GENERATION=true ;;
+    d) export SKIP_PROJDOC_GENERATION=true ;;
     a) export SKIP_ANTORA_GENERATION=true
        export SKIP_CLEAR_CACHE=true
        export SKIP_CLEAR_PREVIOUS=true
@@ -50,7 +50,7 @@ do
        echo "  -e skip examples"
        echo "  -k skip stale example check"
        echo "  -c skip config doc generation"
-       echo "  -w skip projdoc generation"
+       echo "  -d skip projdoc generation"
        echo "  -a skip Antora generation"
        echo "  -s skip serving generated site"
        echo ""
@@ -58,7 +58,7 @@ do
        echo "  -E force examples"
        echo "  -K force stale example check"
        echo "  -C force config doc generation"
-       echo "  -P force projdoc generation"
+       echo "  -D force projdoc generation"
        echo "  -A force Antora generation"
        echo "  -S force serving generated site"
        echo ""
diff --git a/stty.exe.stackdump b/stty.exe.stackdump
new file mode 100644
index 0000000..260de1b
--- /dev/null
+++ b/stty.exe.stackdump
@@ -0,0 +1,11 @@
+Stack trace:
+Frame        Function    Args
+00800000010  0018006401E (0018027DF10, 0018026EFD1, 00800000010, 000FFFFBA60)
+00800000010  0018004973A (00100002000, 000FFFFCC00, 00180353B80, 00000000000)
+00800000010  00180049772 (00000000000, 00180353E90, 00800000010, 000FFFFCB90)
+00800000010  0018005CDBD (000FFFFCCE0, 000FFFFCC99, 00000000000, 000FFFFCC90)
+000FFFFCC0C  0018005CF06 (0000000000C, 00000000000, FFFFFFFFFFFFFFFF, 00000000000)
+000FFFFCCE0  00180049EE8 (00000000000, 00000000000, 00000000000, 00000000000)
+000FFFFFFF0  00180048846 (00000000000, 00000000000, 00000000000, 00000000000)
+000FFFFFFF0  001800488F4 (00000000000, 00000000000, 00000000000, 00000000000)
+End of stack trace