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 2018/02/14 13:12:09 UTC

[isis] 01/02: Merge branch 'maint-1.16.1' into master

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

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

commit 97013ecec28a2987ef8a5f7de1d0460227de8aab
Merge: de41037 392d475
Author: Dan Haywood <da...@haywood-associates.co.uk>
AuthorDate: Wed Feb 14 12:46:22 2018 +0000

    Merge branch 'maint-1.16.1' into master
    
    # Conflicts:
    #	adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-DomainObject_objectType.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Parameter.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-ViewModel_objectType.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-api_BulkInteractionContext.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-spi_CommandService.adoc
    #	adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_metadata-api_MetamodelService.adoc
    #	adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_programming-model_actions.adoc
    #	adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_ui-hints_eager-rendering.adoc
    #	adocs/documentation/src/main/asciidoc/guides/ugvw/_ugvw_layout_file-based.adoc
    #	adocs/documentation/src/main/asciidoc/pages/tg/_tg_pet-clinic.adoc
    #	adocs/documentation/src/main/asciidoc/pages/tg/_tg_stop-scaffolding-start-coding.adoc
    #	core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
    #	core/applib/src/main/java/org/apache/isis/applib/annotation/Bulk.java
    #	core/applib/src/main/java/org/apache/isis/applib/annotation/Command.java
    #	core/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
    #	core/applib/src/main/java/org/apache/isis/applib/annotation/InvokeOn.java
    #	core/applib/src/main/java/org/apache/isis/applib/services/actinvoc/ActionInvocationContext.java
    #	core/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
    #	core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService3.java
    #	core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForCommandAnnotation.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/mustsatisfyspec/MustSatisfySpecificationFacetAbstract.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/parameter/mustsatisfy/MustSatisfySpecificationFacetForMustSatisfyAnnotationOnParameter.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/parameter/mustsatisfy/MustSatisfySpecificationFacetForParameterAnnotation.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/mustsatisfy/MustSatisfySpecificationFacetForMustSatisfyAnnotationOnProperty.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/mustsatisfy/MustSatisfySpecificationFacetForPropertyAnnotation.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
    #	core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
    #	core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/JavaReflectorHelper.java
    #	core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
    #	core/runtime/src/main/java/org/apache/isis/core/runtime/fixturedomainservice/ObjectFixtureFilePersistor.java
    #	core/runtime/src/main/java/org/apache/isis/core/runtime/fixturedomainservice/ObjectFixtureService.java
    #	core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
    #	core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
    #	core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactoryMetamodelRefiner.java
    #	core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
    #	core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java

 .../applib/layout/grid/bootstrap3/bootstrap3.xsd   |   1 +
 .../asciidoc/guides/dg/_dg_asciidoc-syntax.adoc    |  47 +-
 .../_dg_hints-and-tips_datanucleus-enhancer.adoc   |   2 +-
 .../main/asciidoc/guides/dg/_dg_ide_eclipse.adoc   |   2 +-
 .../main/asciidoc/guides/rgant/_rgant-Action.adoc  |  21 +-
 .../guides/rgant/_rgant-Action_associateWith.adoc  |  67 ++
 .../guides/rgant/_rgant-Action_command.adoc        | 397 +++++++++--
 .../guides/rgant/_rgant-Action_hidden.adoc         |   2 +-
 .../guides/rgant/_rgant-Action_publishing.adoc     |   2 +-
 .../guides/rgant/_rgant-Discriminator.adoc         |   4 +-
 ..._rgant-DomainObject_autoCompleteRepository.adoc |   2 +-
 .../rgant/_rgant-DomainObject_publishing.adoc      |   2 +-
 .../guides/rgant/_rgant-DomainService.adoc         |   2 +-
 .../asciidoc/guides/rgant/_rgant-Nullable.adoc     |  10 +-
 .../guides/rgant/_rgant-Parameter_optionality.adoc |   2 +-
 .../guides/rgant/_rgant-PersistenceCapable.adoc    |   4 +-
 .../asciidoc/guides/rgant/_rgant-Property.adoc     |  28 +
 .../rgant/_rgant-PropertyLayout_unchanging.adoc    |   2 +-
 .../guides/rgant/_rgant-Property_command.adoc      | 269 ++++++++
 .../guides/rgant/_rgant-Property_optionality.adoc  |   2 +-
 .../guides/rgant/_rgant-Property_publishing.adoc   |   2 +-
 .../asciidoc/guides/rgant/_rgant-ViewModel.adoc    |   2 +-
 .../guides/rgcfg/_rgcfg_configuring-core.adoc      |  15 +
 .../_rgcms_classes_AppManifest2-bootstrapping.adoc |   4 +-
 ...gcms_classes_domainevent_ActionDomainEvent.adoc |   2 +-
 ..._classes_domainevent_CollectionDomainEvent.adoc |   2 +-
 ...ms_classes_domainevent_PropertyDomainEvent.adoc |   2 +-
 .../guides/rgcms/_rgcms_classes_layout.adoc        |   2 +-
 .../rgcms/_rgcms_classes_value-types_Markup.adoc   |   2 +-
 .../rgcms/_rgcms_methods_reserved_getId.adoc       |   2 +-
 .../asciidoc/guides/rgcms/_rgcms_schema-chg.adoc   |   2 +-
 .../asciidoc/guides/rgcms/_rgcms_schema-cmd.adoc   |  53 +-
 .../guides/rgcms/_rgcms_schema-common.adoc         |  77 ++-
 .../guides/rgsvc/_rgsvc_application-layer-api.adoc |  14 +-
 ...lication-layer-api_ActionInvocationContext.adoc |   8 +-
 ...rgsvc_application-layer-api_CommandContext.adoc |   2 +-
 ...plication-layer-api_CommandExecutorService.adoc |  45 ++
 ...rgsvc_application-layer-spi_CommandService.adoc |  33 +-
 .../_rgsvc_metadata-api_MetamodelService.adoc      |  37 +-
 ...esentation-layer-spi_ContentMappingService.adoc |  53 +-
 ...entation-layer-spi_TableColumnOrderService.adoc |   2 +-
 ...ugfun_building-blocks_events_domain-events.adoc |   2 +-
 ...un_building-blocks_events_lifecycle-events.adoc |   2 +-
 .../_ugfun_building-blocks_events_ui-events.adoc   |   4 +-
 ..._ugfun_getting-started_simpleapp-archetype.adoc |   2 +-
 .../ugfun/_ugfun_programming-model_actions.adoc    |  21 +-
 ...fun_programming-model_domain-services_menu.adoc |  14 +-
 .../_ugfun_programming-model_inject-services.adoc  |   2 +-
 .../ugfun/_ugfun_programming-model_mixins.adoc     |   2 +-
 ...fun_programming-model_mixins_inferred-name.adoc |   2 +-
 .../ugfun/_ugfun_ui-hints_eager-rendering.adoc     |   2 +-
 .../_ugfun_ui-hints_object-titles-and-icons.adoc   |   6 +-
 .../guides/ugodn/_ugodn_hints-and-tips.adoc        |   1 +
 ..._ugodn_hints-and-tips_jdoql-and-timestamps.adoc |  76 +++
 ..._ugtst_bdd-spec-support_writing-a-bdd-spec.adoc |  28 +-
 ...gtst_fixture-scripts_ticking-clock-fixture.adoc |   2 +-
 .../guides/ugvw/_ugvw_layout_file-based.adoc       |  15 +
 adocs/documentation/src/main/asciidoc/index.html   |  11 +-
 .../_migration-notes_1.10.0-to-1.11.0.adoc         |   2 +-
 .../_migration-notes_1.11.0-to-1.12.0.adoc         |   2 +-
 .../_migration-notes_1.12.0-to-1.13.0.adoc         |  12 +-
 .../_migration-notes_1.14.0-to-1.15.0.adoc         |   2 +-
 .../asciidoc/pages/tg/_tg_pet-clinic-extended.adoc |  13 -
 .../src/main/asciidoc/pages/tg/_tg_pet-clinic.adoc | 575 ----------------
 .../tg/_tg_stop-scaffolding-start-coding.adoc      | 744 ---------------------
 .../tutorials/pet-clinic/010-01-login-page.png     | Bin 31965 -> 0 bytes
 .../tutorials/pet-clinic/010-02-home-page.png      | Bin 54415 -> 0 bytes
 .../pet-clinic/010-03-prototyping-menu.png         | Bin 59183 -> 0 bytes
 .../tutorials/pet-clinic/010-04-simpleobjects.png  | Bin 57805 -> 0 bytes
 .../pet-clinic/010-05-simpleobject-list.png        | Bin 29631 -> 0 bytes
 .../pet-clinic/020-01-idea-configuration.png       | Bin 35012 -> 0 bytes
 .../pet-clinic/020-02-idea-configuration.png       | Bin 7430 -> 0 bytes
 .../030-01-idea-configuration-updated.png          | Bin 35122 -> 0 bytes
 .../tutorials/pet-clinic/030-02-updated-app.png    | Bin 32215 -> 0 bytes
 .../040-01-idea-configuration-updated.png          | Bin 35349 -> 0 bytes
 .../tutorials/pet-clinic/050-01-list-all.png       | Bin 33299 -> 0 bytes
 .../tutorials/pet-clinic/050-02-view-pet.png       | Bin 34270 -> 0 bytes
 .../tutorials/pet-clinic/060-01-owners-menu.png    | Bin 65309 -> 0 bytes
 .../tutorials/pet-clinic/060-02-owners-list.png    | Bin 31905 -> 0 bytes
 .../tutorials/pet-clinic/060-03-pets-list.png      | Bin 36166 -> 0 bytes
 .../pet-clinic/060-04-pet-owner-autoComplete.png   | Bin 40468 -> 0 bytes
 .../images/tutorials/pet-clinic/domain-model.png   | Bin 27464 -> 0 bytes
 .../src/main/asciidoc/pages/tg/tg.adoc             | 683 ++++++++++++++++++-
 .../release-notes/_release-notes_1.16.1.adoc       |  24 +
 .../main/asciidoc/release-notes/release-notes.adoc |  11 +-
 .../src/main/asciidoc}/schema/chg/chg-1.1.xsd      |   2 +-
 .../src/main/asciidoc/schema/chg/chg.xsd           |   6 +-
 .../asciidoc/schema/cmd/{cmd.xsd => cmd-1.2.xsd}   |  10 +-
 .../src/main/asciidoc}/schema/cmd/cmd-1.3.xsd      |   2 +-
 .../src/main/asciidoc/schema/cmd/cmd-1.4.xsd       |  39 +-
 .../src/main/asciidoc/schema/cmd/cmd.xsd           |  51 +-
 .../main/asciidoc}/schema/common/common-1.1.xsd    |   2 +-
 .../src/main/asciidoc/schema/common/common.xsd     |  19 +-
 .../asciidoc/schema/ixn/{ixn.xsd => ixn-1.1.xsd}   |  10 +-
 .../src/main/asciidoc}/schema/ixn/ixn-1.2.xsd      |   2 +-
 .../src/main/asciidoc/schema/ixn/ixn-1.3.xsd       |   6 +-
 .../src/main/asciidoc/schema/ixn/ixn.xsd           |  14 +-
 adocs/template/document.html.erb                   |   5 +-
 core/applib/pom.xml                                |   5 +
 .../apache/isis/applib/AppManifestAbstract.java    |  33 +-
 .../org/apache/isis/applib/PropertyResource.java   |   5 +-
 .../org/apache/isis/applib/annotation/Action.java  |  63 ++
 .../isis/applib/annotation/CommandExecuteIn.java   |  24 +-
 .../apache/isis/applib/annotation/InvokeOn.java    |  27 +-
 .../apache/isis/applib/annotation/MemberOrder.java |   2 +-
 .../apache/isis/applib/annotation/Property.java    |  21 +
 .../java/org/apache/isis/applib/clock/Clock.java   |  18 +-
 .../conmap/ContentMappingServiceForCommandDto.java | 152 +++++
 .../ContentMappingServiceForCommandsDto.java       |  91 +++
 .../spi/CommandDtoProcessorService.java}           |  23 +-
 .../isis/applib/fixtures/TickingFixtureClock.java  |  10 +
 .../applib/layout/grid/bootstrap3/BS3TabGroup.java |  15 +
 .../services/actinvoc/ActionInvocationContext.java |  33 +-
 .../isis/applib/services/command/Command.java      |  66 +-
 .../CommandDtoProcessor.java}                      |  30 +-
 .../CommandDtoProcessorForActionAbstract.java      |  41 ++
 .../CommandDtoProcessorForPropertyAbstract.java}   |  28 +-
 .../services/command/CommandExecutorService.java   |  44 +-
 .../applib/services/command/CommandWithDto.java    |  21 +-
 .../services/conmap/ContentMappingService.java     |  27 +
 .../services/eventbus/AbstractDomainEvent.java     |  12 +
 .../services/layout/Object_rebuildMetamodel.java   |   2 +
 .../services/metamodel/MetaModelService.java       |   3 +
 .../queryresultscache/QueryResultsCache.java       |   7 +-
 .../applib/services/xactn/TransactionService.java  |  18 +
 .../apache/isis/schema/utils/CommandDtoUtils.java  |  36 +
 .../apache/isis/schema/utils/CommonDtoUtils.java   |  81 ++-
 .../eventbus/AbstractDomainEvent_veto_Test.java    | 183 +++++
 .../isis/schema/utils/CommandDtoUtils_Test.java    |  68 ++
 ...nDtoUtilsTest.java => CommonDtoUtils_Test.java} |  37 +-
 core/integtestsupport/pom.xml                      |   7 +-
 core/log4j/pom.xml                                 |   5 +
 .../isis/core/runtime/logging/SnapshotServer.java  |  16 +-
 core/maven-plugin/pom.xml                          |   3 +
 core/metamodel/pom.xml                             |  24 +
 .../commons/config/IsisConfigurationDefault.java   |   4 +-
 .../configbuilder/IsisConfigurationBuilder.java    |  15 +-
 .../commons/encoding/DebugDataInputExtended.java   |  28 +-
 .../commons/encoding/DebugDataOutputExtended.java  |  30 +-
 .../resource/ResourceStreamSourceAbstract.java     |   9 +-
 .../ResourceStreamSourceChainOfResponsibility.java |   4 +-
 .../resource/ResourceStreamSourceComposite.java    |   4 +-
 .../isis/core/metamodel/facetapi/FeatureType.java  |  21 +-
 .../action/ActionAnnotationFacetFactory.java       |  30 +-
 .../command/CommandFacetForActionAnnotation.java   |  26 +-
 ...ommandFacetForActionAnnotationAsConfigured.java |   7 +-
 .../command/CommandFacetFromConfiguration.java     |  13 +-
 .../facets/actions/command/CommandFacet.java       |   2 +
 .../actions/command/CommandFacetAbstract.java      |  45 +-
 .../members/order/MemberOrderFacetAbstract.java    |  21 +-
 .../MemberOrderFacetForActionAnnotation.java}      |  18 +-
 .../objectspecid/ObjectSpecIdFacetAbstract.java    |   9 +-
 .../ObjectSpecIdFacetOnStandaloneList.java}        |  13 +-
 .../MustSatisfySpecificationFacetAbstract.java     |  22 +-
 ...fySpecificationFacetForParameterAnnotation.java |   2 -
 .../property/PropertyAnnotationFacetFactory.java   |   2 +-
 .../command/CommandFacetForPropertyAnnotation.java |  24 +-
 ...mandFacetForPropertyAnnotationAsConfigured.java |   5 +-
 ...sfySpecificationFacetForPropertyAnnotation.java |   2 -
 ...onParameterDefaultsAndChoicesPostProcessor.java | 156 +++++
 ...arameterChoicesFacetFromParentedCollection.java |  74 ++
 ...rameterDefaultsFacetFromParentedCollection.java |  63 ++
 ...{ProgrammingModel.java => FacetFactorySet.java} |   9 +-
 .../ObjectSpecificationPostProcessor.java}         |  10 +-
 .../metamodel/progmodel/PostProcessorSet.java}     |  15 +-
 .../core/metamodel/progmodel/ProgrammingModel.java |  62 +-
 .../core/metamodel/services/ServicesInjector.java  |   4 +-
 .../services/appfeat/ApplicationFeatureId.java     |  21 +
 .../services/grid/GridLoaderServiceDefault.java    |  61 +-
 .../services/grid/GridSystemServiceAbstract.java   |   4 +-
 .../metamodel/MetaModelServiceDefault.java         |  31 +
 .../PersistenceSessionServiceInternal.java         |   4 +
 .../PersistenceSessionServiceInternalNoop.java     |   6 +
 .../services/xactn/TransactionServiceDefault.java  |  15 +-
 .../core/metamodel/spec/ObjectSpecification.java   |  68 +-
 .../core/metamodel/spec/feature/ObjectAction.java  |  52 ++
 .../spec/feature/ObjectActionParameter.java        |  77 +++
 .../metamodel/specloader/ServiceInitializer.java   |   4 +-
 .../metamodel/specloader/SpecificationLoader.java  |  51 +-
 .../specloader/facetprocessor/FacetProcessor.java  |  10 +-
 .../specloader/postprocessor/PostProcessor.java    |  59 ++
 .../specloader/specimpl/FacetedMethodsBuilder.java |  26 +-
 .../specimpl/ObjectSpecificationAbstract.java      |  36 +-
 .../specimpl/dflt/ObjectSpecificationDefault.java  |   7 +-
 .../ObjectSpecificationOnStandaloneList.java       |   4 +
 .../MetaModelValidatorToCheckModuleExtent.java     | 153 +++++
 ...taModelValidatorToCheckObjectSpecIdsUnique.java |  95 +++
 .../authentication/standard/SimpleSession.java     |   2 +-
 .../isis/core/runtime/snapshot/XmlSnapshot.java    |  60 +-
 .../isis/core/webapp/content/ResourceServlet.java  |  14 +-
 .../diagnostics/IsisLogOnExceptionFilter.java      |   2 +-
 .../core/webapp/routing/RedirectToDocsFilter.java  |   9 +-
 .../isis/progmodels/dflt/JavaReflectorHelper.java  |   2 +-
 .../dflt/ProgrammingModelFacetsJava5.java          |  13 +
 .../isis/core/metamodel/services/grid/Foo.java}    |  12 +-
 .../core/metamodel/services/grid/Foo.layout.xml    |  23 +
 .../isis/core/metamodel/services/grid/Foo2.java}   |  12 +-
 .../services/grid/Foo2.layout.fallback.xml         |  23 +
 .../isis/core/metamodel/services/grid/Foo3.java}   |  12 +-
 .../services/grid/Foo3.layout.fallback.xml         |  23 +
 .../core/metamodel/services/grid/Foo3.layout.xml   |  23 +
 .../isis/core/metamodel/services/grid/Foo4.java}   |  12 +-
 ...dLoaderServiceDefault_resourceNameFor_Test.java |  58 ++
 .../SpecificationLoaderTestAbstract.java           |   2 +-
 .../specimpl/ObjectMemberAbstractTest.java         |  18 +
 .../testspec/ObjectSpecificationStub.java          |  14 +
 core/pom.xml                                       |  79 ++-
 core/runtime/pom.xml                               |  17 +-
 .../fixtures/FixturesInstallerDelegate.java        |   4 +-
 .../FixturesInstallerFromConfiguration.java        |   2 +-
 .../HeadlessWithBootstrappingAbstract.java         |   4 +-
 .../apache/isis/core/runtime/memento/Memento.java  |  18 +-
 .../runtime/persistence/adapter/PojoAdapter.java   |   4 +-
 .../runner/opts/OptionHandlerAppManifest.java      |   2 +-
 .../runner/opts/OptionHandlerFixtureAbstract.java  |   2 +-
 .../runner/opts/OptionHandlerInitParameters.java   |   4 +-
 .../runner/opts/OptionHandlerSystemProperties.java |   4 +-
 .../core/runtime/services/ServiceInstantiator.java |   6 +-
 .../ServicesInstallerFromConfiguration.java        |   2 +-
 ...cesInstallerFromConfigurationAndAnnotation.java |   2 +-
 .../background/BackgroundCommandExecution.java     | 258 +------
 .../background/CommandExecutionAbstract.java       |  69 ++
 .../background/CommandExecutorServiceDefault.java  | 429 ++++++++++++
 .../changes/ChangedObjectsServiceInternal.java     |  52 +-
 .../services/command/CommandServiceDefault.java    |   4 -
 .../menubars/bootstrap3/MenuBarsServiceBS3.java    |  34 +-
 .../PersistenceSessionServiceInternalDefault.java  |   8 +-
 .../AbstractIsisSessionTemplate.java               |  31 +-
 .../system/internal/IsisLocaleInitializer.java     |   4 +-
 .../system/internal/IsisTimeZoneInitializer.java   |   4 +-
 .../persistence/PersistenceQueryFactory.java       |   2 +-
 .../system/persistence/PersistenceSession.java     |  68 +-
 .../persistence/PersistenceSessionFactory.java     |  10 +-
 .../PersistenceSessionFactoryMetamodelRefiner.java |   4 +
 .../adaptermanager/OidAdapterHashMap.java          |   6 +-
 .../adaptermanager/PojoAdapterHashMap.java         |   6 +-
 .../system/session/IsisSessionFactoryBuilder.java  |   6 +-
 .../system/transaction/IsisTransaction.java        |  39 +-
 .../system/transaction/IsisTransactionManager.java |   2 +-
 .../IsisComponentProviderUsingInstallers.java      |  12 +-
 .../isis/core/webapp/IsisWebAppBootstrapper.java   |   4 +-
 .../CreateSchemaObjectFromClassMetadata.java       |   2 +-
 .../commands/DataNucleusCreateObjectCommand.java   |   2 +-
 .../commands/DataNucleusDeleteObjectCommand.java   |   2 +-
 .../PersistenceQueryFindAllInstancesProcessor.java |   2 +-
 ...sistenceQueryFindUsingApplibQueryProcessor.java |   4 +-
 .../datanucleus/persistence/queries/QueryUtil.java |   4 +-
 .../objectstore/jdo/service/RegisterEntities.java  |   3 +-
 .../src/main/resources/META-INF/MANIFEST.MF        |   6 -
 core/schema/pom.xml                                |   9 +-
 .../resources/org/apache/isis/schema/bindings.xml  |   8 +-
 .../org/apache/isis/schema/chg/chg-1.1.xsd         |   2 +-
 .../isis/schema/cmd/{cmd-1.3.xsd => cmd-1.4.xsd}   |  45 +-
 .../org/apache/isis/schema/common/common-1.1.xsd   |  30 +-
 .../isis/schema/ixn/{ixn-1.2.xsd => ixn-1.3.xsd}   |   6 +-
 core/security-shiro/pom.xml                        |   7 +-
 core/security/pom.xml                              |   7 +-
 core/specsupport/pom.xml                           |   5 +
 .../core/specsupport/specs/CukeGlueAbstract2.java  |   4 +-
 .../specs/CukeGlueBootstrappingAbstract.java       |  10 +
 core/unittestsupport/pom.xml                       |   7 +-
 core/viewer-restfulobjects-applib/pom.xml          |   7 +-
 core/viewer-restfulobjects-rendering/pom.xml       |   8 +-
 core/viewer-restfulobjects-server/pom.xml          |   7 +-
 .../ExceptionMapperForRuntimeException.java        |  13 +-
 .../server/mappers/entity/ExceptionDetail.java     |   2 +-
 core/viewer-wicket-applib/pom.xml                  |   6 +-
 core/viewer-wicket-impl/pom.xml                    |   6 +-
 .../wicket/viewer/IsisWicketApplication.java       |   8 +-
 .../integration/wicket/WebRequestCycleForIsis.java |   4 +-
 .../ComponentFactoryRegistrarDefault.java          |  33 +-
 .../wicket/viewer/services/Object_clearHints.java  |   5 +-
 .../services/TranslationsResolverWicket.java       |   2 +-
 core/viewer-wicket-model/pom.xml                   |   5 +
 .../viewer/wicket/model/models/ActionPrompt.java   |   6 +
 .../wicket/model/models/EntityCollectionModel.java |  20 +-
 .../viewer/wicket/model/models/EntityModel.java    |  68 +-
 .../viewer/wicket/model/models/ScalarModel.java    |  59 +-
 .../model/models/ScalarModelWithMultiPending.java  |  16 +-
 .../model/models/ScalarModelWithPending.java       |  20 +-
 .../model/models/ToggledMementosProvider.java}     |  18 +-
 .../wicket/model/models/EntityModel_hintsTest.java |   2 +-
 core/viewer-wicket-ui/pom.xml                      |   5 +
 .../AdditionalLinksAsDropDownPanel.html            |   1 +
 .../entityactions/EntityActionLinkFactory.java     |   8 +-
 .../actionmenu/entityactions/LinkAndLabelUtil.java |  12 +-
 .../actionmenu/serviceactions/CssMenuItem.java     |   8 +-
 .../serviceactions/ServiceActionLinkFactory.java   |   7 +-
 .../serviceactions/ServiceActionUtil.java          |  12 +
 .../actionprompt/ActionPromptModalWindow.java      |   2 +
 .../collection/AssociatedWithActionsHelper.java    |  87 +++
 .../ui/components/collection/CollectionPanel.java  |  99 ++-
 .../collection/bulk/BulkActionsHelper.java         |  57 +-
 .../collection/bulk/BulkActionsLinkFactory.java    |   4 +-
 .../collection/bulk/BulkActionsProvider.java       |   6 +-
 .../CollectionContentsAsAjaxTablePanel.java        |   4 +-
 .../ajaxtable/IsisAjaxFallbackDataTable.java       |   5 -
 .../columns/ObjectAdapterPropertyColumn.java       |  14 +-
 .../components/entity/fieldset/PropertyGroup.java  |  31 +-
 .../wicket/ui/components/layout/bs3/col/Col.java   |  15 +-
 .../ui/components/property/PropertyEditPanel.java  |   7 +-
 .../ui/components/scalars/ScalarPanelAbstract.java |   2 +-
 .../components/scalars/ScalarPanelAbstract2.java   |  37 +-
 .../scalars/ScalarPanelSelect2Abstract.java        |   2 +-
 .../components/scalars/primitive/BooleanPanel.java |   2 +-
 .../ui/components/scalars/uuid/UuidConverter.java  |  60 ++
 .../ui/components/scalars/uuid/UuidPanel.java      |  59 ++
 .../components/scalars/uuid/UuidPanelFactory.java} |  32 +-
 .../ui/components/scalars/uuid/UuidTextField.java  |  53 ++
 .../StandaloneCollectionPanel.java                 |  42 +-
 .../components/widgets/bootstrap/ModalDialog.java  |  10 +
 .../widgets/linkandlabel/ActionLinkFactory.java    |   5 +-
 .../linkandlabel/ActionLinkFactoryAbstract.java    |  78 ++-
 .../widgets/themepicker/ThemeChooser.java          |   2 +-
 .../viewer/wicket/ui/pages/bootstrap-overrides.css |  17 +
 .../wicket/ui/panels/FormExecutorDefault.java      |   2 +-
 .../scalars/uuid/UuidConverterTest_roundtrip.java  |  73 ++
 core/webserver/pom.xml                             |   5 +
 core/wrapper/pom.xml                               |   7 +-
 example/application/helloworld/pom.xml             |   2 +-
 .../bdd/specglue/BootstrappingGlue.java            |  16 +-
 .../{RunBddSpecs.java => RunIntegBddSpecs.java}    |   2 +-
 .../modules/simple/dom/impl/SimpleObject.java      |   3 +-
 .../simple/dom/impl/SimpleObject.layout.xml        |   6 +-
 324 files changed, 6511 insertions(+), 2877 deletions(-)

diff --cc adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_publishing.adoc
index 0a17ecc,59e3205..20f146f
--- a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_publishing.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Action_publishing.adoc
@@@ -8,10 -8,10 +8,10 @@@
  
  
  The `publishing()` attribute determines whether and how an action invocation is published via the registered
 -implementation of a xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublishingService[`PublishingService`]) or
 +implementation of a xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`]) or
  xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].  This attribute is also
  supported for xref:../rgant/rgant.adoc#_rgant-DomainObject_publishing[domain objects], where it controls whether changed objects
- are published as events, and for xref:../rgant/rgant.adoc#_rgant_Property_publishing[`@Property#publishing()`], where it controls
+ are published as events, and for xref:../rgant/rgant.adoc#_rgant-Property_publishing[`@Property#publishing()`], where it controls
  whether property edits are published as events.
  
  A common use case is to notify external "downstream" systems of changes in the state of the Isis application.
diff --cc adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-DomainObject_publishing.adoc
index bfba388,11ed8ba..1f529e3
--- a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-DomainObject_publishing.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-DomainObject_publishing.adoc
@@@ -7,11 -7,10 +7,11 @@@
  
  
  The `publishing()` attribute determines whether and how a modified object instance is published via the registered
 -implementation of a xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublishingService[`PublishingService`]) or
 -xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].  This attribute is also supported
 +implementation of
 +xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].
 +This attribute is also supported
  for xref:../rgant/rgant.adoc#_rgant-Action_publishing[actions], where it controls whether action invocations are published as
- events, and for xref:../rgant/rgant.adoc#_rgant_Property_publishing[`@Property#publishing()`], where it controls whether
+ events, and for xref:../rgant/rgant.adoc#_rgant-Property_publishing[`@Property#publishing()`], where it controls whether
  property edits are published as events.
  
  A common use case is to notify external "downstream" systems of changes in the state of the Isis application.
diff --cc adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Property_publishing.adoc
index 2be7751,6cbf9fa..3c56ad3
--- a/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Property_publishing.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgant/_rgant-Property_publishing.adoc
@@@ -8,11 -8,10 +8,11 @@@
  
  
  The `publishing()` attribute determines whether and how a property edit is published via the registered implementation
 -of a xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublishingService[`PublishingService`]) or
 -xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].  This attribute is also supported
 +of
 +xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].
 +This attribute is also supported
  for xref:../rgant/rgant.adoc#_rgant-DomainObject_publishing[domain objects], where it controls whether changed objects are
- published as events, and for xref:../rgant/rgant.adoc#_rgant_Property_publishing[`@Property#publishing()`], where it controls
+ published as events, and for xref:../rgant/rgant.adoc#_rgant-Property_publishing[`@Property#publishing()`], where it controls
  whether property edits are published as events.
  
  A common use case is to notify external "downstream" systems of changes in the state of the Isis application.
diff --cc adocs/documentation/src/main/asciidoc/guides/rgcms/_rgcms_schema-common.adoc
index 35acf2b,1bda81c..b5c8175
--- a/adocs/documentation/src/main/asciidoc/guides/rgcms/_rgcms_schema-common.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgcms/_rgcms_schema-common.adoc
@@@ -130,10 -158,18 +158,17 @@@ The common schema also defines two type
  Used for the return value of action invocations, and for the new value in property edits.
  
  
 -These type definitions are just building blocks, also used within the xref:../rgcms/rgcms.adoc#_rgcms_schema-aim[action iInvocation memento] schema.
 -The first, `valueDto` is The second, `valueType`, enumerates the different types of vales, eg of a
 -formal parameter to an action.
 +These type definitions are just building blocks.
 +The first, `valueDto` is The second, `valueType`, enumerates the different types of vales, eg of a formal parameter to an action.
  
  
+ [IMPORTANT]
+ ====
+ When used as a parameter, blob and clob arguments are _not_ serialized.
+ Instead these are persisted only as references.
+ This is primarily to save storage space if the resultant XML is persisted as a memento (eg `CommandDto`).
+ ====
+ 
  
  [[__rgcms_schema-common_ancillary]]
  == Ancillary types
diff --cc adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-spi_CommandService.adoc
index b04eef8,ce1e550..6dfe056
--- a/adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-spi_CommandService.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_application-layer-spi_CommandService.adoc
@@@ -14,16 -16,12 +16,16 @@@ One use case for this is for regressio
  There are a number of related use cases:
  
  * they enable profiling of the running application (which actions are invoked then most often, what is their response time)
 -* if xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`] or
 -xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublishingService[`PublishingService`] (latter deprecated) is configured, they provide better traceability as the `Command` is also correlated with any published events, again through the unique `transactionId` GUID
 -* if xref:../rgsvc/rgsvc.adoc#_rgsvc_spi_AuderService[`AuditerService`] or
 -xref:../rgsvc/rgsvc.adoc#_rgsvc_spi_AuditService[`AuditingService`] (latter deprecated) is configured, they provide better audit information, since the `Command` (the 'cause' of an action) can be correlated to the audit records (the "effect" of the action) through the `transactionId` GUID
++
++
 +* if xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`] is configured, they provide
 +better traceability as the `Command` is also correlated with any published events, again through the unique
 +`transactionId` GUID
 +* if xref:../rgsvc/rgsvc.adoc#_rgsvc_spi_AuditerService[`AuditerService`](s) are configured, they provide better audit
 +information, since the `Command` (the 'cause' of an action) can be correlated to the audit records (the "effect" of
 +the action) through the `transactionId` GUID
  
- However, while persistent ``Command``s _can_ be used for these use cases, it is recommended instead to use the
- xref:../rgsvc/rgsvc.adoc#_rgsvc_application-layer-api_InteractionContext[`InteractionContext`] service and persistent implementations of the
- ``Interaction`` object, eg as provided by the (non-ASF) link:http://platform.incode.org[Incode Platform^]'s publishmq module.
+ However, while persistent ``Command``s _can_ be used for these use cases, it is recommended instead to use the xref:../rgsvc/rgsvc.adoc#_rgsvc_application-layer-api_InteractionContext[`InteractionContext`] service and persistent implementations of the ``Interaction`` object, eg as provided by the (non-ASF) link:http://platform.incode.org[Incode Platform^]'s publishmq module.
  
  
  
@@@ -52,12 -53,15 +55,12 @@@ public interface CommandService 
  }
  ----
  <1> Instantiate the appropriate instance of the `Command` (as defined by the
- xref:../rgsvc/rgsvc.adoc#_rgsvc_application-layer-api_CommandContext[`CommandContext`] service).  Its members will be populated automatically by
- the framework.
- <2> Deprecated and *IS NOT CALLED* by the framework.
- The framework automatically populates the ``Command``'s `timestamp`, `user` and `transactionId` fields, so there is no need for the service implementation to initialize any of these.
- In particular, the ``Command`` will already have been initialized with the provided `transactionId` argument.
- <3> Set the hint that the `Command` should be persisted if possible (when completed, see below).
+ xref:../rgsvc/rgsvc.adoc#_rgsvc_application-layer-api_CommandContext[`CommandContext`] service).
+ Its members will be populated automatically by the framework.
 -<2> Deprecated and *IS NOT CALLED* by the framework.
 -The framework automatically populates the ``Command``'s `timestamp`, `user` and `transactionId` fields, so there is no need for the service implementation to initialize any of these.
 -In particular, the ``Command`` will already have been initialized with the provided `transactionId` argument.
 -<3> Set the hint that the `Command` should be persisted if possible (when completed, see below).
 -<4> "Complete" the command, typically meaning that the command should be persisted it if its `Command#getPersistence()` flag and persistence hint (`Command#isPersistHint()`) indicate that it should be.  +
++<2> Set the hint that the `Command` should be persisted if possible (when completed, see below).
++<3> "Complete" the command, typically meaning that the command should be persisted it if its `Command#getPersistence()` flag and persistence hint (`Command#isPersistHint()`) indicate that it should be.  +
+ +
+ The framework will automatically have set the `completedAt` property of the `Command`.
  
  
  
@@@ -97,10 -100,10 +100,10 @@@ This is closely related to the xref:../
  
  The implementations of `CommandService` and `BackgroundCommandService` are intended to go together, so that persistent parent `Command`s can be associated with their child background `Command`s.
  
 -The services provided by this module combines very well with the xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_AuditingService[`AuditingService`].
 -The `CommandService` captures the _cause_ of an interaction (an action was invoked, a property was edited), while the `AuditingService3` captures the _effect_ of that interaction in terms of changed state.
 +The services provided by this module combines very well with the xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_AuditerService[`AuditerService`].
- The `CommandService` captures the _cause_ of an interaction (an action was invoked, a property was edited), while the `AuditerService` captures the _effect_ of that interaction in terms of changed state.
++The `CommandService` captures the __cause__ of an interaction (an action was invoked, a property was edited), while the `AuditerService` captures the __effect__ of that interaction in terms of changed state.
  
 -You may also want to configure the xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublishingService[`PublishingService`].
 +You may also want to configure the xref:../rgsvc/rgsvc.adoc#_rgsvc_persistence-layer-spi_PublisherService[`PublisherService`].
  
  All three of these services collaborate implicitly by way of the xref:../rgcms/rgcms.adoc#_rgcms_classes_mixins_HasTransactionId[`HasTransactionId`] interface.
  
diff --cc adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_metadata-api_MetamodelService.adoc
index 3b45d42,222e67e..361e468
--- a/adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_metadata-api_MetamodelService.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/rgsvc/_rgsvc_metadata-api_MetamodelService.adoc
@@@ -6,9 -6,11 +6,10 @@@
  
  
  
- The `MetaModelService4` service (and its various supertypes) provides access to a number of aspects of Apache Isis' internal metamodel.
+ The `MetaModelService5` service (and its various supertypes) provides access to a number of aspects of Apache Isis' internal metamodel.
  
  
 -
+ [[_rgsvc_metadata-api_MetamodelService_api]]
  == API
  
  
diff --cc adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_programming-model_actions.adoc
index 8a391b2,b48ab06..693703e
--- a/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_programming-model_actions.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugfun/_ugfun_programming-model_actions.adoc
@@@ -255,8 -255,8 +255,13 @@@ public Order updateDiscount
      return this;
  }
  ----
++<<<<<<< HEAD
 +<1> Specifies the property precision using xref:../rgant/rgant.adoc#_rgant_Column_scale[`@Column#scale()`]
 +<2> Specifies the corresponding parameter precision using xref:../rgant/rgant.adoc#_rgant-Digits[`@Digits#fraction()`].
++=======
+ <1> Specifies the property precision using xref:../rgant/rgant.adoc#_rgant-Column_scale[`@Column#scale()`]
+ <2> Specifies the corresponding parameter precision using xref:../rgant/rgant.adoc#_rgant-Digits_fraction[`@Digits#fraction()`].
++>>>>>>> maint-1.16.1
  
  See also xref:../ugfun/ugfun.adoc#_ugfun_programming-model_properties-vs-parameters[properties vs parameters].
  
diff --cc adocs/documentation/src/main/asciidoc/guides/ugvw/_ugvw_layout_file-based.adoc
index 4f49ccf,3a30493..38956fc
--- a/adocs/documentation/src/main/asciidoc/guides/ugvw/_ugvw_layout_file-based.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/ugvw/_ugvw_layout_file-based.adoc
@@@ -32,6 -32,27 +32,17 @@@ These are JAXB-annotated classes with c
  
  
  
+ == Search Algorithm (Library Support)
+ 
+ For a given domain object `Xxx` the framework initially searches for a file (on the classpath) called `Xxx.layout.xml`.
+ 
+ If this can't be found, then the framework will search for a file named `Xxx.layout.fallback.xml`.
+ If present, this will be used instead.
+ 
+ This therefore allows libraries that provide a domain entities/view models (for example, the (non-ASF) link:http://platform.incode.org[Incode Platform] modules) to define the UI of these objects using a layout file, while still allowing the consuming application to override that layout if it so requires.
+ 
+ 
+ 
 -[NOTE]
 -====
 -It is also possible to describe layouts using a `.layout.json` file.
 -However, `.layout.json` support is deprecated; the ``.layout.xml`` file also enables much more sophisticated layouts than those afforded by ``.layout.json``.
 -
 -If you have an application with older `.layout.json` files, then it is possible to download initial `.layout.xml` files using the xref:../rgsvc/rgsvc.adoc#_rgsvc_metadata-api_LayoutService[`LayoutService`] (exposed as an action on the prototyping menu).
 -
 -The `.layout.json` file will be ignored once a `.layout.xml` file is present.
 -====
 -
  
  == Grids vs Components
  
diff --cc core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
index 0183df7,d1178eb..118b83d
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Action.java
@@@ -25,7 -25,13 +25,12 @@@ import java.lang.annotation.Retention
  import java.lang.annotation.RetentionPolicy;
  import java.lang.annotation.Target;
  
+ import org.apache.isis.applib.conmap.ContentMappingServiceForCommandDto;
+ import org.apache.isis.applib.conmap.ContentMappingServiceForCommandsDto;
+ import org.apache.isis.applib.services.command.CommandDtoProcessor;
+ import org.apache.isis.applib.services.command.CommandWithDto;
+ import org.apache.isis.applib.services.command.spi.CommandService;
  import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
 -import org.apache.isis.applib.services.publish.PublisherService;
  
  /**
   * Domain semantics for domain object collection.
@@@ -115,8 -121,11 +120,11 @@@ public @interface Action 
       * <p>
       * Has no meaning if annotated on an action of a domain service.
       * </p>
+      *
+      * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
       */
+     @Deprecated
 -    InvokeOn invokeOn() default InvokeOn.OBJECT_ONLY;
 +    InvokeOn invokeOn() default InvokeOn.NOT_SPECIFIED;
  
      // //////////////////////////////////////
  
@@@ -178,7 -208,46 +202,46 @@@
       *     By default there are no restrictions, with the action being available in all environments.
       * </p>
       */
 -    RestrictTo restrictTo() default RestrictTo.NO_RESTRICTIONS;
 +    RestrictTo restrictTo() default RestrictTo.NOT_SPECIFIED;
  
  
+     // //////////////////////////////////////
+ 
+ 
+     /**
+      * Associates this action with a property or collection, specifying its id.
+      *
+      * <p>
+      *     This is an alternative to using {@link MemberOrder#name()}.  To specify the order (equivalent to
+      *     {@link MemberOrder#sequence()}}), use {@link #associateWithSequence()}.
+      * </p>
+      *
+      * <p>
+      *     For example <code>@Action(associateWith="items", associateWithSequence="2.1")</code>
+      * </p>
+      *
+      * <p>
+      *     If an action is associated with a collection, then any matching parameters will have
+      *     their choices automatically inferred from the collection (if not otherwise specified)
+      *     and any collection parameter defaults can be specified using checkboxes
+      *     (in the Wicket UI, at least).
+      * </p>
+      */
+     String associateWith() default "";
+ 
+     /**
+      * Specifies the sequence/order in the UI for an action that's been associated with a property or collection.
+      *
+      * <p>
+      *     This is an alternative to using {@link MemberOrder#sequence()}, but is ignored if
+      *     {@link Action#associateWith()} isn't also specified.
+      * </p>
+      *
+      * <p>
+      *     For example <code>@Action(associateWith="items", associateWithSequence="2.1")</code>
+      * </p>
+      */
+     String associateWithSequence() default "1";
+ 
+ 
  }
diff --cc core/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
index 6c666c5,cd9311a..789ab07
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/CommandExecuteIn.java
@@@ -38,8 -38,50 +38,30 @@@ public enum CommandExecuteIn 
       * persisted {@link org.apache.isis.applib.services.command.Command command} object as a placeholder to the
       * result.
       */
-     BACKGROUND;
+     BACKGROUND,
+     /**
+      * For commands that are replicated from a master onto a slave and are to be replayed (typically using the same
+      * mechanism as "regular" background commands, eg a background job).
+      *
+      * <p>
+      *     For framework use, not intended to be used in application code.
+      * </p>
+      */
+     REPLAYABLE,
+     /**
+      * For commands that have been excluded and will not run.
+      * These are typically for a replayable command that has hit an exception (which normally would prevent any further
+      * replayable commands from being replayed) and which the administrator has decided to skip.
+      */
+     EXCLUDED
+     ;
+ 
+     public boolean isForeground() { return this == FOREGROUND; }
+     public boolean isBackground() { return this == BACKGROUND; }
+     public boolean isReplayable() { return this == REPLAYABLE; }
+     public boolean isExcluded() { return this == EXCLUDED; }
+ 
  
 -    @Deprecated
 -    public static CommandExecuteIn from(final Command.ExecuteIn executeIn) {
 -        if(executeIn == null) return null;
 -        if(executeIn == Command.ExecuteIn.FOREGROUND) return FOREGROUND;
 -        if(executeIn == Command.ExecuteIn.BACKGROUND) return BACKGROUND;
 -        if(executeIn == Command.ExecuteIn.REPLAYABLE) return REPLAYABLE;
 -        // shouldn't happen
 -        throw new IllegalArgumentException("Unrecognized : executeIn" + executeIn);
 -    }
 -
 -    @Deprecated
 -    public static Command.ExecuteIn from(final CommandExecuteIn commandExecuteIn) {
 -        if(commandExecuteIn == null) return null;
 -        if(commandExecuteIn == FOREGROUND) return Command.ExecuteIn.FOREGROUND;
 -        if(commandExecuteIn == BACKGROUND) return Command.ExecuteIn.BACKGROUND;
 -        if(commandExecuteIn == REPLAYABLE) return Command.ExecuteIn.REPLAYABLE;
 -        // shouldn't happen
 -        throw new IllegalArgumentException("Unrecognized : executeIn" + commandExecuteIn);
 -    }
 -
      public static class Type {
  
          private Type() {}
diff --cc core/applib/src/main/java/org/apache/isis/applib/annotation/InvokeOn.java
index 8e17153,be84512..72dfed6
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/InvokeOn.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/InvokeOn.java
@@@ -40,12 -49,29 +49,28 @@@ public enum InvokeOn 
       * <p>
       *     Corresponds to (the deprecated) <code>@Bulk(appliesTo=BULK_ONLY)</code> annotation.
       * </p>
+      *
+      * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
       */
+     @Deprecated
 -    COLLECTION_ONLY;
 +    COLLECTION_ONLY,
 +    /**
 +     * Ignore the value provided by this annotation (meaning that the framework will keep searching, in meta
 +     * annotations or superclasses/interfaces).
++     *
++     * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
 +     */
-     NOT_SPECIFIED
++    @Deprecated
++    NOT_SPECIFIED;
+ 
+     @Deprecated
+     public static Bulk.AppliesTo from(final InvokeOn invokeOn) {
+         if(invokeOn == null) return null;
+         if(invokeOn == OBJECT_AND_COLLECTION) return Bulk.AppliesTo.BULK_AND_REGULAR;
+         if(invokeOn == COLLECTION_ONLY) return Bulk.AppliesTo.BULK_ONLY;
+         if(invokeOn == OBJECT_ONLY) return Bulk.AppliesTo.REGULAR_ONLY;
+         // shouldn't happen
+         throw new IllegalArgumentException("Unrecognized appliesTo: " + invokeOn);
+     }
  
 -    @Deprecated
 -    public static InvokeOn from(final Bulk.AppliesTo appliesTo) {
 -        if(appliesTo == null) return null;
 -        if(appliesTo == Bulk.AppliesTo.BULK_AND_REGULAR) return OBJECT_AND_COLLECTION;
 -        if(appliesTo == Bulk.AppliesTo.BULK_ONLY) return COLLECTION_ONLY;
 -        if(appliesTo == Bulk.AppliesTo.REGULAR_ONLY) return OBJECT_ONLY;
 -        // shouldn't happen
 -        throw new IllegalArgumentException("Unrecognized appliesTo: " + appliesTo);
 -    }
  }
diff --cc core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
index 77632c9,ed91f9e..4ec8d78
--- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Property.java
@@@ -131,9 -136,25 +136,25 @@@ public @interface Property 
       * or {@link org.apache.isis.applib.services.publish.PublisherService} is registered with the framework.
       * </p>
       */
 -    Publishing publishing() default Publishing.AS_CONFIGURED;
 +    Publishing publishing() default Publishing.NOT_SPECIFIED;
  
  
+     /**
+      * The {@link CommandDtoProcessor} to process this command's DTO.
+      *
+      * <p>
+      *     Specifying a processor requires that the implementation of {@link CommandService} provides a
+      *     custom implementation of {@link org.apache.isis.applib.services.command.Command} that additional extends
+      *     from {@link CommandWithDto}.
+      * </p>
+      *
+      * <p>
+      *     Tprocessor itself is used by {@link ContentMappingServiceForCommandDto} and
+      *     {@link ContentMappingServiceForCommandsDto} to dynamically transform the DTOs.
+      * </p>
+      */
+     Class<? extends CommandDtoProcessor> commandDtoProcessor() default CommandDtoProcessor.class;
+ 
  
  
  
diff --cc core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java
index 0000000,c3b055e..a31dc59
mode 000000,100644..100644
--- a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandDto.java
@@@ -1,0 -1,151 +1,152 @@@
+ /*
+  *  Licensed to the Apache Software Foundation (ASF) under one
+  *  or more contributor license agreements.  See the NOTICE file
+  *  distributed with this work for additional information
+  *  regarding copyright ownership.  The ASF licenses this file
+  *  to you under the Apache License, Version 2.0 (the
+  *  "License"); you may not use this file except in compliance
+  *  with the License.  You may obtain a copy of the License at
+  *
+  *        http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing,
+  *  software distributed under the License is distributed on an
+  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  *  KIND, either express or implied.  See the License for the
+  *  specific language governing permissions and limitations
+  *  under the License.
+  */
+ package org.apache.isis.applib.conmap;
+ 
+ import java.sql.Timestamp;
+ import java.util.List;
+ 
+ import javax.inject.Inject;
+ import javax.ws.rs.core.MediaType;
+ 
+ import org.apache.isis.applib.annotation.DomainService;
+ import org.apache.isis.applib.annotation.NatureOfService;
+ import org.apache.isis.applib.annotation.Programmatic;
+ import org.apache.isis.applib.conmap.spi.CommandDtoProcessorService;
+ import org.apache.isis.applib.services.bookmark.Bookmark;
+ import org.apache.isis.applib.services.command.Command;
+ import org.apache.isis.applib.services.command.CommandDtoProcessor;
+ import org.apache.isis.applib.services.command.CommandWithDto;
 -import org.apache.isis.applib.services.metamodel.MetaModelService5;
++import org.apache.isis.applib.services.conmap.ContentMappingService;
++import org.apache.isis.applib.services.metamodel.MetaModelService;
+ import org.apache.isis.schema.cmd.v1.CommandDto;
+ import org.apache.isis.schema.common.v1.PeriodDto;
+ import org.apache.isis.schema.utils.CommandDtoUtils;
+ import org.apache.isis.schema.utils.jaxbadapters.JavaSqlTimestampXmlGregorianCalendarAdapter;
+ 
+ @DomainService(
+         nature = NatureOfService.DOMAIN,
+         menuOrder = "" + Integer.MAX_VALUE
+ )
+ public class ContentMappingServiceForCommandDto implements ContentMappingService {
+ 
+     @Programmatic
+     public Object map(Object object, final List<MediaType> acceptableMediaTypes) {
+         final boolean supported = Util.isSupported(CommandDto.class, acceptableMediaTypes);
+         if(!supported) {
+             return null;
+         }
+ 
+         return asProcessedDto(object);
+     }
+ 
+     /**
+      * Not part of the {@link ContentMappingService} API.
+      */
+     @Programmatic
+     public CommandDto map(final CommandWithDto commandWithDto) {
+         return asProcessedDto(commandWithDto);
+     }
+ 
+     CommandDto asProcessedDto(final Object object) {
+         if (!(object instanceof CommandWithDto)) {
+             return null;
+         }
+         final CommandWithDto commandWithDto = (CommandWithDto) object;
+         return asProcessedDto(commandWithDto);
+     }
+ 
+     private CommandDto asProcessedDto(final CommandWithDto commandWithDto) {
+         if(commandWithDto == null) {
+             return null;
+         }
+         CommandDto commandDto = commandWithDto.asDto();
+ 
+         // global processors
+         for (final CommandDtoProcessorService commandDtoProcessorService : commandDtoProcessorServices) {
+             commandDto = commandDtoProcessorService.process(commandWithDto, commandDto);
+             if(commandDto == null) {
+                 // any processor could return null, effectively breaking the chain.
+                 return null;
+             }
+         }
+ 
+         // specific processors for this specific member (action or property)
+         final CommandDtoProcessor commandDtoProcessor =
+                 metaModelService.commandDtoProcessorFor(commandDto.getMember().getLogicalMemberIdentifier());
+         if (commandDtoProcessor == null) {
+             return commandDto;
+         }
+         return commandDtoProcessor.process(commandWithDto, commandDto);
+     }
+ 
+ 
+     /**
+      * Uses the SPI infrastructure to copy over standard properties from {@link Command} to {@link CommandDto}.
+      */
+     @DomainService(
+             nature = NatureOfService.DOMAIN,
+             // specify quite a high priority since custom processors will probably want to run after this one
+             // (but can choose to run before if they wish)
+             menuOrder = "1000"
+     )
+     public static class CopyOverFromCommand implements CommandDtoProcessorService {
+ 
+         public CommandDto process(final Command command, CommandDto commandDto) {
+ 
+             // for some reason this isn't being persisted initially, so patch it in.  TODO: should fix this
+             commandDto.setUser(command.getUser());
+ 
+             // the timestamp field was only introduced in v1.4 of cmd.xsd, so there's no guarantee
+             // it will have been populated.  We therefore copy the value in from CommandWithDto entity.
+             if(commandDto.getTimestamp() == null) {
+                 final Timestamp timestamp = command.getTimestamp();
+                 commandDto.setTimestamp(JavaSqlTimestampXmlGregorianCalendarAdapter.print(timestamp));
+             }
+ 
+             CommandDtoUtils.setUserData(commandDto,
+                     CommandWithDto.USERDATA_KEY_TARGET_CLASS, command.getTargetClass());
+             CommandDtoUtils.setUserData(commandDto,
+                     CommandWithDto.USERDATA_KEY_TARGET_ACTION, command.getTargetAction());
+             CommandDtoUtils.setUserData(commandDto,
+                     CommandWithDto.USERDATA_KEY_ARGUMENTS, command.getArguments());
+ 
+             final Bookmark result = command.getResult();
+             CommandDtoUtils.setUserData(commandDto,
+                     CommandWithDto.USERDATA_KEY_RETURN_VALUE, result != null ? result.toString() : null);
+             // knowing whether there was an exception is on the master is used to determine whether to
+             // continue when replayed on the slave if an exception occurs there also
+             CommandDtoUtils.setUserData(commandDto,
+                     CommandWithDto.USERDATA_KEY_EXCEPTION, command.getException());
+ 
+             PeriodDto timings = CommandDtoUtils.timingsFor(commandDto);
+             timings.setStartedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getStartedAt()));
+             timings.setCompletedAt(JavaSqlTimestampXmlGregorianCalendarAdapter.print(command.getCompletedAt()));
+ 
+             return commandDto;
+         }
+     }
+ 
+ 
+     @Inject
 -    MetaModelService5 metaModelService;
++    MetaModelService metaModelService;
+ 
+     @Inject
+     List<CommandDtoProcessorService> commandDtoProcessorServices;
+ 
+ }
diff --cc core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java
index 0000000,95ba22a..71238d8
mode 000000,100644..100644
--- a/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/conmap/ContentMappingServiceForCommandsDto.java
@@@ -1,0 -1,94 +1,91 @@@
+ /*
+  *  Licensed to the Apache Software Foundation (ASF) under one
+  *  or more contributor license agreements.  See the NOTICE file
+  *  distributed with this work for additional information
+  *  regarding copyright ownership.  The ASF licenses this file
+  *  to you under the Apache License, Version 2.0 (the
+  *  "License"); you may not use this file except in compliance
+  *  with the License.  You may obtain a copy of the License at
+  *
+  *        http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing,
+  *  software distributed under the License is distributed on an
+  *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  *  KIND, either express or implied.  See the License for the
+  *  specific language governing permissions and limitations
+  *  under the License.
+  */
+ package org.apache.isis.applib.conmap;
+ 
+ import java.util.List;
+ 
+ import javax.inject.Inject;
+ import javax.ws.rs.core.MediaType;
+ 
+ import org.apache.isis.applib.annotation.DomainService;
+ import org.apache.isis.applib.annotation.NatureOfService;
+ import org.apache.isis.applib.annotation.Programmatic;
 -import org.apache.isis.applib.services.metamodel.MetaModelService5;
++import org.apache.isis.applib.services.conmap.ContentMappingService;
+ import org.apache.isis.schema.cmd.v1.CommandDto;
+ import org.apache.isis.schema.cmd.v1.CommandsDto;
+ 
+ @DomainService(
+         nature = NatureOfService.DOMAIN,
+         menuOrder = "" + Integer.MAX_VALUE
+ )
+ public class ContentMappingServiceForCommandsDto implements ContentMappingService {
+ 
+     @Programmatic
+     public Object map(Object object, final List<MediaType> acceptableMediaTypes) {
+         final boolean supported = Util.isSupported(CommandsDto.class, acceptableMediaTypes);
+         if(!supported) {
+             return null;
+         }
+ 
+         return map(object);
+     }
+ 
+     /**
+      * Not part of the {@link ContentMappingService} API.
+      */
+     @Programmatic
+     public CommandsDto map(final Object object) {
+         if(object instanceof CommandsDto) {
+             return ((CommandsDto) object);
+         }
+ 
 -        CommandDto commandDto = asDto(object, metaModelService5);
++        CommandDto commandDto = asDto(object);
+         if(commandDto != null) {
+             final CommandsDto commandsDto = new CommandsDto();
+             commandsDto.getCommandDto().add(commandDto);
+             return commandsDto;
+         }
+ 
+         if (object instanceof List) {
+             final List list = (List) object;
+             final CommandsDto commandsDto = new CommandsDto();
+             for (final Object obj : list) {
 -                final CommandDto objAsCommandDto = asDto(obj, metaModelService5);
++                final CommandDto objAsCommandDto = asDto(obj);
+                 if(objAsCommandDto != null) {
+                     commandsDto.getCommandDto().add(objAsCommandDto);
+                 } else {
+                     // simply ignore.
+                     // this is the means by which we can avoid replicating commands.
+                 }
+             }
+             return commandsDto;
+         }
+ 
+         // else
+         return new CommandsDto();
+     }
+ 
 -    private CommandDto asDto(final Object object, MetaModelService5 metaModelService5) {
++    private CommandDto asDto(final Object object) {
+         return contentMappingServiceForCommandDto.asProcessedDto(object);
+     }
+ 
+     @Inject
 -    MetaModelService5 metaModelService5;
 -
 -    @Inject
+     ContentMappingServiceForCommandDto contentMappingServiceForCommandDto;
+ 
+ }
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/actinvoc/ActionInvocationContext.java
index 0ba521d,86060cc..2f6cb58
--- a/core/applib/src/main/java/org/apache/isis/applib/services/actinvoc/ActionInvocationContext.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/actinvoc/ActionInvocationContext.java
@@@ -45,12 -50,12 +50,15 @@@ public class ActionInvocationContext 
  
      /**
       * Intended only to support unit testing.
+      *
+      * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
       */
+     @Deprecated
      public static ActionInvocationContext onObject(final Object domainObject) {
 -        return new ActionInvocationContext(InvokedOn.OBJECT, Collections.singletonList(domainObject));
 +        ActionInvocationContext aic = new ActionInvocationContext();
 +        aic.setInvokedOn(InvokedOn.OBJECT);
 +        aic.setDomainObjects(Collections.singletonList(domainObject));
 +        return aic;
      }
  
      /**
@@@ -62,12 -70,12 +73,15 @@@
  
      /**
       * Intended only to support unit testing.
+      *
+      * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
       */
+     @Deprecated
      public static ActionInvocationContext onCollection(final List<Object> domainObjects) {
 -        return new ActionInvocationContext(InvokedOn.COLLECTION, domainObjects);
 +        ActionInvocationContext aic = new ActionInvocationContext();
 +        aic.setInvokedOn(InvokedOn.COLLECTION);
 +        aic.setDomainObjects(domainObjects);
 +        return aic;
      }
  
      // //////////////////////////////////////
@@@ -78,8 -86,32 +92,7 @@@
  
      private int index;
  
 -    // //////////////////////////////////////
 -
 -    /**
 -     * @deprecated - instead of bulk actions, use view models with collection parameters and {@link Action#associateWith()}.
 -     */
 -    @Deprecated
 -    public ActionInvocationContext() {
 -    }
 -
 -    /**
 -     * @deprecated - now a {@link javax.enterprise.context.RequestScoped} service
 -     */
 -    @Deprecated
 -    public ActionInvocationContext(final InvokedOn invokedOn, final Object... domainObjects) {
 -        this(invokedOn, Arrays.asList(domainObjects));
 -    }
 -
 -    /**
 -     * @deprecated - now a {@link javax.enterprise.context.RequestScoped} service
 -     */
 -    @Deprecated
 -    public ActionInvocationContext(final InvokedOn invokedOn, final List<Object> domainObjects) {
 -        this.invokedOn = invokedOn;
 -        this.domainObjects = domainObjects;
 -    }
  
- 
      // //////////////////////////////////////
  
      /**
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
index d42f8ad,0ae75e1..d3e1496
--- a/core/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
@@@ -17,14 -17,11 +17,12 @@@
  package org.apache.isis.applib.services.command;
  
  import java.sql.Timestamp;
 +import java.util.List;
  
- import javax.annotation.Nullable;
- 
  import org.apache.isis.applib.Identifier;
  import org.apache.isis.applib.annotation.Action;
 -import org.apache.isis.applib.annotation.Command.ExecuteIn;
 -import org.apache.isis.applib.annotation.Command.Persistence;
 +import org.apache.isis.applib.annotation.CommandExecuteIn;
 +import org.apache.isis.applib.annotation.CommandPersistence;
  import org.apache.isis.applib.annotation.Programmatic;
  import org.apache.isis.applib.clock.Clock;
  import org.apache.isis.applib.services.HasTransactionId;
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/conmap/ContentMappingService.java
index a4a0fd7,49b0eb5..8de4d66
--- a/core/applib/src/main/java/org/apache/isis/applib/services/conmap/ContentMappingService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/conmap/ContentMappingService.java
@@@ -16,9 -16,10 +16,10 @@@
   *  specific language governing permissions and limitations
   *  under the License.
   */
 -package org.apache.isis.applib.conmap;
 +package org.apache.isis.applib.services.conmap;
  
  import java.util.List;
+ import java.util.Map;
  
  import javax.ws.rs.core.MediaType;
  
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelService.java
index 589b602,3263ba7..b4213ee
--- a/core/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/metamodel/MetaModelService.java
@@@ -20,11 -20,8 +20,12 @@@ package org.apache.isis.applib.services
  
  import java.util.List;
  
 +import org.apache.isis.applib.AppManifest;
 +import org.apache.isis.applib.AppManifest2;
  import org.apache.isis.applib.annotation.DomainObject;
  import org.apache.isis.applib.annotation.Programmatic;
 +import org.apache.isis.applib.services.bookmark.Bookmark;
++import org.apache.isis.applib.services.command.CommandDtoProcessor;
  
  /**
   * This service provides a formal API into Isis' metamodel.
@@@ -61,87 -58,5 +62,89 @@@ public interface MetaModelService 
      @Programmatic
      List<DomainMember> export();
  
 +    /**
 +     * @deprecated - use {@link #sortOf(Class, MetaModelService.Mode)}
 +     */
 +    @Deprecated
 +    @Programmatic
 +    Sort sortOf(Class<?> domainType);
 +
 +    /**
 +     * @deprecated - use {@link #sortOf(Bookmark, MetaModelService.Mode)}
 +     */
 +    @Deprecated
 +    @Programmatic
 +    Sort sortOf(Bookmark bookmark);
 +
 +    @Programmatic
 +    Sort sortOf(Class<?> domainType, Mode mode);
 +
 +    @Programmatic
 +    Sort sortOf(Bookmark bookmark, Mode mode);
 +
 +    enum Sort {
 +        VIEW_MODEL,
 +        JDO_ENTITY,
 +        DOMAIN_SERVICE,
 +        MIXIN,
 +        VALUE,
 +        COLLECTION,
 +        UNKNOWN;
 +
 +        public boolean isDomainService() {
 +            return this == DOMAIN_SERVICE;
 +        }
 +
 +        public boolean isMixin() {
 +            return this == MIXIN;
 +        }
 +
 +        public boolean isViewModel() {
 +            return this == VIEW_MODEL;
 +        }
 +
 +        public boolean isValue() {
 +            return this == VALUE;
 +        }
 +
 +        public boolean isCollection() {
 +            return this == COLLECTION;
 +        }
 +
 +        public boolean isJdoEntity() {
 +            return this == JDO_ENTITY;
 +        }
 +
 +        public boolean isUnknown() {
 +            return this == UNKNOWN;
 +        }
 +
 +    }
 +
 +    enum Mode {
 +        /**
 +         * If the {@link #sortOf(Class, Mode) sort of} object type is unknown, then throw an exception.
 +         */
 +        STRICT,
 +        /**
 +         * If the {@link #sortOf(Class, Mode) sort of} object type is unknown, then return {@link Sort#UNKNOWN}.
 +         */
 +        RELAXED
 +    }
 +
 +    /**
 +     * @return as {@link #getAppManifest()}, downcasted (else null).
 +     */
 +    @Programmatic
 +    AppManifest2 getAppManifest2();
 +
 +    /**
 +     * @return the {@link AppManifest} used to bootstrap the application.
 +     */
 +    @Programmatic
 +    AppManifest getAppManifest();
 +
++    @Programmatic
++    CommandDtoProcessor commandDtoProcessorFor(String memberIdentifier);
  
  }
diff --cc core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
index 8631686,42380a6..124dba5
--- a/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/xactn/TransactionService.java
@@@ -20,6 -20,6 +20,8 @@@
  package org.apache.isis.applib.services.xactn;
  
  import org.apache.isis.applib.annotation.Programmatic;
++import org.apache.isis.applib.services.command.Command;
++import org.apache.isis.applib.services.command.CommandContext;
  
  public interface TransactionService {
  
@@@ -50,54 -50,4 +52,70 @@@
      @Programmatic
      Transaction currentTransaction();
  
 +    /**
 +     * Generally this is equivalent to using {@link #currentTransaction()} and {@link Transaction#getTransactionState()}.
 +     * However, if there is no current transaction, then this will return {@link TransactionState#NONE}.
 +     */
 +    @Programmatic
 +    TransactionState getTransactionState();
 +
 +
 +    /**
 +     * Intended only for use by fixture scripts and integration tests.
 +     *
 +     * <p>
 +     *     The behaviour depends on the current state of the transaction, and the specified policy.
 +     *     <ul>
 +     *         <li>
 +     *              If the current transaction is in that it is still in progress, then commits and starts a new one.
 +     *         </li>
 +     *         <li>
 +     *              If the current transaction is complete, in that it is already committed or was rolled back, then simply starts a new one.
 +     *         </li>
 +     *         <li>
 +     *              If the current transaction is marked for abort, then depends on the provided policy:
 +     *              <ul>
 +     *                  <li>
 +     *                      If set to {@link Policy#ALWAYS always}, then rolls back and starts a new transaction
 +     *                  </li>
 +     *                  <li>
 +     *                      But if set to {@link Policy#UNLESS_MARKED_FOR_ABORT marked for abort}, then fails fast by throwing a runtime exception.
 +     *                  </li>
 +     *              </ul>
 +     *         </li>
 +     *
 +     *     </ul>
 +     *     If the current transaction has been marked for abort only, then depends on the provided rolls it back, and (again) starts a new one.
 +     * </p>
 +     *
 +     * <p>
 +     *     This is a refinement of the {@link TransactionService#nextTransaction()}, introduced in
 +     *     order to improve the error handling of that method in the case of an already must-abort transaction, and
 +     *     also to allow the caller to have more control on how to continue.
 +     * </p>
 +     */
 +    @Programmatic
 +    void nextTransaction(Policy policy);
 +
++
++    /**
++     * If the current transaction does not use the specified {@link Command} as its
++     * {@link CommandContext#getCommand() command context}, then commit and start a new one.
++     * @param command
++     */
++    void nextTransaction(Command command);
++
++    /**
++     * As per {@link #nextTransaction(Policy)} and {@link #nextTransaction(Command)}.
++     */
++    void nextTransaction(Policy policy, Command command);
++
++
 +    public enum Policy {
 +        UNLESS_MARKED_FOR_ABORT,
 +        ALWAYS
 +    }
 +
++
++
  }
diff --cc core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
index 8fe38c6,6c3ea91..b85a869
--- a/core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
+++ b/core/applib/src/main/java/org/apache/isis/schema/utils/CommonDtoUtils.java
@@@ -33,8 -37,12 +37,13 @@@ import org.joda.time.LocalTime
  
  import org.apache.isis.applib.services.bookmark.Bookmark;
  import org.apache.isis.applib.services.bookmark.BookmarkService;
 +import org.apache.isis.applib.util.Casts;
+ import org.apache.isis.applib.value.Blob;
+ import org.apache.isis.applib.value.Clob;
+ import org.apache.isis.schema.cmd.v1.MapDto;
  import org.apache.isis.schema.cmd.v1.ParamDto;
+ import org.apache.isis.schema.common.v1.BlobDto;
+ import org.apache.isis.schema.common.v1.ClobDto;
  import org.apache.isis.schema.common.v1.CollectionDto;
  import org.apache.isis.schema.common.v1.EnumDto;
  import org.apache.isis.schema.common.v1.OidDto;
@@@ -322,11 -348,18 +355,19 @@@ public final class CommonDtoUtils 
          case ENUM:
              final EnumDto enumDto = valueDto.getEnum();
              final String enumType = enumDto.getEnumType();
 +            @SuppressWarnings("rawtypes") 
              final Class<? extends Enum> enumClass = loadClassElseThrow(enumType);
 -            return (T) Enum.valueOf(enumClass, enumDto.getEnumName());
 +            return Enum.valueOf(Casts.uncheckedCast(enumClass), enumDto.getEnumName());
          case REFERENCE:
 -            return (T) valueDto.getReference();
 +            return valueDto.getReference();
+         case COLLECTION:
 -            return (T)valueDto.getCollection();
++            return valueDto.getCollection();
+         case BLOB:
+             final BlobDto blobDto = valueDto.getBlob();
 -            return (T)new Blob(blobDto.getName(), blobDto.getMimeType(), blobDto.getBytes());
++            return new Blob(blobDto.getName(), blobDto.getMimeType(), blobDto.getBytes());
+         case CLOB:
+             final ClobDto clobDto = valueDto.getClob();
 -            return (T)new Clob(clobDto.getName(), clobDto.getMimeType(), clobDto.getChars());
++            return new Clob(clobDto.getName(), clobDto.getMimeType(), clobDto.getChars());
          case VOID:
              return null;
          default:
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
index d6af533,b58ff4a..6c21f1c
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/ActionAnnotationFacetFactory.java
@@@ -20,11 -20,26 +20,14 @@@
  package org.apache.isis.core.metamodel.facets.actions.action;
  
  import java.lang.reflect.Method;
 +import java.util.List;
  
+ import com.google.common.base.Strings;
+ 
  import org.apache.isis.applib.annotation.Action;
 -import org.apache.isis.applib.annotation.ActionInteraction;
 -import org.apache.isis.applib.annotation.ActionSemantics;
 -import org.apache.isis.applib.annotation.Bulk;
 -import org.apache.isis.applib.annotation.Command;
 -import org.apache.isis.applib.annotation.Disabled;
 -import org.apache.isis.applib.annotation.Hidden;
 -import org.apache.isis.applib.annotation.Idempotent;
 -import org.apache.isis.applib.annotation.PostsActionInvokedEvent;
 -import org.apache.isis.applib.annotation.Prototype;
 -import org.apache.isis.applib.annotation.PublishedAction;
 -import org.apache.isis.applib.annotation.QueryOnly;
 -import org.apache.isis.applib.annotation.TypeOf;
  import org.apache.isis.applib.services.HasTransactionId;
  import org.apache.isis.applib.services.eventbus.ActionDomainEvent;
 -import org.apache.isis.applib.services.eventbus.ActionInvokedEvent;
+ import org.apache.isis.core.commons.config.IsisConfiguration;
  import org.apache.isis.core.metamodel.facetapi.FacetHolder;
  import org.apache.isis.core.metamodel.facetapi.FacetUtil;
  import org.apache.isis.core.metamodel.facetapi.FeatureType;
@@@ -52,11 -82,31 +55,15 @@@ import org.apache.isis.core.metamodel.f
  import org.apache.isis.core.metamodel.facets.actions.publish.PublishedActionFacet;
  import org.apache.isis.core.metamodel.facets.actions.semantics.ActionSemanticsFacet;
  import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
 -import org.apache.isis.core.metamodel.facets.members.disabled.DisabledFacet;
+ import org.apache.isis.core.metamodel.facets.members.order.MemberOrderFacet;
+ import org.apache.isis.core.metamodel.facets.members.order.annotprop.MemberOrderFacetForActionAnnotation;
+ import org.apache.isis.core.metamodel.services.ServicesInjector;
  import org.apache.isis.core.metamodel.spec.ObjectSpecification;
  import org.apache.isis.core.metamodel.specloader.CollectionUtils;
+ import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
 -import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorForDeprecatedAnnotation;
  import org.apache.isis.core.metamodel.util.EventUtil;
  
 -public class ActionAnnotationFacetFactory extends FacetFactoryAbstract
 -            implements MetaModelValidatorRefiner {
 -
 -    private final MetaModelValidatorForDeprecatedAnnotation actionSemanticsValidator = new MetaModelValidatorForDeprecatedAnnotation(ActionSemantics.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation actionInteractionValidator = new MetaModelValidatorForDeprecatedAnnotation(ActionInteraction.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation postsActionInvokedEventValidator = new MetaModelValidatorForDeprecatedAnnotation(PostsActionInvokedEvent.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation bulkValidator = new MetaModelValidatorForDeprecatedAnnotation(Bulk.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation commandValidator = new MetaModelValidatorForDeprecatedAnnotation(Command.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation queryOnlyValidator = new MetaModelValidatorForDeprecatedAnnotation(QueryOnly.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation idempotentValidator = new MetaModelValidatorForDeprecatedAnnotation(Idempotent.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation publishedActionValidator = new MetaModelValidatorForDeprecatedAnnotation(PublishedAction.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation typeOfValidator = new MetaModelValidatorForDeprecatedAnnotation(TypeOf.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation hiddenValidator = new MetaModelValidatorForDeprecatedAnnotation(Hidden.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation disabledValidator = new MetaModelValidatorForDeprecatedAnnotation(Disabled.class);
 -    private final MetaModelValidatorForDeprecatedAnnotation prototypeValidator = new MetaModelValidatorForDeprecatedAnnotation(Prototype.class);
 +public class ActionAnnotationFacetFactory extends FacetFactoryAbstract {
  
  
  
@@@ -216,8 -367,18 +224,8 @@@
              return;
          }
  
 -        CommandFacet commandFacet;
 -
 -        // check for deprecated @Command annotation first
 -        final Command annotation = Annotations.getAnnotation(method, Command.class);
 -        commandFacet = commandValidator.flagIfPresent(
 -                CommandFacetForCommandAnnotation.create(annotation, processMethodContext.getFacetHolder(),
 -                        servicesInjector), processMethodContext);
 -
 -        // else check for @Action(command=...)
 -        if(commandFacet == null) {
 -            commandFacet = CommandFacetForActionAnnotation.create(action, getConfiguration(), servicesInjector, holder);
 -        }
 +        // check for @Action(command=...)
-         CommandFacet commandFacet = CommandFacetForActionAnnotation.create(actions, getConfiguration(), holder);
++        CommandFacet commandFacet = CommandFacetForActionAnnotation.create(actions, getConfiguration(), servicesInjector, holder);
  
          FacetUtil.addFacet(commandFacet);
      }
@@@ -279,5 -458,66 +287,25 @@@
          FacetUtil.addFacet(typeOfFacet);
      }
  
+     void processAssociateWith(final ProcessMethodContext processMethodContext) {
+ 
+         final Method method = processMethodContext.getMethod();
+         final FacetedMethod holder = processMethodContext.getFacetHolder();
+ 
+         // check for @Action(associateWith=...)
+         MemberOrderFacet memberOrderFacet = null;
+ 
+         final Action action = Annotations.getAnnotation(method, Action.class);
+         if (action != null) {
+             final String associateWith = action.associateWith();
+             if(!Strings.isNullOrEmpty(associateWith)) {
+                 final String associateWithSequence = action.associateWithSequence();
+                 memberOrderFacet = new MemberOrderFacetForActionAnnotation(associateWith, associateWithSequence, holder);
+             }
+         }
+ 
+         FacetUtil.addFacet(memberOrderFacet);
+     }
+ 
  
 -    // ///////////////////////////////////////////////////////////////
 -
 -    @Override
 -    public void refineMetaModelValidator(final MetaModelValidatorComposite metaModelValidator, final IsisConfiguration configuration) {
 -        metaModelValidator.add(actionSemanticsValidator);
 -        metaModelValidator.add(actionInteractionValidator);
 -        metaModelValidator.add(postsActionInvokedEventValidator);
 -        metaModelValidator.add(bulkValidator);
 -        metaModelValidator.add(commandValidator);
 -        metaModelValidator.add(queryOnlyValidator);
 -        metaModelValidator.add(idempotentValidator);
 -        metaModelValidator.add(publishedActionValidator);
 -        metaModelValidator.add(typeOfValidator);
 -        metaModelValidator.add(hiddenValidator);
 -        metaModelValidator.add(disabledValidator);
 -        metaModelValidator.add(prototypeValidator);
 -    }
 -
 -    // ///////////////////////////////////////////////////////////////
 -
 -
 -    @Override
 -    public void setServicesInjector(final ServicesInjector servicesInjector) {
 -        super.setServicesInjector(servicesInjector);
 -        final IsisConfiguration configuration = getConfiguration();
 -
 -        actionSemanticsValidator.setConfiguration(configuration);
 -        actionInteractionValidator.setConfiguration(configuration);
 -        postsActionInvokedEventValidator.setConfiguration(configuration);
 -        bulkValidator.setConfiguration(configuration);
 -        commandValidator.setConfiguration(configuration);
 -        queryOnlyValidator.setConfiguration(configuration);
 -        idempotentValidator.setConfiguration(configuration);
 -        publishedActionValidator.setConfiguration(configuration);
 -        typeOfValidator.setConfiguration(configuration);
 -        hiddenValidator.setConfiguration(configuration);
 -        disabledValidator.setConfiguration(configuration);
 -        prototypeValidator.setConfiguration(configuration);
 -    }
 -
 -
  }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
index 499b411,6a9cff4..85577a8
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotation.java
@@@ -33,44 -35,41 +35,53 @@@ import org.apache.isis.core.metamodel.s
  public class CommandFacetForActionAnnotation extends CommandFacetAbstract {
  
      public static CommandFacet create(
 -            final Action action,
 +            final List<Action> actions,
              final IsisConfiguration configuration,
+             final ServicesInjector servicesInjector,
              final FacetHolder holder) {
  
 -        CommandReification commandReification =
 -                action != null
 -                    ? action.command()
 -                    : CommandReification.AS_CONFIGURED;
 -        CommandPersistence commandPersistence =
 -                action != null
 -                    ? action.commandPersistence()
 -                    : CommandPersistence.PERSISTED;
 -        final CommandExecuteIn commandExecuteIn =
 -                action != null
 -                    ? action.commandExecuteIn()
 -                    :  CommandExecuteIn.FOREGROUND;
 -        final Class<? extends CommandDtoProcessor> processorClass =
 -                action != null
 -                    ? action.commandDtoProcessor()
 -                    : null;
 -        final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
 +        final CommandActionsConfiguration setting = CommandActionsConfiguration.parse(configuration);
  
 -        if(processor != null) {
 -            commandReification = CommandReification.ENABLED;
 -            commandPersistence = CommandPersistence.PERSISTED;
 -        }
 -        final Persistence persistence = CommandPersistence.from(commandPersistence);
 -        final ExecuteIn executeIn = CommandExecuteIn.from(commandExecuteIn);
 +        return actions.stream()
 +                .filter(action -> action.command() != CommandReification.NOT_SPECIFIED)
 +                .findFirst()
 +                .map(action -> {
 +
-                     final CommandReification command = action.command();
-                     final CommandPersistence persistence = action.commandPersistence();
++                    CommandReification command = action.command();
++                    CommandPersistence persistence = action.commandPersistence();
 +                    final CommandExecuteIn executeIn = action.commandExecuteIn();
++                    final Class<? extends CommandDtoProcessor> processorClass = action.commandDtoProcessor();
++                    final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
+ 
++                    if(processor != null) {
++                        command = CommandReification.ENABLED;
++                        persistence = CommandPersistence.PERSISTED;
++                    }
  
 -        switch (commandReification) {
 -            case AS_CONFIGURED:
 -                final CommandActionsConfiguration setting = CommandActionsConfiguration.parse(configuration);
 -                switch (setting) {
 +                    switch (command) {
 +                    case AS_CONFIGURED:
 +                        switch (setting) {
 +                        case NONE:
 +                            return null;
 +                        case IGNORE_SAFE:
 +                            if (hasSafeSemantics(holder)) {
 +                                return null;
 +                            }
 +                            // else fall through
 +                        default:
 +                            return (CommandFacet)new CommandFacetForActionAnnotationAsConfigured(
-                                     persistence, executeIn, Enablement.ENABLED, holder);
++                                    persistence, executeIn, Enablement.ENABLED, holder, servicesInjector);
 +                        }
 +                    case DISABLED:
 +                        return null;
 +                    case ENABLED:
-                         return new CommandFacetForActionAnnotation(persistence, executeIn, Enablement.ENABLED, holder);
++                        return new CommandFacetForActionAnnotation(
++                                persistence, executeIn, Enablement.ENABLED, processor, holder, servicesInjector);
 +                    }
 +                    throw new IllegalStateException("command '" + command + "' not recognised");
 +                })
 +                .orElseGet(() -> {
 +                    switch (setting) {
                      case NONE:
                          return null;
                      case IGNORE_SAFE:
@@@ -79,29 -82,31 +90,30 @@@
                          }
                          // else fall through
                      default:
 -                        return action != null
 -                                ? new CommandFacetForActionAnnotationAsConfigured(persistence, executeIn, Enablement.ENABLED, holder,
 -                                servicesInjector)
 -                                : CommandFacetFromConfiguration.create(holder, servicesInjector);
 -                }
 -            case DISABLED:
 -                return null;
 -            case ENABLED:
 -                return new CommandFacetForActionAnnotation(
 -                        persistence, executeIn, Enablement.ENABLED, processor,
 -                        holder, servicesInjector);
 -        }
 -
 -        return null;
 +                        return CommandFacetFromConfiguration.create(holder);
 +                    }
- 
 +                });
      }
  
 +    private static boolean hasSafeSemantics(final FacetHolder holder) {
 +        final ActionSemanticsFacet actionSemanticsFacet = holder.getFacet(ActionSemanticsFacet.class);
 +        if(actionSemanticsFacet == null) {
 +            throw new IllegalStateException("Require ActionSemanticsFacet in order to process");
 +        }
 +        if(actionSemanticsFacet.value().isSafeInNature()) {
 +            return true;
 +        }
 +        return false;
 +    }
  
      CommandFacetForActionAnnotation(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
              final Enablement enablement,
-             final FacetHolder holder) {
-         super(persistence, executeIn, enablement, holder);
+             final CommandDtoProcessor processor,
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
+         super(persistence, executeIn, enablement, processor, holder, servicesInjector);
      }
  
  
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
index 07c3d86,8550b5a..8d19fae
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetForActionAnnotationAsConfigured.java
@@@ -18,18 -18,21 +18,21 @@@
   */
  package org.apache.isis.core.metamodel.facets.actions.action.command;
  
 -import org.apache.isis.applib.annotation.Command.ExecuteIn;
 -import org.apache.isis.applib.annotation.Command.Persistence;
 +import org.apache.isis.applib.annotation.CommandExecuteIn;
 +import org.apache.isis.applib.annotation.CommandPersistence;
  import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+ import org.apache.isis.core.metamodel.services.ServicesInjector;
  
  public class CommandFacetForActionAnnotationAsConfigured extends CommandFacetForActionAnnotation {
  
      CommandFacetForActionAnnotationAsConfigured(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
              final Enablement enablement,
-             final FacetHolder holder) {
-         super(persistence, executeIn, enablement, holder);
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
+         super(persistence, executeIn, enablement, null,
+                 holder, servicesInjector);
      }
  
  
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
index 4f91364,c1b7f71..387aed5
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/command/CommandFacetFromConfiguration.java
@@@ -27,15 -28,20 +28,19 @@@ import org.apache.isis.core.metamodel.s
  
  public class CommandFacetFromConfiguration extends CommandFacetAbstract {
  
-     public static CommandFacet create(final FacetHolder holder) {
-         return new CommandFacetFromConfiguration(CommandPersistence.PERSISTED, CommandExecuteIn.FOREGROUND, holder);
+     public static CommandFacet create(
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
 -        return new CommandFacetFromConfiguration(Persistence.PERSISTED, ExecuteIn.FOREGROUND, holder,
++        return new CommandFacetFromConfiguration(CommandPersistence.PERSISTED, CommandExecuteIn.FOREGROUND, holder,
+                 servicesInjector);
      }
  
      private CommandFacetFromConfiguration(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
-             final FacetHolder holder) {
-         super(persistence, executeIn, Enablement.ENABLED, holder);
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
 -        super(persistence, executeIn, Enablement.ENABLED, null,
 -                holder, servicesInjector);
++        super(persistence, executeIn, Enablement.ENABLED, null, holder, servicesInjector);
      }
  
  }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
index 6dff421,b9f8fdd..d8561c6
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacet.java
@@@ -19,10 -19,10 +19,11 @@@
  
  package org.apache.isis.core.metamodel.facets.actions.command;
  
 -import org.apache.isis.applib.annotation.Command.ExecuteIn;
 -import org.apache.isis.applib.annotation.Command.Persistence;
 +import org.apache.isis.applib.annotation.Action;
 +import org.apache.isis.applib.annotation.CommandExecuteIn;
 +import org.apache.isis.applib.annotation.CommandPersistence;
  import org.apache.isis.applib.services.command.Command;
+ import org.apache.isis.applib.services.command.CommandDtoProcessor;
  import org.apache.isis.core.metamodel.facetapi.Facet;
  
  /**
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
index 609ecc6,e08b4ca..ad63162
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/command/CommandFacetAbstract.java
@@@ -19,8 -19,9 +19,9 @@@
  
  package org.apache.isis.core.metamodel.facets.actions.command;
  
 -import org.apache.isis.applib.annotation.Command.ExecuteIn;
 -import org.apache.isis.applib.annotation.Command.Persistence;
 +import org.apache.isis.applib.annotation.CommandExecuteIn;
 +import org.apache.isis.applib.annotation.CommandPersistence;
+ import org.apache.isis.applib.services.command.CommandDtoProcessor;
  import org.apache.isis.core.metamodel.facetapi.Facet;
  import org.apache.isis.core.metamodel.facetapi.FacetHolder;
  import org.apache.isis.core.metamodel.facets.MarkerFacetAbstract;
@@@ -40,16 -42,20 +42,20 @@@ public abstract class CommandFacetAbstr
          }
      }
  
 -    private final Persistence persistence;
 -    private final ExecuteIn executeIn;
 +    private final CommandPersistence persistence;
 +    private final CommandExecuteIn executeIn;
      private final Enablement enablement;
+     private final CommandDtoProcessor processor;
  
      public CommandFacetAbstract(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
-             final Enablement enablement, 
-             final FacetHolder holder) {
+             final Enablement enablement,
+             final CommandDtoProcessor processor,
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
          super(type(), holder);
+         inject(processor, servicesInjector);
          this.persistence = persistence;
          this.executeIn = executeIn;
          this.enablement = enablement;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/mustsatisfyspec/MustSatisfySpecificationFacetAbstract.java
index c2f013e,235b2dc..4dd9533
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/mustsatisfyspec/MustSatisfySpecificationFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/mustsatisfyspec/MustSatisfySpecificationFacetAbstract.java
@@@ -21,8 -21,10 +21,10 @@@ package org.apache.isis.core.metamodel.
  
  import java.util.List;
  
- import org.apache.isis.applib.services.wrapper.events.ValidityEvent;
+ import com.google.common.collect.Lists;
+ 
 -import org.apache.isis.applib.events.ValidityEvent;
  import org.apache.isis.applib.services.i18n.TranslationService;
++import org.apache.isis.applib.services.wrapper.events.ValidityEvent;
  import org.apache.isis.applib.spec.Specification;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.facetapi.Facet;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/parameter/mustsatisfy/MustSatisfySpecificationFacetForParameterAnnotation.java
index 3e1e7e6,f94da8e..78bbdb1
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/parameter/mustsatisfy/MustSatisfySpecificationFacetForParameterAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/parameter/mustsatisfy/MustSatisfySpecificationFacetForParameterAnnotation.java
@@@ -38,21 -35,15 +38,19 @@@ public class MustSatisfySpecificationFa
              final FacetHolder holder,
              final ServicesInjector servicesInjector) {
  
 -        if (parameter == null) {
 -            return null;
 -        }
 -
 -        final Class<?>[] values = parameter.mustSatisfy();
 -        final List<Specification> specifications = specificationsFor(values);
 -        return specifications.size() > 0 ? new MustSatisfySpecificationFacetForParameterAnnotation(specifications, holder, servicesInjector) : null;
 +        List<Specification> specifications = parameters.stream()
 +                .map(Parameter::mustSatisfy)
 +                .flatMap(classes ->
 +                        Arrays.stream(classes)
 +                                .map(MustSatisfySpecificationFacetAbstract::newSpecificationElseNull)
 +                                .filter(Objects::nonNull)
 +                )
-                 .filter(Objects::nonNull)
 +                .collect(Collectors.toList());
 +        return specifications.size() > 0
 +                ? new MustSatisfySpecificationFacetForParameterAnnotation(specifications, holder, servicesInjector)
 +                : null;
      }
  
- 
      private MustSatisfySpecificationFacetForParameterAnnotation(
              final List<Specification> specifications,
              final FacetHolder holder,
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
index a405e95,7f919f7..6f82d19
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/PropertyAnnotationFacetFactory.java
@@@ -215,7 -283,8 +215,7 @@@ public class PropertyAnnotationFacetFac
          }
  
          // check for @Property(command=...)
-         final CommandFacet commandFacet = CommandFacetForPropertyAnnotation.create(properties, getConfiguration(), holder);
 -        final CommandFacet commandFacet = CommandFacetForPropertyAnnotation.create(property, getConfiguration(), holder,
 -                servicesInjector);
++        final CommandFacet commandFacet = CommandFacetForPropertyAnnotation.create(properties, getConfiguration(), holder, servicesInjector);
  
          FacetUtil.addFacet(commandFacet);
      }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
index 28c5902,3eb1290..dee1ed2
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotation.java
@@@ -33,53 -35,56 +35,63 @@@ import org.apache.isis.core.metamodel.s
  public class CommandFacetForPropertyAnnotation extends CommandFacetAbstract {
  
      public static CommandFacet create(
 -            final Property property,
 +            final List<Property> properties,
              final IsisConfiguration configuration,
-             final FacetHolder holder) {
+             final FacetHolder holder,
+             final ServicesInjector servicesInjector) {
  
 -        CommandReification commandReification = property != null ? property.command() : CommandReification.AS_CONFIGURED;
 -        final CommandPersistence commandPersistence = property != null ? property.commandPersistence() : CommandPersistence.PERSISTED;
 -        final CommandExecuteIn commandExecuteIn = property != null? property.commandExecuteIn() :  CommandExecuteIn.FOREGROUND;
 -        final Class<? extends CommandDtoProcessor> processorClass =
 -                property != null ? property.commandDtoProcessor() : null;
 -        final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
 -
 -        if(processor != null) {
 -            commandReification = CommandReification.ENABLED;
 -        }
 -        final Persistence persistence = CommandPersistence.from(commandPersistence);
 -        final ExecuteIn executeIn = CommandExecuteIn.from(commandExecuteIn);
 +        final CommandPropertiesConfiguration setting = CommandPropertiesConfiguration.parse(configuration);
  
 +        return properties.stream()
 +                .filter(property -> property.command() != CommandReification.NOT_SPECIFIED)
 +                .findFirst()
 +                .map(property -> {
-                     final CommandReification command = property.command();
++                    CommandReification command = property.command();
 +                    final CommandPersistence commandPersistence = property.commandPersistence();
 +                    final CommandExecuteIn commandExecuteIn = property.commandExecuteIn();
  
 -        switch (commandReification) {
 -            case AS_CONFIGURED:
 -                final CommandPropertiesConfiguration setting = CommandPropertiesConfiguration.parse(configuration);
 -                switch (setting) {
 -                case NONE:
 -                    return null;
 -                default:
 -                    return property != null
 -                            ? new CommandFacetForPropertyAnnotationAsConfigured(persistence, executeIn, Enablement.ENABLED, holder,
 -                            servicesInjector)
 -                            : CommandFacetFromConfiguration.create(holder, servicesInjector);
 -                }
 -            case DISABLED:
 -                return null;
 -            case ENABLED:
 -                return new CommandFacetForPropertyAnnotation(persistence, executeIn, Enablement.ENABLED, holder,
 -                        processor, servicesInjector);
 -        }
++                    final Class<? extends CommandDtoProcessor> processorClass =
++                            property != null ? property.commandDtoProcessor() : null;
++                    final CommandDtoProcessor processor = newProcessorElseNull(processorClass);
+ 
 -        return null;
++                    if(processor != null) {
++                        command = CommandReification.ENABLED;
++                    }
 +                    switch (command) {
 +                    case AS_CONFIGURED:
 +                        switch (setting) {
 +                        case NONE:
 +                            return null;
 +                        default:
 +                            return (CommandFacet)new CommandFacetForPropertyAnnotationAsConfigured(commandPersistence,
-                                     commandExecuteIn, Enablement.ENABLED, holder);
++                                    commandExecuteIn, Enablement.ENABLED, holder, servicesInjector);
 +                        }
 +                    case DISABLED:
 +                        return null;
 +                    case ENABLED:
-                         return new CommandFacetForPropertyAnnotation(commandPersistence, commandExecuteIn, Enablement.ENABLED, holder);
++                        return new CommandFacetForPropertyAnnotation(commandPersistence, commandExecuteIn, Enablement.ENABLED, holder, processor, servicesInjector);
 +                    }
 +                    throw new IllegalStateException("command '" + command + "' not recognised");
 +                })
 +                .orElseGet(() -> {
 +                    switch (setting) {
 +                    case NONE:
 +                        return null;
 +                    default:
 +                        return CommandFacetFromConfiguration.create(holder);
 +                    }
 +                });
      }
  
  
      CommandFacetForPropertyAnnotation(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
              final Enablement enablement,
-             final FacetHolder holder) {
-         super(persistence, executeIn, enablement, holder);
+             final FacetHolder holder,
+             final CommandDtoProcessor processor,
+             final ServicesInjector servicesInjector) {
+         super(persistence, executeIn, enablement, processor, holder, servicesInjector);
      }
  
  
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
index 582d8c2,ea71ae5..00816fb
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/command/CommandFacetForPropertyAnnotationAsConfigured.java
@@@ -18,18 -18,19 +18,19 @@@
   */
  package org.apache.isis.core.metamodel.facets.properties.property.command;
  
 -import org.apache.isis.applib.annotation.Command.ExecuteIn;
 -import org.apache.isis.applib.annotation.Command.Persistence;
 +import org.apache.isis.applib.annotation.CommandExecuteIn;
 +import org.apache.isis.applib.annotation.CommandPersistence;
  import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+ import org.apache.isis.core.metamodel.services.ServicesInjector;
  
  public class CommandFacetForPropertyAnnotationAsConfigured extends CommandFacetForPropertyAnnotation {
  
      CommandFacetForPropertyAnnotationAsConfigured(
 -            final Persistence persistence,
 -            final ExecuteIn executeIn,
 +            final CommandPersistence persistence,
 +            final CommandExecuteIn executeIn,
              final Enablement enablement,
-             final FacetHolder holder) {
-         super(persistence, executeIn, enablement, holder);
+             final FacetHolder holder, final ServicesInjector servicesInjector) {
+         super(persistence, executeIn, enablement, holder, null, servicesInjector);
      }
  
  
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/mustsatisfy/MustSatisfySpecificationFacetForPropertyAnnotation.java
index fa4be84,dcc56c9..5c93fbf
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/mustsatisfy/MustSatisfySpecificationFacetForPropertyAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/property/mustsatisfy/MustSatisfySpecificationFacetForPropertyAnnotation.java
@@@ -38,21 -35,15 +38,19 @@@ public class MustSatisfySpecificationFa
              final FacetHolder holder,
              final ServicesInjector servicesInjector) {
  
 -        if (property == null) {
 -            return null;
 -        }
 -
 -        final Class<?>[] values = property.mustSatisfy();
 -        final List<Specification> specifications = specificationsFor(values);
 -        return specifications.size() > 0 ? new MustSatisfySpecificationFacetForPropertyAnnotation(specifications, holder, servicesInjector) : null;
 +        List<Specification> specifications = properties.stream()
 +                .map(Property::mustSatisfy)
 +                .flatMap(classes ->
 +                        Arrays.stream(classes)
 +                              .map(MustSatisfySpecificationFacetAbstract::newSpecificationElseNull)
 +                              .filter(Objects::nonNull)
 +                )
-                 .filter(Objects::nonNull)
 +                .collect(Collectors.toList());
 +        return specifications.size() > 0
 +                ? new MustSatisfySpecificationFacetForPropertyAnnotation(specifications, holder, servicesInjector)
 +                : null;
      }
  
- 
      private MustSatisfySpecificationFacetForPropertyAnnotation(final List<Specification> specifications, final FacetHolder holder, final ServicesInjector servicesInjector) {
          super(specifications, holder, servicesInjector);
      }
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index f9c1adc,342589f..9e5b34c
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@@ -34,10 -34,14 +34,14 @@@ import org.apache.isis.applib.annotatio
  import org.apache.isis.applib.annotation.NatureOfService;
  import org.apache.isis.applib.annotation.Programmatic;
  import org.apache.isis.applib.services.bookmark.Bookmark;
+ import org.apache.isis.applib.services.command.CommandDtoProcessor;
  import org.apache.isis.applib.services.grid.GridService;
  import org.apache.isis.applib.services.metamodel.DomainMember;
 -import org.apache.isis.applib.services.metamodel.MetaModelService5;
 +import org.apache.isis.applib.services.metamodel.MetaModelService;
+ import org.apache.isis.core.metamodel.facets.actions.command.CommandFacet;
  import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
+ import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureId;
+ import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureType;
  import org.apache.isis.core.metamodel.services.appmanifest.AppManifestProvider;
  import org.apache.isis.core.metamodel.spec.ObjectSpecId;
  import org.apache.isis.core.metamodel.spec.ObjectSpecification;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
index 2a81809,09107b6..bfcc89c
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternal.java
@@@ -21,8 -21,9 +21,9 @@@ import java.util.List
  import org.apache.isis.applib.annotation.Programmatic;
  import org.apache.isis.applib.query.Query;
  import org.apache.isis.applib.services.bookmark.Bookmark;
 -import org.apache.isis.applib.services.bookmark.BookmarkService2;
 +import org.apache.isis.applib.services.bookmark.BookmarkService;
 +import org.apache.isis.applib.services.xactn.Transaction;
+ import org.apache.isis.applib.services.command.Command;
 -import org.apache.isis.applib.services.xactn.Transaction2;
  import org.apache.isis.applib.services.xactn.TransactionState;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
index 87407e1,05454f8..086400b
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/persistsession/PersistenceSessionServiceInternalNoop.java
@@@ -24,8 -24,9 +24,9 @@@ import org.apache.isis.applib.annotatio
  import org.apache.isis.applib.annotation.NatureOfService;
  import org.apache.isis.applib.query.Query;
  import org.apache.isis.applib.services.bookmark.Bookmark;
 -import org.apache.isis.applib.services.bookmark.BookmarkService2;
 +import org.apache.isis.applib.services.bookmark.BookmarkService;
 +import org.apache.isis.applib.services.xactn.Transaction;
+ import org.apache.isis.applib.services.command.Command;
 -import org.apache.isis.applib.services.xactn.Transaction2;
  import org.apache.isis.applib.services.xactn.TransactionState;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.adapter.oid.Oid;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
index 96d92de,59946d5..0848d8b
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/xactn/TransactionServiceDefault.java
@@@ -21,8 -21,9 +21,9 @@@ package org.apache.isis.core.metamodel.
  
  import org.apache.isis.applib.annotation.DomainService;
  import org.apache.isis.applib.annotation.NatureOfService;
 +import org.apache.isis.applib.services.xactn.Transaction;
 +import org.apache.isis.applib.services.xactn.TransactionService;
+ import org.apache.isis.applib.services.command.Command;
 -import org.apache.isis.applib.services.xactn.Transaction2;
 -import org.apache.isis.applib.services.xactn.TransactionService3;
  import org.apache.isis.applib.services.xactn.TransactionState;
  import org.apache.isis.core.commons.exceptions.IsisException;
  import org.apache.isis.core.metamodel.services.persistsession.PersistenceSessionServiceInternal;
@@@ -41,11 -42,21 +42,21 @@@ public class TransactionServiceDefault 
  
      @Override
      public void nextTransaction() {
-         nextTransaction(TransactionService.Policy.UNLESS_MARKED_FOR_ABORT);
+         nextTransaction((Command)null);
+     }
+ 
+     @Override
 -    public void nextTransaction(final Command command) {
 -        nextTransaction(TransactionService3.Policy.UNLESS_MARKED_FOR_ABORT, command);
++    public void nextTransaction(final Command commandIfAny) {
++        nextTransaction(TransactionService.Policy.UNLESS_MARKED_FOR_ABORT, commandIfAny);
      }
  
      @Override
 -    public void nextTransaction(TransactionService3.Policy policy) {
 +    public void nextTransaction(TransactionService.Policy policy) {
+         nextTransaction(policy, null);
+     }
+ 
+     @Override
 -    public void nextTransaction(TransactionService3.Policy policy, final Command commandIfAny) {
++    public void nextTransaction(TransactionService.Policy policy, final Command commandIfAny) {
          final TransactionState transactionState = getTransactionState();
          switch (transactionState) {
          case NONE:
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
index dd405ea,4e753eb..7d4e842
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
@@@ -23,23 -23,27 +23,24 @@@ import java.util.Collections
  import java.util.Comparator;
  import java.util.List;
  
 -import javax.annotation.Nullable;
 -
  import com.google.common.base.Function;
  
+ import org.apache.isis.applib.annotation.DomainObject;
 -import org.apache.isis.applib.annotation.ObjectType;
  import org.apache.isis.core.commons.authentication.AuthenticationSession;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.consent.Consent;
  import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
  import org.apache.isis.core.metamodel.consent.InteractionResult;
--import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
  import org.apache.isis.core.metamodel.facets.all.describedas.DescribedAsFacet;
  import org.apache.isis.core.metamodel.facets.all.help.HelpFacet;
  import org.apache.isis.core.metamodel.facets.all.hide.HiddenFacet;
  import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
--import org.apache.isis.core.metamodel.facets.object.parented.ParentedCollectionFacet;
++import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
  import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
  import org.apache.isis.core.metamodel.facets.object.icon.IconFacet;
  import org.apache.isis.core.metamodel.facets.object.immutable.ImmutableFacet;
  import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
++import org.apache.isis.core.metamodel.facets.object.parented.ParentedCollectionFacet;
  import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
  import org.apache.isis.core.metamodel.facets.object.plural.PluralFacet;
  import org.apache.isis.core.metamodel.facets.object.title.TitleFacet;
@@@ -162,7 -187,7 +184,7 @@@ public interface ObjectSpecification ex
       * Returns the title string for the specified object.
       * 
       * <p>
--     * Corresponds to the {@link TitleFacet#value()) value} of
++     * Corresponds to the {@link TitleFacet#title(ObjectAdapter)} ) value} of
       * {@link TitleFacet}; is not necessarily immutable.
       * 
       * @deprecated use {@link #getTitle(ObjectAdapter, ObjectAdapter)}
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index c225cf8,bbdbeb4..0c421e4
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@@ -374,11 -385,151 +378,59 @@@ public interface ObjectAction extends O
          private Predicates() {
          }
  
 -        public static Predicate<ObjectAction> dynamicallyVisible(
 -                final ObjectAdapter target,
 -                final InteractionInitiatedBy interactionInitiatedBy,
 -                final Where where) {
 -            return org.apache.isis.applib.filter.Filters
 -                    .asPredicate(Filters.dynamicallyVisible(target, interactionInitiatedBy, where));
 -        }
 -
 -        public static Predicate<ObjectAction> withId(final String actionId) {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.withId(actionId));
 -        }
 -
 -        public static Predicate<ObjectAction> withNoValidationRules() {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.withNoValidationRules());
 -        }
 -
 -        public static Predicate<ObjectAction> ofType(final ActionType type) {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.ofType(type));
 -        }
 -
 -        public static Predicate<ObjectAction> bulk() {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.bulk());
 -        }
 -
 -        // UNUSED?
 -        public static Predicate<ObjectAction> notBulkOnly() {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.notBulkOnly());
 -        }
 -
 -        public static Predicate<ObjectAction> memberOrderOf(ObjectAssociation association) {
 -            return org.apache.isis.applib.filter.Filters.asPredicate(Filters.memberOrderOf(association));
 -        }
 -
+         public static Predicate<ObjectAction> associatedWith(final String collectionName) {
+             return new AssociatedWith(collectionName);
+         }
+ 
+         public static Predicate<ObjectAction> associatedWithAndWithCollectionParameterFor(
+                 final String collectionName,
+                 final ObjectSpecification collectionTypeOfSpec) {
+ 
+             return com.google.common.base.Predicates.and(
+                     new AssociatedWith(collectionName),
+                     new HasParameterMatching(
+                         new ObjectActionParameter.Predicates.CollectionParameter(collectionTypeOfSpec)
+                     )
+             );
+         }
+ 
+         public static class AssociatedWith implements Predicate<ObjectAction> {
+             private final String memberNameAssociatedWith;
+             public AssociatedWith(final String memberNameAssociatedWith) {
+                 this.memberNameAssociatedWith = memberNameAssociatedWith;
+             }
+ 
+             @Override
+             public boolean apply(final ObjectAction objectAction) {
+                 final MemberOrderFacet memberOrderFacet = objectAction.getFacet(MemberOrderFacet.class);
+                 if(memberOrderFacet == null) {
+                     return false;
+                 }
+                 final String name = memberNameAssociatedWith;
+                 final String memberOrderName = memberOrderFacet.untranslatedName();
+                 return name != null && memberOrderName != null &&
+                        Objects.equal(name.toLowerCase(), memberOrderName.toLowerCase());
+             }
+         }
+ 
+         public static class HasParameterMatching implements Predicate<ObjectAction> {
+             private final Predicate<ObjectActionParameter> parameterPredicate;
+             public HasParameterMatching(final Predicate<ObjectActionParameter> parameterPredicate) {
+                 this.parameterPredicate = parameterPredicate;
+             }
+ 
+             @Override
+             public boolean apply(@Nullable final ObjectAction objectAction) {
+                 return FluentIterable
+                         .from(objectAction.getParameters())
+                         .anyMatch(parameterPredicate);
+             }
+         }
 -    }
 -
 -    //endregion
  
 -    //region > Filters
 -
 -    public static final class Filters {
 -
 -        private Filters() {
 -        }
 -
 -        /**
 -         * @deprecated -use {@link com.google.common.base.Predicate equivalent}
 -         */
 -        @Deprecated
 -        public static Filter<ObjectAction> dynamicallyVisible(
 -                final ObjectAdapter target,
 -                final InteractionInitiatedBy interactionInitiatedBy,
 -                final Where where) {
 -            return new Filter<ObjectAction>() {
 +        public static com.google.common.base.Predicate ofType(final ActionType type) {
 +            return new Predicate<ObjectAction>() {
                  @Override
 -                public boolean accept(final ObjectAction objectAction) {
 -                    final Consent visible = objectAction.isVisible(target, interactionInitiatedBy, where);
 -                    return visible.isAllowed();
 -                }
 -            };
 -        }
 -
 -        /**
 -         * @deprecated -use {@link com.google.common.base.Predicate equivalent}
 -         */
 -        @Deprecated
 -        public static Filter<ObjectAction> withId(final String actionId) {
 -            return new Filter<ObjectAction>() {
 -                @Override
 -                public boolean accept(ObjectAction objectAction) {
 -                    return objectAction.getId().equals(actionId);
 -                }
 -            };
 -        }
 -
 -        /**
 -         * @deprecated -use {@link com.google.common.base.Predicate equivalent}
 -         */
 -        @Deprecated
 -        public static Filter<ObjectAction> withNoValidationRules() {
 -            return new Filter<ObjectAction>() {
 -                @Override
 -                public boolean accept(final ObjectAction objectAction) {
 -                    final List<Facet> validatingFacets = objectAction.getFacets(FacetFilters
 -                            .isA(ValidatingInteractionAdvisor.class));
 -                    return validatingFacets.isEmpty();
 -                }
 -            };
 -        }
 -
 -        /**
 -         * @deprecated -use {@link com.google.common.base.Predicate equivalent}
 -         */
 -        @Deprecated
 -        public static Filter<ObjectAction> ofType(final ActionType type) {
 -            return new Filter<ObjectAction>() {
 -                @Override
 -                public boolean accept(ObjectAction oa) {
 +                public boolean apply(ObjectAction oa) {
                      return oa.getType() == type;
                  }
              };
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
index 6ababf3,df26433..c0e7043
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
@@@ -19,9 -19,12 +19,12 @@@
  
  package org.apache.isis.core.metamodel.spec.feature;
  
+ import javax.annotation.Nullable;
+ 
  import com.google.common.base.Function;
+ import com.google.common.base.Predicate;
  
 -import org.apache.isis.applib.filter.Filter;
 +import com.google.common.base.Predicate;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
  import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
index 702ab74,ca81150..32004bc
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/SpecificationLoader.java
@@@ -96,17 -98,26 +99,22 @@@ public class SpecificationLoader implem
  
      private final MetaModelValidator metaModelValidator;
      private final SpecificationCacheDefault cache = new SpecificationCacheDefault();
 -    private final List<LayoutMetadataReader> layoutMetadataReaders;
+     private final PostProcessor postProcessor;
  
      public SpecificationLoader(
+             final IsisConfiguration configuration,
              final ProgrammingModel programmingModel,
              final MetaModelValidator metaModelValidator,
 -            final List<LayoutMetadataReader> layoutMetadataReaders,
              final ServicesInjector servicesInjector) {
  
+         this.configuration = configuration;
+ 
          this.servicesInjector = servicesInjector;
          this.programmingModel = programmingModel;
          this.metaModelValidator = metaModelValidator;
  
          this.facetProcessor = new FacetProcessor(programmingModel);
+         this.postProcessor = new PostProcessor(programmingModel, servicesInjector);
 -
 -        this.layoutMetadataReaders = layoutMetadataReaders;
      }
  
      @Override
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index 2b77b34,4446489..7b5871d
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@@ -185,9 -203,9 +185,9 @@@ public class FacetedMethodsBuilder 
      // ////////////////////////////////////////////////////////////////////////////
  
  
 -    public Properties introspectClass() {
 +    public void introspectClass() {
          if (LOG.isInfoEnabled()) {
-             LOG.info("introspecting " + getClassName() + ": class-level details");
+             LOG.info("introspecting {}: class-level details", getClassName());
          }
  
          // process facets at object level
@@@ -238,9 -311,9 +238,9 @@@
          return associationFacetMethods;
      }
  
 -    private List<FacetedMethod> createAssociationFacetedMethods(Properties properties) {
 +    private List<FacetedMethod> createAssociationFacetedMethods() {
          if (LOG.isDebugEnabled()) {
-             LOG.debug("introspecting " + getClassName() + ": properties and collections");
+             LOG.debug("introspecting {}: properties and collections", getClassName());
          }
          final Set<Method> associationCandidateMethods = getFacetProcessor().findAssociationCandidateAccessors(methods, new HashSet<Method>());
  
@@@ -277,15 -351,13 +277,15 @@@
          findAndRemovePrefixedNonVoidMethods(MethodScope.OBJECT, GET_PREFIX, Object.class, 0, propertyAccessors);
          findAndRemovePrefixedNonVoidMethods(MethodScope.OBJECT, IS_PREFIX, Boolean.class, 0, propertyAccessors);
  
 -        createPropertyFacetedMethodsFromAccessors(propertyAccessors, fields, properties);
 +        createPropertyFacetedMethodsFromAccessors(propertyAccessors, fields);
      }
  
 -    private void createCollectionFacetedMethodsFromAccessors(final List<Method> accessorMethods, final List<FacetedMethod> facetMethodsToAppendto, Properties properties) {
 +    private void createCollectionFacetedMethodsFromAccessors(
 +            final List<Method> accessorMethods,
 +            final List<FacetedMethod> facetMethodsToAppendto) {
          for (final Method accessorMethod : accessorMethods) {
              if (LOG.isDebugEnabled()) {
-                 LOG.debug("  identified accessor method representing collection: " + accessorMethod);
+                 LOG.debug("  identified accessor method representing collection: {}", accessorMethod);
              }
  
              // create property and add facets
@@@ -309,12 -381,10 +309,12 @@@
          }
      }
  
 -    private void createPropertyFacetedMethodsFromAccessors(final List<Method> accessorMethods, final List<FacetedMethod> facetedMethodsToAppendto, Properties properties) throws MetaModelException {
 +    private void createPropertyFacetedMethodsFromAccessors(
 +            final List<Method> accessorMethods,
 +            final List<FacetedMethod> facetedMethodsToAppendto) throws MetaModelException {
  
          for (final Method accessorMethod : accessorMethods) {
-             LOG.debug("  identified accessor method representing property: " + accessorMethod);
+             LOG.debug("  identified accessor method representing property: {}", accessorMethod);
  
              final Class<?> returnType = accessorMethod.getReturnType();
  
@@@ -362,12 -432,13 +362,12 @@@
       * Perhaps it's important to skip helpers first. I doubt it, though.
       */
      private List<FacetedMethod> findActionFacetedMethods(
 -            final MethodScope methodScope, 
 -            final Properties metadataProperties) {
 +            final MethodScope methodScope) {
          if (LOG.isDebugEnabled()) {
-             LOG.debug("introspecting " + getClassName() + ": actions");
+             LOG.debug("introspecting {}: actions", getClassName());
          }
 -        final List<FacetedMethod> actionFacetedMethods1 = findActionFacetedMethods(methodScope, RecognisedHelpersStrategy.SKIP, metadataProperties);
 -        final List<FacetedMethod> actionFacetedMethods2 = findActionFacetedMethods(methodScope, RecognisedHelpersStrategy.DONT_SKIP, metadataProperties);
 +        final List<FacetedMethod> actionFacetedMethods1 = findActionFacetedMethods(methodScope, RecognisedHelpersStrategy.SKIP);
 +        final List<FacetedMethod> actionFacetedMethods2 = findActionFacetedMethods(methodScope, RecognisedHelpersStrategy.DONT_SKIP);
          return ListExtensions.combineWith(actionFacetedMethods1, actionFacetedMethods2);
      }
  
diff --cc core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index 720fdfd,65d2ff3..ddcbd68
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@@ -173,11 -175,8 +173,6 @@@ public class ObjectSpecificationDefaul
          }
  
  
--
-         if(isNotIntrospected()) {
-             facetedMethodsBuilder.introspectClassPostProcessing();
-         }
-         
 -
          if(isNotIntrospected()) {
              updateFromFacetValues();    
          }
diff --cc core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/JavaReflectorHelper.java
index 52835a8,ee0b8ce..4dc3dfe
--- a/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/JavaReflectorHelper.java
+++ b/core/metamodel/src/main/java/org/apache/isis/progmodels/dflt/JavaReflectorHelper.java
@@@ -57,7 -60,7 +57,7 @@@ public final class JavaReflectorHelpe
              programmingModel.refineMetaModelValidator(metaModelValidator, configuration);
          }
  
-         return new SpecificationLoader(programmingModel, metaModelValidator, servicesInjector);
 -        return new SpecificationLoader(configuration, programmingModel, metaModelValidator, layoutMetadataReaders, servicesInjector);
++        return new SpecificationLoader(configuration, programmingModel, metaModelValidator, servicesInjector);
      }
  
  }
diff --cc core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
index 47b2183,8e386f2..2360cbe
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/specloader/SpecificationLoaderTestAbstract.java
@@@ -106,8 -108,9 +106,8 @@@ public abstract class SpecificationLoad
  
          final SpecificationLoader specificationLoader =
                  new SpecificationLoader(
-                         new ProgrammingModelFacetsJava5(stubConfiguration),
+                         stubConfiguration, new ProgrammingModelFacetsJava5(stubConfiguration),
 -                        new MetaModelValidatorDefault(), Lists.<LayoutMetadataReader>newArrayList(
 -                                new LayoutMetadataReaderFromJson()), stubServicesInjector);
 +                        new MetaModelValidatorDefault(), stubServicesInjector);
  
          stubServicesInjector.addFallbackIfRequired(SpecificationLoader.class, specificationLoader);
  
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
index 751d85e,90c2bc4..0d5ec9d
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/BackgroundCommandExecution.java
@@@ -16,32 -16,16 +16,32 @@@
   */
  package org.apache.isis.core.runtime.services.background;
  
- import java.sql.Timestamp;
- import java.util.Collections;
  import java.util.List;
  
- import com.google.common.base.Function;
- import com.google.common.base.Throwables;
- import com.google.common.collect.Iterables;
  import com.google.common.collect.Lists;
  
 +import org.apache.isis.applib.services.bookmark.Bookmark;
 +import org.apache.isis.applib.services.bookmark.BookmarkService;
 +import org.apache.isis.applib.services.clock.ClockService;
 +import org.apache.isis.applib.services.command.Command;
 +import org.apache.isis.applib.services.command.Command.Executor;
 +import org.apache.isis.applib.services.iactn.Interaction;
 +import org.apache.isis.applib.services.iactn.InteractionContext;
 +import org.apache.isis.applib.services.jaxb.JaxbService;
 +import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
 +import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 +import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 +import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 +import org.apache.isis.core.metamodel.spec.feature.Contributed;
 +import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 +import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 +import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 +import org.apache.isis.core.runtime.sessiontemplate.AbstractIsisSessionTemplate;
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
 -import org.apache.isis.applib.services.command.Command;
+ import org.apache.isis.applib.services.command.CommandExecutorService;
+ import org.apache.isis.applib.services.command.CommandWithDto;
  import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
  import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
  import org.apache.isis.core.runtime.system.transaction.TransactionalClosure;
@@@ -65,24 -37,40 +53,36 @@@
   * This implementation uses the {@link #findBackgroundCommandsToExecute() hook method} so that it is
   * independent of the location where the actions have actually been persisted to.
   */
- public abstract class BackgroundCommandExecution extends AbstractIsisSessionTemplate {
+ public abstract class BackgroundCommandExecution extends CommandExecutionAbstract {
  
+     private final static Logger LOG = LoggerFactory.getLogger(BackgroundCommandExecution.class);
  
+     /**
+      * Defaults to the historical defaults * for running background commands.
+      */
+     public BackgroundCommandExecution() {
+         this(CommandExecutorService.SudoPolicy.NO_SWITCH);
+     }
+ 
+     public BackgroundCommandExecution(final CommandExecutorService.SudoPolicy sudoPolicy) {
+         super(sudoPolicy);
+     }
+ 
+     // //////////////////////////////////////
  
 -    
      protected void doExecute(Object context) {
  
          final PersistenceSession persistenceSession = getPersistenceSession();
          final IsisTransactionManager transactionManager = getTransactionManager(persistenceSession);
-         final List<Command> backgroundCommands = Lists.newArrayList();
-         transactionManager.executeWithinTransaction(new TransactionalClosure() {
-             @Override
-             public void execute() {
-                 backgroundCommands.addAll(findBackgroundCommandsToExecute());
-             }
+         final List<Command> commands = Lists.newArrayList();
 -        transactionManager.executeWithinTransaction(new TransactionalClosure() {
 -            @Override
 -            public void execute() {
 -                commands.addAll(findBackgroundCommandsToExecute());
 -            }
++        transactionManager.executeWithinTransaction(() -> {
++            commands.addAll(findBackgroundCommandsToExecute());
          });
  
-         for (final Command backgroundCommand : backgroundCommands) {
-             execute(transactionManager, backgroundCommand);
+         LOG.debug("Found {} to execute", commands.size());
+ 
+         for (final Command command : commands) {
+             execute(transactionManager, (CommandWithDto) command);
          }
      }
  
@@@ -91,210 -79,5 +91,4 @@@
       */
      protected abstract List<? extends Command> findBackgroundCommandsToExecute();
  
-     // //////////////////////////////////////
- 
-     
-     private void execute(
-             final IsisTransactionManager transactionManager,
-             final Command backgroundCommand) {
- 
-         transactionManager.executeWithinTransaction(
-                 backgroundCommand,
-                 new TransactionalClosure() {
-             @Override
-             public void execute() {
- 
-                 // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
-                 final Interaction backgroundInteraction = interactionContext.getInteraction();
- 
-                 final String memento = backgroundCommand.getMemento();
- 
-                 try {
-                     backgroundCommand.setExecutor(Executor.BACKGROUND);
- 
-                     final CommandDto dto = jaxbService.fromXml(CommandDto.class, memento);
- 
-                     final MemberDto memberDto = dto.getMember();
-                     final String memberId = memberDto.getMemberIdentifier();
- 
-                     final OidsDto oidsDto = CommandDtoUtils.targetsFor(dto);
-                     final List<OidDto> targetOidDtos = oidsDto.getOid();
- 
-                     final InteractionType interactionType = memberDto.getInteractionType();
-                     if(interactionType == InteractionType.ACTION_INVOCATION) {
- 
-                         final ActionDto actionDto = (ActionDto) memberDto;
- 
-                         for (OidDto targetOidDto : targetOidDtos) {
- 
-                             final ObjectAdapter targetAdapter = adapterFor(targetOidDto);
-                             final ObjectAction objectAction = findObjectAction(targetAdapter, memberId);
- 
-                             // we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then
-                             // it will switch the targetAdapter to be the mixedInAdapter transparently
-                             final ObjectAdapter[] argAdapters = argAdaptersFor(actionDto);
-                             final ObjectAdapter resultAdapter = objectAction.execute(
-                                     targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK);
- 
-                             //
-                             // for the result adapter, we could alternatively have used...
-                             // (priorExecution populated by the push/pop within the interaction object)
-                             //
-                             // final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution();
-                             // Object unused = priorExecution.getReturned();
-                             //
- 
-                             // REVIEW: this doesn't really make sense if >1 action
-                             // in any case, the capturing of the action interaction should be the
-                             // responsibility of auditing/profiling
-                             if(resultAdapter != null) {
-                                 Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter);
-                                 backgroundCommand.setResult(resultBookmark);
-                             }
-                         }
-                     } else {
- 
-                         final PropertyDto propertyDto = (PropertyDto) memberDto;
- 
-                         for (OidDto targetOidDto : targetOidDtos) {
- 
-                             final Bookmark bookmark = Bookmark.from(targetOidDto);
-                             final Object targetObject = bookmarkService.lookup(bookmark);
- 
-                             final ObjectAdapter targetAdapter = adapterFor(targetObject);
- 
-                             final OneToOneAssociation property = findOneToOneAssociation(targetAdapter, memberId);
- 
-                             final ObjectAdapter newValueAdapter = newValueAdapterFor(propertyDto);
- 
-                             property.set(targetAdapter, newValueAdapter, InteractionInitiatedBy.FRAMEWORK);
-                             // there is no return value for property modifications.
-                         }
-                     }
- 
-                 } catch (RuntimeException e) {
-                     // hmmm, this doesn't really make sense if >1 action
-                     //
-                     // in any case, the capturing of the result of the action invocation should be the
-                     // responsibility of the interaction...
-                     backgroundCommand.setException(Throwables.getStackTraceAsString(e));
- 
-                     // lower down the stack the IsisTransactionManager will have set the transaction to abort
-                     // however, we don't want that to occur (because any changes made to the backgroundCommand itself
-                     // would also be rolled back, and it would keep getting picked up again by a scheduler for
-                     // processing); instead we clear the abort cause and ensure we can continue.
-                     transactionManager.getCurrentTransaction().clearAbortCauseAndContinue();
-                 }
- 
-                 // it's possible that there is no priorExecution, specifically if there was an exception
-                 // invoking the action.  We therefore need to guard that case.
-                 final Interaction.Execution<?,?> priorExecution = backgroundInteraction.getPriorExecution();
-                 final Timestamp completedAt =
-                         priorExecution != null
-                                 ? priorExecution.getCompletedAt()
-                                 : clockService.nowAsJavaSqlTimestamp();  // close enough...
-                 backgroundCommand.setCompletedAt(completedAt);
-             }
- 
-             private ObjectAction findObjectAction(
-                     final ObjectAdapter targetAdapter,
-                     final String actionId) throws RuntimeException {
- 
-                 final ObjectSpecification specification = targetAdapter.getSpecification();
- 
-                 final ObjectAction objectAction = findActionElseNull(specification, actionId);
-                 if(objectAction == null) {
-                     throw new RuntimeException(String.format("Unknown action '%s'", actionId));
-                 }
-                 return objectAction;
-             }
- 
-             private OneToOneAssociation findOneToOneAssociation(
-                     final ObjectAdapter targetAdapter,
-                     final String propertyId) throws RuntimeException {
- 
- 
-                 final ObjectSpecification specification = targetAdapter.getSpecification();
- 
-                 final OneToOneAssociation property = findOneToOneAssociationElseNull(specification, propertyId);
-                 if(property == null) {
-                     throw new RuntimeException(String.format("Unknown property '%s'", propertyId));
-                 }
-                 return property;
-             }
-         });
-     }
- 
-     protected ObjectAdapter newValueAdapterFor(final PropertyDto propertyDto) {
-         final ValueWithTypeDto newValue = propertyDto.getNewValue();
-         final Object arg = CommonDtoUtils.getValue(newValue);
-         return adapterFor(arg);
-     }
- 
-     private static ObjectAction findActionElseNull(
-             final ObjectSpecification specification,
-             final String actionId) {
-         final List<ObjectAction> objectActions = specification.getObjectActions(Contributed.INCLUDED);
-         for (final ObjectAction objectAction : objectActions) {
-             if(objectAction.getIdentifier().toClassAndNameIdentityString().equals(actionId)) {
-                 return objectAction;
-             }
-         }
-         return null;
-     }
- 
-     private static OneToOneAssociation findOneToOneAssociationElseNull(
-             final ObjectSpecification specification,
-             final String propertyId) {
-         final List<ObjectAssociation> associations = specification.getAssociations(Contributed.INCLUDED);
-         for (final ObjectAssociation association : associations) {
-             if( association.getIdentifier().toClassAndNameIdentityString().equals(propertyId) &&
-                 association instanceof OneToOneAssociation) {
-                 return (OneToOneAssociation) association;
-             }
-         }
-         return null;
-     }
- 
-     private ObjectAdapter[] argAdaptersFor(final ActionDto actionDto) {
-         final List<ParamDto> params = paramDtosFrom(actionDto);
-         final List<ObjectAdapter> args = Lists.newArrayList(
-                 Iterables.transform(params, new Function<ParamDto, ObjectAdapter>() {
-                     @Override
-                     public ObjectAdapter apply(final ParamDto paramDto) {
-                         final Object arg = CommonDtoUtils.getValue(paramDto);
-                         return adapterFor(arg);
-                     }
-                 })
-         );
-         return args.toArray(new ObjectAdapter[]{});
-     }
- 
-     private static List<ParamDto> paramDtosFrom(final ActionDto actionDto) {
-         final ParamsDto parameters = actionDto.getParameters();
-         if (parameters != null) {
-             final List<ParamDto> parameterList = parameters.getParameter();
-             if (parameterList != null) {
-                 return parameterList;
-             }
-         }
-         return Collections.emptyList();
-     }
- 
-     // //////////////////////////////////////
- 
- 
-     @javax.inject.Inject
-     BookmarkService bookmarkService;
- 
-     @javax.inject.Inject
-     JaxbService jaxbService;
- 
-     @javax.inject.Inject
-     InteractionContext interactionContext;
- 
-     @javax.inject.Inject
-     ClockService clockService;
- 
--
  }
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutorServiceDefault.java
index 0000000,cb29cf0..c27f847
mode 000000,100644..100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutorServiceDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/background/CommandExecutorServiceDefault.java
@@@ -1,0 -1,430 +1,429 @@@
+ /**
+  *  Licensed to the Apache Software Foundation (ASF) under one or more
+  *  contributor license agreements.  See the NOTICE file distributed with
+  *  this work for additional information regarding copyright ownership.
+  *  The ASF licenses this file to You under the Apache License, Version 2.0
+  *  (the "License"); you may not use this file except in compliance with
+  *  the License.  You may obtain a copy of the License at
+  *
+  *     http://www.apache.org/licenses/LICENSE-2.0
+  *
+  *  Unless required by applicable law or agreed to in writing, software
+  *  distributed under the License is distributed on an "AS IS" BASIS,
+  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  *  See the License for the specific language governing permissions and
+  *  limitations under the License.
+  */
+ package org.apache.isis.core.runtime.services.background;
+ 
+ import java.sql.Timestamp;
+ import java.util.Collections;
+ import java.util.List;
+ 
+ import com.google.common.base.Function;
+ import com.google.common.base.Throwables;
+ import com.google.common.collect.Iterables;
+ import com.google.common.collect.Lists;
+ 
+ import org.slf4j.Logger;
+ import org.slf4j.LoggerFactory;
+ 
+ import org.apache.isis.applib.annotation.DomainService;
+ import org.apache.isis.applib.annotation.NatureOfService;
+ import org.apache.isis.applib.annotation.Programmatic;
+ import org.apache.isis.applib.services.bookmark.Bookmark;
+ import org.apache.isis.applib.services.bookmark.BookmarkService2;
+ import org.apache.isis.applib.services.clock.ClockService;
+ import org.apache.isis.applib.services.command.Command;
+ import org.apache.isis.applib.services.command.CommandContext;
+ import org.apache.isis.applib.services.command.CommandExecutorService;
+ import org.apache.isis.applib.services.command.CommandWithDto;
+ import org.apache.isis.applib.services.iactn.Interaction;
+ import org.apache.isis.applib.services.iactn.InteractionContext;
+ import org.apache.isis.applib.services.sudo.SudoService;
+ import org.apache.isis.applib.services.xactn.Transaction2;
 -import org.apache.isis.applib.services.xactn.TransactionService3;
+ import org.apache.isis.applib.services.xactn.TransactionState;
+ import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+ import org.apache.isis.core.metamodel.adapter.oid.RootOid;
+ import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+ import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
+ import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+ import org.apache.isis.core.metamodel.spec.feature.Contributed;
+ import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+ import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+ import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+ import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
+ import org.apache.isis.core.runtime.system.context.IsisContext;
+ import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
+ import org.apache.isis.core.runtime.system.session.IsisSessionFactory;
+ import org.apache.isis.core.runtime.system.transaction.IsisTransactionManager;
+ import org.apache.isis.schema.cmd.v1.ActionDto;
+ import org.apache.isis.schema.cmd.v1.CommandDto;
+ import org.apache.isis.schema.cmd.v1.MemberDto;
+ import org.apache.isis.schema.cmd.v1.ParamDto;
+ import org.apache.isis.schema.cmd.v1.ParamsDto;
+ import org.apache.isis.schema.cmd.v1.PropertyDto;
+ import org.apache.isis.schema.common.v1.CollectionDto;
+ import org.apache.isis.schema.common.v1.InteractionType;
+ import org.apache.isis.schema.common.v1.OidDto;
+ import org.apache.isis.schema.common.v1.OidsDto;
+ import org.apache.isis.schema.common.v1.ValueDto;
+ import org.apache.isis.schema.common.v1.ValueType;
+ import org.apache.isis.schema.common.v1.ValueWithTypeDto;
+ import org.apache.isis.schema.utils.CommandDtoUtils;
+ import org.apache.isis.schema.utils.CommonDtoUtils;
+ 
+ @DomainService(nature = NatureOfService.DOMAIN)
+ public class CommandExecutorServiceDefault implements CommandExecutorService {
+ 
+     private final static Logger LOG = LoggerFactory.getLogger(CommandExecutorServiceDefault.class);
+ 
+     @Programmatic
+     public void executeCommand(
+             final CommandExecutorService.SudoPolicy sudoPolicy,
+             final CommandWithDto commandWithDto) {
+ 
+         ensureTransactionInProgressWithContext(commandWithDto);
+ 
+         switch (sudoPolicy) {
+         case NO_SWITCH:
+             executeCommand(commandWithDto);
+             break;
+         case SWITCH:
+             final String user = commandWithDto.getUser();
+             sudoService.sudo(user, new Runnable() {
+                 @Override
+                 public void run() {
+                     executeCommand(commandWithDto);
+                 }
+             });
+             break;
+         default:
+             throw new IllegalStateException("Probable framework error, unrecognized sudoPolicy: " + sudoPolicy);
+         }
+ 
+         // double check that we've ended up in the same state
+         ensureTransactionInProgress();
+     }
+ 
+     private void ensureTransactionInProgressWithContext(final Command command) {
+ 
+         ensureTransactionInProgress();
+ 
+         // check the required command is used as the context.
+         // this will ensure that any audit entries also inherit from this existing command.
+         if(commandContext.getCommand() != command) {
+             transactionService.nextTransaction(command);
+         }
+     }
+ 
+     private void ensureTransactionInProgress() {
+         final Transaction2 currentTransaction = transactionService.currentTransaction();
+         if(currentTransaction == null) {
+             throw new IllegalStateException("No current transaction");
+         }
+         final TransactionState transactionState = currentTransaction.getTransactionState();
+         if(!transactionState.canCommit()) {
+             throw new IllegalStateException("Current transaction is not in a state to be committed, is: " + transactionState);
+         }
+     }
+ 
+     protected void executeCommand(final CommandWithDto commandWithDto) {
+ 
+         // setup for us by IsisTransactionManager; will have the transactionId of the backgroundCommand
+         final Interaction interaction = interactionContext.getInteraction();
+ 
+         org.apache.isis.applib.annotation.Command.ExecuteIn executeIn = commandWithDto.getExecuteIn();
+ 
+         LOG.info("Executing: {} {} {} {}", executeIn, commandWithDto.getMemberIdentifier(), commandWithDto.getTimestamp(), commandWithDto.getTransactionId());
+ 
+         RuntimeException exceptionIfAny = null;
+ 
+         try {
+             commandWithDto.setExecutor(Command.Executor.BACKGROUND);
+ 
+             // responsibility for setting the Command#startedAt is in the ActionInvocationFacet or
+             // PropertySetterFacet, but this is run if the domain object was found.  If the domain object is
+             // thrown then we would have a command with only completedAt, which is inconsistent.
+             // Therefore instead we copy down from the backgroundInteraction (similar to how we populate the
+             // completedAt at the end)
+             final Interaction.Execution currentExecution = interaction.getCurrentExecution();
+ 
+             final Timestamp startedAt = currentExecution != null
+                     ? currentExecution.getStartedAt()
+                     : clockService.nowAsJavaSqlTimestamp();
+ 
+             commandWithDto.setStartedAt(startedAt);
+ 
+             final CommandDto dto = commandWithDto.asDto();
+ 
+             final MemberDto memberDto = dto.getMember();
+             final String memberId = memberDto.getMemberIdentifier();
+ 
+             final OidsDto oidsDto = CommandDtoUtils.targetsFor(dto);
+             final List<OidDto> targetOidDtos = oidsDto.getOid();
+ 
+             final InteractionType interactionType = memberDto.getInteractionType();
+             if(interactionType == InteractionType.ACTION_INVOCATION) {
+ 
+                 final ActionDto actionDto = (ActionDto) memberDto;
+ 
+                 for (OidDto targetOidDto : targetOidDtos) {
+ 
+                     final ObjectAdapter targetAdapter = adapterFor(targetOidDto);
+                     final ObjectAction objectAction = findObjectAction(targetAdapter, memberId);
+ 
+                     // we pass 'null' for the mixedInAdapter; if this action _is_ a mixin then
+                     // it will switch the targetAdapter to be the mixedInAdapter transparently
+                     final ObjectAdapter[] argAdapters = argAdaptersFor(actionDto);
+                     final ObjectAdapter resultAdapter = objectAction.execute(
+                             targetAdapter, null, argAdapters, InteractionInitiatedBy.FRAMEWORK);
+ 
+                     // flush any Isis PersistenceCommands pending
+                     // (else might get transient objects for the return value)
+                     transactionService.flushTransaction();
+ 
+                     //
+                     // for the result adapter, we could alternatively have used...
+                     // (priorExecution populated by the push/pop within the interaction object)
+                     //
+                     // final Interaction.Execution priorExecution = backgroundInteraction.getPriorExecution();
+                     // Object unused = priorExecution.getReturned();
+                     //
+ 
+                     // REVIEW: this doesn't really make sense if >1 action
+                     if(resultAdapter != null) {
+                         Bookmark resultBookmark = CommandUtil.bookmarkFor(resultAdapter);
+                         commandWithDto.setResult(resultBookmark);
+                     }
+                 }
+             } else {
+ 
+                 final PropertyDto propertyDto = (PropertyDto) memberDto;
+ 
+                 for (OidDto targetOidDto : targetOidDtos) {
+ 
+                     final Bookmark bookmark = Bookmark.from(targetOidDto);
+                     final Object targetObject = bookmarkService.lookup(bookmark);
+ 
+                     final ObjectAdapter targetAdapter = adapterFor(targetObject);
+ 
+                     final OneToOneAssociation property = findOneToOneAssociation(targetAdapter, memberId);
+ 
+                     final ObjectAdapter newValueAdapter = newValueAdapterFor(propertyDto);
+ 
+                     property.set(targetAdapter, newValueAdapter, InteractionInitiatedBy.FRAMEWORK);
+ 
+                     // there is no return value for property modifications.
+                 }
+             }
+ 
+         } catch (RuntimeException ex) {
+ 
+             LOG.warn("Exception when executing : {} {}", executeIn, commandWithDto.getMemberIdentifier(), ex);
+ 
+             exceptionIfAny = ex;
+         }
+ 
+         // committing the xactn might also trigger an exception
+         try {
+             transactionService.nextTransaction(TransactionService3.Policy.ALWAYS);
+         } catch(RuntimeException ex) {
+ 
+             LOG.warn("Exception when committing : {} {}", executeIn, commandWithDto.getMemberIdentifier(), ex);
+ 
+             if(exceptionIfAny == null) {
+                 exceptionIfAny = ex;
+             }
+ 
+             // this will set up a new transaction
+             transactionService.nextTransaction();
+         }
+ 
+         // it's possible that there is no priorExecution, specifically if there was an exception
+         // when performing the action invocation/property edit.  We therefore need to guard that case.
+         final Interaction.Execution priorExecution = interaction.getPriorExecution();
+         if (commandWithDto.getStartedAt() == null) {
+             // if attempting to commit the xactn threw an error, we will (I think?) have lost this info, so need to
+             // capture
+             commandWithDto.setStartedAt(
+                     priorExecution != null
+                             ? priorExecution.getStartedAt()
+                             : clockService.nowAsJavaSqlTimestamp());
+         }
+ 
+         final Timestamp completedAt =
+                 priorExecution != null
+                         ? priorExecution.getCompletedAt()
+                         : clockService.nowAsJavaSqlTimestamp();  // close enough...
+         commandWithDto.setCompletedAt(completedAt);
+ 
+         if(exceptionIfAny != null) {
+             commandWithDto.setException(Throwables.getStackTraceAsString(exceptionIfAny));
+         }
+     }
+ 
+     // //////////////////////////////////////
+ 
+     private static ObjectAction findObjectAction(
+             final ObjectAdapter targetAdapter,
+             final String actionId) throws RuntimeException {
+ 
+         final ObjectSpecification specification = targetAdapter.getSpecification();
+ 
+         final ObjectAction objectAction = findActionElseNull(specification, actionId);
+         if(objectAction == null) {
+             throw new RuntimeException(String.format("Unknown action '%s'", actionId));
+         }
+         return objectAction;
+     }
+ 
+     private static OneToOneAssociation findOneToOneAssociation(
+             final ObjectAdapter targetAdapter,
+             final String propertyId) throws RuntimeException {
+ 
+         final ObjectSpecification specification = targetAdapter.getSpecification();
+ 
+         final OneToOneAssociation property = findOneToOneAssociationElseNull(specification, propertyId);
+         if(property == null) {
+             throw new RuntimeException(String.format("Unknown property '%s'", propertyId));
+         }
+         return property;
+     }
+ 
+     private ObjectAdapter newValueAdapterFor(final PropertyDto propertyDto) {
+         final ValueWithTypeDto newValue = propertyDto.getNewValue();
+         final Object arg = CommonDtoUtils.getValue(newValue);
+         return adapterFor(arg);
+     }
+ 
+     private static ObjectAction findActionElseNull(
+             final ObjectSpecification specification,
+             final String actionId) {
+         final List<ObjectAction> objectActions = specification.getObjectActions(Contributed.INCLUDED);
+         for (final ObjectAction objectAction : objectActions) {
+             if(objectAction.getIdentifier().toClassAndNameIdentityString().equals(actionId)) {
+                 return objectAction;
+             }
+         }
+         return null;
+     }
+ 
+     private static OneToOneAssociation findOneToOneAssociationElseNull(
+             final ObjectSpecification specification,
+             final String propertyId) {
+         final List<ObjectAssociation> associations = specification.getAssociations(Contributed.INCLUDED);
+         for (final ObjectAssociation association : associations) {
+             if( association.getIdentifier().toClassAndNameIdentityString().equals(propertyId) &&
+                     association instanceof OneToOneAssociation) {
+                 return (OneToOneAssociation) association;
+             }
+         }
+         return null;
+     }
+ 
+     private ObjectAdapter[] argAdaptersFor(final ActionDto actionDto) {
+         final List<ParamDto> params = paramDtosFrom(actionDto);
+         final List<ObjectAdapter> args = Lists.newArrayList(
+                 Iterables.transform(params, new Function<ParamDto, ObjectAdapter>() {
+                     @Override
+                     public ObjectAdapter apply(final ParamDto paramDto) {
+                         final Object arg = CommonDtoUtils.getValue(paramDto);
+                         return adapterFor(arg);
+                     }
+                 })
+         );
+         return args.toArray(new ObjectAdapter[]{});
+     }
+ 
+     private static List<ParamDto> paramDtosFrom(final ActionDto actionDto) {
+         final ParamsDto parameters = actionDto.getParameters();
+         if (parameters != null) {
+             final List<ParamDto> parameterList = parameters.getParameter();
+             if (parameterList != null) {
+                 return parameterList;
+             }
+         }
+         return Collections.emptyList();
+     }
+ 
+     private ObjectAdapter adapterFor(final Object targetObject) {
+         if(targetObject instanceof OidDto) {
+             final OidDto oidDto = (OidDto) targetObject;
+             return adapterFor(oidDto);
+         }
+         if(targetObject instanceof CollectionDto) {
+             final CollectionDto collectionDto = (CollectionDto) targetObject;
+             final List<ValueDto> valueDtoList = collectionDto.getValue();
+             final List<Object> pojoList = Lists.newArrayList();
+             for (final ValueDto valueDto : valueDtoList) {
+                 ValueType valueType = collectionDto.getType();
+                 final Object valueOrOidDto = CommonDtoUtils.getValue(valueDto, valueType);
+                 // converting from adapter and back means we handle both
+                 // collections of references and of values
+                 final ObjectAdapter objectAdapter = adapterFor(valueOrOidDto);
+                 Object pojo = objectAdapter != null ? objectAdapter.getObject() : null;
+                 pojoList.add(pojo);
+             }
+             return adapterFor(pojoList);
+         }
+         if(targetObject instanceof Bookmark) {
+             final Bookmark bookmark = (Bookmark) targetObject;
+             return adapterFor(bookmark);
+         }
+         return getPersistenceSession().adapterFor(targetObject);
+     }
+ 
+     private ObjectAdapter adapterFor(final OidDto oidDto) {
+         final Bookmark bookmark = Bookmark.from(oidDto);
+         return adapterFor(bookmark);
+     }
+ 
+     private ObjectAdapter adapterFor(final Bookmark bookmark) {
+         final RootOid rootOid = RootOid.create(bookmark);
+         return adapterFor(rootOid);
+     }
+ 
+     private ObjectAdapter adapterFor(final RootOid rootOid) {
+         return getPersistenceSession().adapterFor(rootOid);
+     }
+ 
+     // //////////////////////////////////////
+ 
+     protected IsisSessionFactory getIsisSessionFactory() {
+         return IsisContext.getSessionFactory();
+     }
+ 
+     protected PersistenceSession getPersistenceSession() {
+         return getIsisSessionFactory().getCurrentSession().getPersistenceSession();
+     }
+ 
+     protected IsisTransactionManager getTransactionManager(PersistenceSession persistenceSession) {
+         return persistenceSession.getTransactionManager();
+     }
+ 
+     protected SpecificationLoader getSpecificationLoader() {
+         return getIsisSessionFactory().getSpecificationLoader();
+     }
+ 
+     // //////////////////////////////////////
+ 
+     @javax.inject.Inject
+     BookmarkService2 bookmarkService;
+ 
+     @javax.inject.Inject
+     InteractionContext interactionContext;
+ 
+     @javax.inject.Inject
+     SudoService sudoService;
+ 
+     @javax.inject.Inject
+     ClockService clockService;
+ 
+     @javax.inject.Inject
+     TransactionService3 transactionService;
+ 
+     @javax.inject.Inject
+     CommandContext commandContext;
+ 
+ }
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
index 91bf672,d2dfeed..5a8fc46
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/persistsession/PersistenceSessionServiceInternalDefault.java
@@@ -25,8 -25,9 +25,9 @@@ import org.apache.isis.applib.annotatio
  import org.apache.isis.applib.annotation.Programmatic;
  import org.apache.isis.applib.query.Query;
  import org.apache.isis.applib.services.bookmark.Bookmark;
 -import org.apache.isis.applib.services.bookmark.BookmarkService2;
 +import org.apache.isis.applib.services.bookmark.BookmarkService;
 +import org.apache.isis.applib.services.xactn.Transaction;
+ import org.apache.isis.applib.services.command.Command;
 -import org.apache.isis.applib.services.xactn.Transaction2;
  import org.apache.isis.applib.services.xactn.TransactionState;
  import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
  import org.apache.isis.core.metamodel.adapter.oid.Oid;
diff --cc core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactoryMetamodelRefiner.java
index c294447,8ae7ac6..8f5352d
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactoryMetamodelRefiner.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/system/persistence/PersistenceSessionFactoryMetamodelRefiner.java
@@@ -22,6 -22,10 +22,8 @@@ import org.apache.isis.core.commons.con
  import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
  import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
  import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite;
+ import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorToCheckModuleExtent;
+ import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorToCheckObjectSpecIdsUnique;
 -import org.apache.isis.objectstore.jdo.metamodel.facets.object.auditable.AuditableAnnotationInJdoApplibFacetFactory;
 -import org.apache.isis.objectstore.jdo.metamodel.facets.object.auditable.AuditableMarkerInterfaceInJdoApplibFacetFactory;
  import org.apache.isis.objectstore.jdo.metamodel.facets.object.datastoreidentity.JdoDatastoreIdentityAnnotationFacetFactory;
  import org.apache.isis.objectstore.jdo.metamodel.facets.object.discriminator.JdoDiscriminatorAnnotationFacetFactory;
  import org.apache.isis.objectstore.jdo.metamodel.facets.object.persistencecapable.JdoPersistenceCapableAnnotationFacetFactory;
diff --cc core/security-shiro/pom.xml
index dfaecd6,0c86741..13535bb
--- a/core/security-shiro/pom.xml
+++ b/core/security-shiro/pom.xml
@@@ -23,12 -23,11 +23,11 @@@
  	<parent>
  		<groupId>org.apache.isis.core</groupId>
  		<artifactId>isis</artifactId>
 -        <version>1.16.1-SNAPSHOT</version>
 +        <version>2.0.0-M1-SNAPSHOT</version>
  	</parent>
  
- 	<groupId>org.apache.isis.core</groupId>
  	<artifactId>isis-core-security-shiro</artifactId>
 -    <version>1.16.1-SNAPSHOT</version>
 +    <version>2.0.0-M1-SNAPSHOT</version>
  
  	<name>Apache Isis Security Shiro</name>
  
diff --cc core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract2.java
index 01b95a3,528d463..e144b27
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract2.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueAbstract2.java
@@@ -22,7 -22,8 +22,9 @@@ import org.apache.isis.core.runtime.hea
   * Base class for BDD spec glue.
   *
   * <p>
-  *     Note that there also needs to be at least one spec glue that inherits from{@link CukeGlueBootstrappingAbstract}.
+  *     Note that there also needs to be at least one spec glue that performs the bootstrapping.
 - *     inherits from{@link CukeGlueBootstrappingAbstract}.
++ *     This should inline the boilerplate that can be found in {@link CukeGlueBootstrappingAbstract} (it's not possible
++ *     to inherit from that class, unfortunately).
   * </p>
   */
  public abstract class CukeGlueAbstract2 extends HeadlessAbstract {
diff --cc core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueBootstrappingAbstract.java
index 0ca1e90,e5e21e2..8a02153
--- a/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueBootstrappingAbstract.java
+++ b/core/specsupport/src/main/java/org/apache/isis/core/specsupport/specs/CukeGlueBootstrappingAbstract.java
@@@ -25,7 -25,17 +25,17 @@@ import cucumber.api.java.Before
  /**
   * For BDD spec using headless access, there needs to be (at least) one BDD spec glue that inherits from this adapter
   * class, specifying the {@link Module} to use to bootstrap the system.
+  *
+  * <p>
 - *     <b>This class is deprecated</b>.  it's not possible to subclass from this class, it'll result in an exception:
++ *     <b>This class is deprecated</b>.  It's not possible to subclass from this class, it'll result in an exception:
+  *     <code>cucumber.runtime.CucumberException: You're not allowed to extend classes that define Step Definitions or
+  *     hooks</code>.
+  *     Instead, just inline the contents of this class.
+  * </p>
+  *
 - * @deprecated - it's not possible to subclass from this class, Instead, just inline the contents of this class.
++ * @deprecated - it's not possible to subclass from this class. Instead, just inline the contents of this class.
   */
+ @Deprecated
  public abstract class CukeGlueBootstrappingAbstract extends HeadlessWithBootstrappingAbstract {
  
      protected CukeGlueBootstrappingAbstract(final Module module) {
diff --cc core/viewer-wicket-applib/pom.xml
index 914e2e0,5c1e359..a415304
--- a/core/viewer-wicket-applib/pom.xml
+++ b/core/viewer-wicket-applib/pom.xml
@@@ -24,10 -24,9 +24,9 @@@
  	<parent>
  		<groupId>org.apache.isis.core</groupId>
  		<artifactId>isis</artifactId>
 -		<version>1.16.1-SNAPSHOT</version>
 +		<version>2.0.0-M1-SNAPSHOT</version>
      </parent>
  
-     <groupId>org.apache.isis.core</groupId>
  	<artifactId>isis-core-viewer-wicket-applib</artifactId>
  	<name>Apache Isis Wicket Viewer Applib</name>
  
diff --cc core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
index a350367,fc06ba5..613e2ca
--- a/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
+++ b/core/viewer-wicket-impl/src/main/java/org/apache/isis/viewer/wicket/viewer/registries/components/ComponentFactoryRegistrarDefault.java
@@@ -45,10 -48,16 +48,19 @@@ import org.apache.isis.viewer.wicket.ui
  import org.apache.isis.viewer.wicket.ui.components.header.HeaderPanelFactory;
  import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditFormPanelFactory;
  import org.apache.isis.viewer.wicket.ui.components.property.PropertyEditPanelFactory;
- import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.*;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisBlobPanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisClobPanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisColorPanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisDatePanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisDateTimePanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisMoneyPanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisPasswordPanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisPercentagePanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisTimePanelFactory;
+ import org.apache.isis.viewer.wicket.ui.components.scalars.isisapplib.IsisTimeStampPanelFactory;
 +import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8LocalDatePanelFactory;
 +import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8LocalDateTimePanelFactory;
 +import org.apache.isis.viewer.wicket.ui.components.scalars.jdk8time.Jdk8OffsetDateTimePanelFactory;
  import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlDatePanelFactory;
  import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimePanelFactory;
  import org.apache.isis.viewer.wicket.ui.components.scalars.jdkdates.JavaSqlTimestampPanelFactory;
diff --cc core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
index 395c37a,39fd75a..e80e8f2
--- a/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
+++ b/core/viewer-wicket-ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/bulk/BulkActionsHelper.java
@@@ -21,11 -21,11 +21,11 @@@ package org.apache.isis.viewer.wicket.u
  import java.io.Serializable;
  import java.util.Collections;
  import java.util.List;
++import java.util.stream.Collectors;
  
- import com.google.common.base.Predicate;
- import com.google.common.collect.Iterables;
 -import com.google.common.collect.FluentIterable;
++import com.google.common.base.Predicates;
  import com.google.common.collect.Lists;
  
 -import org.apache.isis.applib.filter.Filters;
  import org.apache.isis.core.metamodel.deployment.DeploymentCategory;
  import org.apache.isis.core.metamodel.spec.ActionType;
  import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@@ -55,32 -54,28 +54,26 @@@ public class BulkActionsHelper implemen
              return Collections.emptyList();
          }
  
-         final ObjectSpecification typeSpec = model.getTypeOfSpecification();
- 
-         List<ObjectAction> objectActions = typeSpec.getObjectActions(ActionType.USER, Contributed.INCLUDED,
-                 com.google.common.base.Predicates.<ObjectAction>alwaysTrue());
+         final ObjectSpecification objectSpec = getObjectSpecification(isisSessionFactory);
  
-         final DeploymentCategory deploymentCategory = isisSessionFactory.getDeploymentCategory();
-         if ( !deploymentCategory.isProduction()) {
-             List<ObjectAction> prototypeActions   = typeSpec.getObjectActions(ActionType.PROTOTYPE, Contributed.INCLUDED,
-                     com.google.common.base.Predicates.<ObjectAction>alwaysTrue());
-             objectActions.addAll(prototypeActions);
-         }
+         final List<ActionType> actionTypes = inferActionTypes(isisSessionFactory);
 -        List<ObjectAction> objectActions = objectSpec.getObjectActions(actionTypes, Contributed.INCLUDED, Filters.<ObjectAction>any());
++        List<ObjectAction> objectActions = objectSpec.getObjectActions(actionTypes, Contributed.INCLUDED, Predicates.<ObjectAction>alwaysTrue());
  
-         List<ObjectAction> flattenedActions = objectActions;
- 
-         return Lists.newArrayList(Iterables.filter(flattenedActions, BULK));
 -        return FluentIterable.from(objectActions)
 -                .filter(ObjectAction.Predicates.bulk())
 -                .toList();
++        return objectActions.stream().filter(ObjectAction.Predicates.bulk()::apply).collect(Collectors.toList());
      }
  
+     private ObjectSpecification getObjectSpecification(final IsisSessionFactory isisSessionFactory) {
+         return collectionModel.getTypeOfSpecification();
+     }
  
-     @SuppressWarnings("deprecation")
-     private static final Predicate<ObjectAction> BULK = ObjectAction.Predicates.bulk();
- 
-     /**
-      * Protected so can be overridden in testing if required.
-      */
-     protected boolean isDebugMode() {
-         return true;
+     private List<ActionType> inferActionTypes(final IsisSessionFactory isisSessionFactory) {
+         final List<ActionType> actionTypes = Lists.newArrayList();
+         actionTypes.add(ActionType.USER);
+         final DeploymentCategory deploymentCategory = isisSessionFactory.getDeploymentCategory();
+         if ( !deploymentCategory.isProduction()) {
+             actionTypes.add(ActionType.PROTOTYPE);
+         }
+         return actionTypes;
      }
  
  }
diff --cc example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
index 519ad7a,9c598d3..8da92ba
--- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
+++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java
@@@ -63,9 -64,11 +64,9 @@@ public class SimpleObject implements Co
      private String notes;
  
  
-     @Action(semantics = SemanticsOf.IDEMPOTENT, command = CommandReification.ENABLED, publishing = Publishing.ENABLED)
+     @Action(semantics = SemanticsOf.IDEMPOTENT, command = CommandReification.ENABLED, publishing = Publishing.ENABLED, associateWith = "name")
      public SimpleObject updateName(
 -            @Parameter(maxLength = 40)
 -            @ParameterLayout(named = "Name")
 -            final String name) {
 +            @Name final String name) {
          setName(name);
          return this;
      }

-- 
To stop receiving notification emails like this one, please contact
danhaywood@apache.org.