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 2015/07/17 18:08:09 UTC

isis git commit: ISIS-1173: split out FixtureScriptsSpecificationProvider.

Repository: isis
Updated Branches:
  refs/heads/master d159f02cd -> 596596323


ISIS-1173: split out FixtureScriptsSpecificationProvider.


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

Branch: refs/heads/master
Commit: 5965963234eaf6c3c992b40fdccdc5a53644196c
Parents: d159f02
Author: Dan Haywood <da...@haywood-associates.co.uk>
Authored: Fri Jul 17 17:07:42 2015 +0100
Committer: Dan Haywood <da...@haywood-associates.co.uk>
Committed: Fri Jul 17 17:07:42 2015 +0100

----------------------------------------------------------------------
 .../_migration-notes_1.8.0-to-1.9.0.adoc        |   1 +
 ...tes_1.8.0-to-1.9.0_exception-recognizer.adoc |   2 +-
 ..._fixture-scripts-specification-provider.adoc |  13 ++
 ...rg_classes_super_manpage-FixtureScripts.adoc |   2 +-
 .../main/asciidoc/guides/_rg_services-api.adoc  |  13 ++
 ...vices-api_manpage-FixtureScriptsDefault.adoc |  50 +++++
 .../main/asciidoc/guides/_rg_services-spi.adoc  |   9 +
 ...age-FixtureScriptsSpecificationProvider.adoc |  70 ++++++
 ...g_testing_fixture-scripts_api-and-usage.adoc |  47 +++-
 .../applib/fixturescripts/FixtureScripts.java   | 113 +++++++---
 .../fixturespec/FixtureScriptsDefault.java      | 214 +++++++++++++++++++
 .../FixtureScriptsSpecification.java            | 143 +++++++++++++
 .../FixtureScriptsSpecificationProvider.java    |  37 ++++
 ...ionRecognizerCompositeForJdoObjectStore.java |  12 +-
 .../services/ServicesInstallerAbstract.java     |  12 +-
 .../IsisSystemAbstract.java                     |  15 ++
 .../fixture/DomainAppFixturesProvider.java      |  42 ++++
 .../fixture/DomainAppFixturesService.java       |  76 -------
 18 files changed, 744 insertions(+), 127 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0.adoc b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0.adoc
index 2db4c83..4bae36c 100644
--- a/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0.adoc
+++ b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0.adoc
@@ -15,6 +15,7 @@ Apache Isis 1.9.0 has not yet been released; it is still 1.9.0-SNAPSHOT.
 include::_migration-notes_1.8.0-to-1.9.0_upgrading-to-dn4.adoc[leveloffset=+1]
 include::_migration-notes_1.8.0-to-1.9.0_upgrading-to-java8.adoc[leveloffset=+1]
 include::_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc[leveloffset=+1]
+include::_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider.adoc[leveloffset=+1]
 include::_migration-notes_1.8.0-to-1.9.0_war-packaging.adoc[leveloffset=+1]
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc
index 4f4a0cd..8053992 100644
--- a/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc
+++ b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_exception-recognizer.adoc
@@ -1,4 +1,4 @@
-[[_migration-notes_1.8.0-to-1.9.0_upgrading-to-java8]]
+[[_migration-notes_1.8.0-to-1.9.0_exception-recognizer]]
 = `ExceptionRecognizerCompositeForJdoObjectStore`
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or 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.
 :_basedir: ../

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider.adoc b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider.adoc
new file mode 100644
index 0000000..085e75f
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider.adoc
@@ -0,0 +1,13 @@
+[[_migration-notes_1.8.0-to-1.9.0_fixture-scripts-specification-provider]]
+= `FixtureScriptsSpecificationProvider`
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or 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.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+The `FixtureScriptsSpecificationProvider` SPI service is an alternative to subclassing the xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`] domain service.  The logic that would normally be in the subclass moves to the provider service instead, and the framework instantiates a fallback default instance, xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`FixtureScriptsDefault`].
+
+This new design is optional; if you continue to provide your own subclass then everything will continue as before.  However the new design is more flexible and involves less code.
+
+See xref:ug.adoc#_ug_testing_fixture-scripts_api-and-usage[user guide] for further discussion.
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_rg_classes_super_manpage-FixtureScripts.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_classes_super_manpage-FixtureScripts.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_classes_super_manpage-FixtureScripts.adoc
index 44280fb..fdf71f3 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rg_classes_super_manpage-FixtureScripts.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_classes_super_manpage-FixtureScripts.adoc
@@ -4,6 +4,6 @@
 :_basedir: ../
 :_imagesdir: images/
 
-NOTE: TODO
+NOTE: TODO - see also user guide's xref:ug.adoc#_ug_testing_fixture-scripts_api-and-usage[fixture scripts' API and usage], xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`FixtureScriptsDefault`] (fallback implementation) and xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`].
 
 

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_rg_services-api.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_services-api.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_services-api.adoc
index 2505267..5e6e324 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rg_services-api.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_services-api.adoc
@@ -128,6 +128,18 @@ xref:rg.adoc#_rg_services-spi_manpage-CommandService[`CommandService`] for persi
 |
 
 
+|xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`o.a.i.applib.` +
+`services.` +
+`fixturespec` +
+`FixtureScriptsDefault`]
+|Fallback implementation of xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`], providing the ability to execute fixture scripts.
+|`FixtureScriptsDefault` +
+``o.a.i.core`` +
+``isis-core-applib``
+|Interacts with xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScripts-
+SpecificationProvider`].
+
+
 |xref:rg.adoc#_rg_services-api_manpage-GuiceBeanProvider[`o.a.i.applib.` +
 `services.guice` +
 `GuiceBeanProvider`]
@@ -269,6 +281,7 @@ include::_rg_services-api_manpage-DeepLinkService.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-DomainObjectContainer.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-EmailService.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-EventBusService.adoc[leveloffset=+1]
+include::_rg_services-api_manpage-FixtureScriptsDefault.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-GuiceBeanProvider.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-IsisJdoSupport.adoc[leveloffset=+1]
 include::_rg_services-api_manpage-MementoService.adoc[leveloffset=+1]

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_rg_services-api_manpage-FixtureScriptsDefault.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_services-api_manpage-FixtureScriptsDefault.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_services-api_manpage-FixtureScriptsDefault.adoc
new file mode 100644
index 0000000..ef3b3e1
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_services-api_manpage-FixtureScriptsDefault.adoc
@@ -0,0 +1,50 @@
+[[_rg_services-api_manpage-FixtureScriptsDefault]]
+= `FixtureScriptsDefault`
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or 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.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+The `FixtureScriptsDefault` service provides the ability to execute xref:ug.adoc#_ug_testing_fixture-scripts_api-and-usage[fixture scripts] .
+
+The service extends from the xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`], and is only instantiated by the framework if there no custom implementation of `FixtureScripts` has been otherwise provided; in other words it is a fallback.
+
+If this service is instantiated (as a fallback) then it uses the xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`] to obtain a `FixtureScriptsSpecification`.  This configures this service, telling it which package to search for `FixtureScript` classes, how to execute those classes, and hints that influence the UI.
+
+[TIP]
+====
+We recommend using xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`] rather than subclassing xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`].
+====
+
+
+
+== API & Implementation
+
+The API for the service is:
+
+[source,java]
+----
+public class FixtureScriptsDefault ... {
+    @Programmatic
+    public List<FixtureResult> runFixtureScript(
+        FixtureScript fixtureScript,
+        String parameters) { ... }
+}
+----
+
+... in other words the same as xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`] superclass that it inherits from.
+
+
+== Configuration
+
+As noted in the introduction, this service is only instantiated if there is no other implementation of `FixtureScripts` available on the classpath.
+
+If an instance of `FixtureScriptsSpecificationProvider` is available on the classpath, then the service will be visible in the UI (assuming xref:rg.adoc#_rg_runtime_deployment-types[prototype mode]).  Otherwise the service will be available only to be injected and invoked programmatically.
+
+
+
+
+== Related Services
+
+The service interacts with xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`].

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi.adoc
index 34674c5..56c5da7 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi.adoc
@@ -125,6 +125,14 @@ a configured `EmailService`
 ``isis-viewer-wicket-impl``
 |
 
+|xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`o.a.i.applib.` +
+`services.fixturespec` +
+`FixtureScripts-` +
+`SpecificationProvider`]
+|Provides settings for xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`FixtureScriptsDefault`] fallback domain service for executing fixture scripts.
+|
+|
+
 |xref:rg.adoc#_rg_services-spi_manpage-PublishingService[`o.a.i.applib.` +
 `services.publish` +
 `PublishingService`]
@@ -261,6 +269,7 @@ include::_rg_services-spi_manpage-ContentNegotiationService.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-EmailNotificationService.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-EventSerializer.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-ExceptionRecognizer.adoc[leveloffset=+1]
+include::_rg_services-spi_manpage-FixtureScriptsSpecificationProvider.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-LocaleProvider.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-PublishingService.adoc[leveloffset=+1]
 include::_rg_services-spi_manpage-RepresentationService.adoc[leveloffset=+1]

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-FixtureScriptsSpecificationProvider.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-FixtureScriptsSpecificationProvider.adoc b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-FixtureScriptsSpecificationProvider.adoc
new file mode 100644
index 0000000..1e1cd19
--- /dev/null
+++ b/adocs/documentation/src/main/asciidoc/guides/_rg_services-spi_manpage-FixtureScriptsSpecificationProvider.adoc
@@ -0,0 +1,70 @@
+[[_rg_services-spi_manpage-FixtureScriptsSpecificationProvider]]
+= `FixtureScriptsSpecificationProvider`
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or 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.
+:_basedir: ../
+:_imagesdir: images/
+
+
+
+The `FixtureScriptsSpecificationProvider` configures the xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`FixtureScriptsDefault`] domain service, providing the location to search for fixture scripts and other settings.
+
+The service is only used if the `FixtureScriptsDefault` service is instantiated as a fallback by the framework.  If the application provides its own subclass of xref:rg.adoc#_rg_classes_utility_manpage-FixtureScripts[`FixtureScripts`] superclass, then this provider service is not used.
+
+[TIP]
+====
+Of the two designs, we encourage you to implement this "provider" SPI rather than subclass `FixtureScripts`.  The primary benefit (apart from decoupling responsibilities) is that it ensures that there is always an instance of `FixtureScripts` available for use.
+====
+
+
+
+== SPI
+
+The SPI defined by the service is:
+
+[source,java]
+----
+public interface FixtureScriptsSpecificationProvider {
+    @Programmatic
+    FixtureScriptsSpecification getSpecification();
+}
+----
+
+where `FixtureScriptsSpecification` exposes these values:
+
+[source,java]
+----
+public class FixtureScriptsSpecification {
+    public String getPackagePrefix() { ... }
+    public FixtureScripts.NonPersistedObjectsStrategy getNonPersistedObjectsStrategy() { ... }
+    public FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() { ... }
+    public Class<? extends FixtureScript> getRunScriptDefaultScriptClass() { ... }
+    public DropDownPolicy getRunScriptDropDownPolicy() { ... }
+    public Class<? extends FixtureScript> getRecreateScriptClass() { ... }
+    ...
+}
+----
+
+The class is immutable but it has a builder (obtained using `FixturescriptsSpecification.builder(...)`) for a fluent API.
+
+
+
+== Implementation
+
+The xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype] has a simple implementation of this service:
+
+[source,java]
+----
+@DomainService(nature = NatureOfService.DOMAIN)
+public class DomainAppFixturesProvider implements FixtureScriptsSpecificationProvider {
+    @Override
+    public FixtureScriptsSpecification getSpecification() {
+        return FixtureScriptsSpecification
+                .builder(DomainAppFixturesProvider.class)
+                .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)
+                .withRunScriptDefault(RecreateSimpleObjects.class)
+                .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES)
+                .withRecreate(RecreateSimpleObjects.class)
+                .build();
+    }
+}
+----

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_api-and-usage.adoc
----------------------------------------------------------------------
diff --git a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_api-and-usage.adoc b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_api-and-usage.adoc
index 8fa4118..3f29dca 100644
--- a/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_api-and-usage.adoc
+++ b/adocs/documentation/src/main/asciidoc/guides/_ug_testing_fixture-scripts_api-and-usage.adoc
@@ -5,17 +5,52 @@
 :_imagesdir: images/
 
 
-There are two parts to using fixture scripts: the `FixtureScripts` domain service class, and the `FixtureScript` view model class, both being `abstract`.
+There are two parts to using fixture scripts: the `FixtureScripts` domain service class, and the `FixtureScript` view model class:
 
-* The job of the `FixtureScripts` domain service is to locate all fixture scripts from the classpath and to let them be invoked, either from an integration test/BDD spec or from the UI of your Isis app.
+* The role of the `FixtureScripts` domain service is to locate all fixture scripts from the classpath and to let them be invoked, either from an integration test/BDD spec or from the UI of your Isis app.
 
-* With `FixtureScript` meanwhile you subclass for each of the scenarios that you want to define.  You can also subclass from `FixtureScript` to create helpers; more on this below.
+* The role of `FixtureScript` meanwhile is to subclass for each of the scenarios that you want to define.  You can also subclass from `FixtureScript` to create helpers; more on this below.
 
 Let's look at `FixtureScripts` domain service in more detail first.
 
 == `FixtureScripts`
 
-In your code you subclass `FixtureScripts` domain service primarily just to specify which package to search for.  For example, here's the service that's generated by the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype]:
+There are two ways in which you can provide a `FixtureScripts` service.
+
+The original (pre-1.9.0) approach is to subclass subclass `FixtureScripts` domain service, with your subclass specifying which package to search for.  Various other settings can also be provided, and - being a custom class - you can also add in additional actions.  A common example is to provide a "one-shot" action to recreate a standard demo set of objects.
+
+As of 1.9.0 there is an alternative design.  Instead of subclassing `FixtureScripts` you instead implement the xref:rg.adoc#_rg_services-spi_manpage-FixtureScriptsSpecificationProvider[`FixtureScriptsSpecificationProvider`] SPI.  (As its name suggests), this provides a `FixtureScriptsSpecification` object that contains the same information as would otherwise have been in the `FixtureScripts` subclass.
+
+The actual implementation of the `FixtureScripts` service is then provided by the framework itself, namely the xref:rg.adoc#_rg_services-api_manpage-FixtureScriptsDefault[`FixtureScriptsDefault`] domain service, annotated to be rendered on the secondary "Prototyping" menu.  This uses the `FixtureScriptsSpecificationProvider` to adjust itself accordinly.
+
+For example, here's the `FixtureScriptsSpecificationProvider` service that's generated by the xref:ug.adoc#_ug_getting-started_simpleapp-archetype[SimpleApp archetype]:
+
+[source,java]
+----
+@DomainService(nature = NatureOfService.DOMAIN)
+public class DomainAppFixturesProvider implements FixtureScriptsSpecificationProvider {
+    @Override
+    public FixtureScriptsSpecification getSpecification() {
+        return FixtureScriptsSpecification
+                .builder(DomainAppFixturesProvider.class)                                       // <1>
+                .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)                         // <2>
+                .withRunScriptDefault(RecreateSimpleObjects.class)                              // <3>
+                .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES)      // <4>
+                .withRecreate(RecreateSimpleObjects.class)                                      // <5>
+                .build();
+    }
+}
+----
+<1> search for all fixture scripts under the package containing this class
+<2> if the same fixture script (class) is encountered more than once, then run anyway; more on this in xref:ug.adoc#_ug_testing_fixture-scripts_api-and-usage_organizing[Organizing Fixture scripts]], below.
+<3> specify the fixture script class to provide as the default for the service's "run fixture script" action
+<4> whether the service's "run fixture script" action should display other fixture scripts using a choices drop down or (if there are very many of them) using an auto-complete
+<5> if present, enables a "recreate objects and return first" action to be displayed in the UI
+
+
+The benefit of this design - decoupling the responsibilities of the superclass and the subclass - is that it ensures that there is always an instance of `FixtureScripts` available, even if the application itself doesn't provide one.  Some of the (non-ASF) link:http://isisaddons.org[Isis Addons] modules (eg http://github.com/isisaddons/isis-module-security[Isis addons' security] module) expect there to be a `FixtureScripts` service for seeding data, which has caused some confusion.
+
+By way of comparison, if using the older pre-1.9.0 approach then you would create a subclass:
 
 [source,java]
 ----
@@ -26,7 +61,6 @@ In your code you subclass `FixtureScripts` domain service primarily just to spec
         menuOrder = "500"
 )
 public class DomainAppFixturesService extends FixtureScripts {     // <3>
-
     public DomainAppFixturesService() {
         super(
             "domainapp",                                           // <4>
@@ -50,8 +84,9 @@ public class DomainAppFixturesService extends FixtureScripts {     // <3>
 <6> (optional) specify a default fixture script to run, in this case `RecreateSimpleObjects` fixture script (see below)
 <7> make all fixture scripts found available as a drop-down (by increasing the visibility of this method to `public`)
 
+This isn't quite equivalent; you would need to write additional code to support the "recreate objects and return first" action, for example.
 
-Here's how the domain service looks like in the UI:
+Either way, here's how the domain service looks like in the UI:
 
 image::{_imagesdir}testing/fixture-scripts/prototyping-menu.png[width="700px",link="{_imagesdir}testing/fixture-scripts/prototyping-menu.png"]
 

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/FixtureScripts.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/FixtureScripts.java b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/FixtureScripts.java
index acb5175..7602e7f 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/FixtureScripts.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/fixturescripts/FixtureScripts.java
@@ -23,10 +23,13 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
+
 import javax.annotation.PostConstruct;
+
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
+
 import org.apache.isis.applib.AbstractService;
 import org.apache.isis.applib.ViewModel;
 import org.apache.isis.applib.annotation.Action;
@@ -40,13 +43,16 @@ import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.services.bookmark.BookmarkService;
 import org.apache.isis.applib.services.classdiscovery.ClassDiscoveryService;
 import org.apache.isis.applib.services.classdiscovery.ClassDiscoveryService2;
+import org.apache.isis.applib.services.fixturespec.FixtureScriptsDefault;
+import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecification;
 import org.apache.isis.applib.services.memento.MementoService;
 import org.apache.isis.applib.services.memento.MementoService.Memento;
 import org.apache.isis.applib.util.ObjectContracts;
 
 public abstract class FixtureScripts extends AbstractService {
 
-    //region > nonPersistedObjectsStrategy, multipleExecutionStrategy enums
+
+    //region > Specification, nonPersistedObjectsStrategy, multipleExecutionStrategy enums
 
     /**
      * How to handle objects that are to be
@@ -110,88 +116,126 @@ public abstract class FixtureScripts extends AbstractService {
 
     //endregion
 
+
     //region > constructors
 
     /**
-     * Defaults to {@link org.apache.isis.applib.fixturescripts.FixtureScripts.NonPersistedObjectsStrategy#PERSIST persist}
-     * strategy (if non-persisted objects are {@link #newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link org.apache.isis.applib.fixturescripts.FixtureResultList}),
-     * defaults {@link #getMultipleExecutionStrategy()} to {@link org.apache.isis.applib.fixturescripts.FixtureScripts.MultipleExecutionStrategy#IGNORE ignore}
+     * Defaults to {@link FixtureScripts.NonPersistedObjectsStrategy#PERSIST persist}
+     * strategy (if non-persisted objects are {@link FixtureScripts#newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link FixtureResultList}),
+     * defaults {@link #getMultipleExecutionStrategy()} to {@link FixtureScripts.MultipleExecutionStrategy#IGNORE ignore}
      * if multiple instances of the same fixture script class are encountered.
      *
      * @param packagePrefix - to search for fixture script implementations, eg "com.mycompany"
+     *
+     * @deprecated - use {@link #FixtureScripts(FixtureScriptsSpecification)} instead.
      */
+    @Deprecated
     public FixtureScripts(final String packagePrefix) {
-        this(packagePrefix, NonPersistedObjectsStrategy.PERSIST, MultipleExecutionStrategy.IGNORE);
+        this(FixtureScriptsSpecification.builder(packagePrefix)
+                                        .build());
     }
 
     /**
-     * Defaults to {@link org.apache.isis.applib.fixturescripts.FixtureScripts.NonPersistedObjectsStrategy#PERSIST persist}
-     * strategy (if non-persisted objects are {@link #newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link org.apache.isis.applib.fixturescripts.FixtureResultList}).
+     * Defaults to {@link FixtureScripts.NonPersistedObjectsStrategy#PERSIST persist}
+     * strategy (if non-persisted objects are {@link FixtureScripts#newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link FixtureResultList}).
      *
      * @param packagePrefix - to search for fixture script implementations, eg "com.mycompany"
      * @param multipleExecutionStrategy - whether more than one instance of the same fixture script class can be run multiple times
+     *
+     * @deprecated - use {@link #FixtureScripts(FixtureScriptsSpecification)} instead.
      */
+    @Deprecated
     public FixtureScripts(
             final String packagePrefix,
             final MultipleExecutionStrategy multipleExecutionStrategy) {
-        this(packagePrefix, NonPersistedObjectsStrategy.PERSIST, multipleExecutionStrategy);
+        this(FixtureScriptsSpecification.builder(packagePrefix)
+                                        .with(multipleExecutionStrategy)
+                .build());
     }
 
     /**
-     * Defaults {@link #getMultipleExecutionStrategy()} to {@link org.apache.isis.applib.fixturescripts.FixtureScripts.MultipleExecutionStrategy#IGNORE ignore}
+     * Defaults {@link #getMultipleExecutionStrategy()} to {@link FixtureScripts.MultipleExecutionStrategy#IGNORE ignore}
      * if multiple instances of the same fixture script class are encountered.
      *
      * @param packagePrefix  - to search for fixture script implementations, eg "com.mycompany"
      * @param nonPersistedObjectsStrategy - how to handle any non-persisted objects that are {@link #newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link org.apache.isis.applib.fixturescripts.FixtureResultList}.
+     *
+     * @deprecated - use {@link #FixtureScripts(FixtureScriptsSpecification)} instead.
      */
+    @Deprecated
     public FixtureScripts(
             final String packagePrefix, final NonPersistedObjectsStrategy nonPersistedObjectsStrategy) {
-        this(packagePrefix, nonPersistedObjectsStrategy, MultipleExecutionStrategy.IGNORE);
+        this(FixtureScriptsSpecification.builder(packagePrefix)
+                                        .with(nonPersistedObjectsStrategy)
+                                        .build());
     }
 
     /**
      * @param packagePrefix  - to search for fixture script implementations, eg "com.mycompany"
      * @param nonPersistedObjectsStrategy - how to handle any non-persisted objects that are {@link #newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link org.apache.isis.applib.fixturescripts.FixtureResultList}.
      * @param multipleExecutionStrategy - whether more than one instance of the same fixture script class can be run multiple times
+     *
+     * @deprecated - use {@link #FixtureScripts(FixtureScriptsSpecification)} instead.
      */
+    @Deprecated
     public FixtureScripts(
             final String packagePrefix,
             final NonPersistedObjectsStrategy nonPersistedObjectsStrategy,
             final MultipleExecutionStrategy multipleExecutionStrategy) {
-        this.packagePrefix = packagePrefix;
-        this.nonPersistedObjectsStrategy = nonPersistedObjectsStrategy;
-        this.multipleExecutionStrategy = multipleExecutionStrategy;
+        this(FixtureScriptsSpecification.builder(packagePrefix)
+                                        .with(nonPersistedObjectsStrategy)
+                                        .with(multipleExecutionStrategy)
+                                        .build());
+    }
+
+    /**
+     * @param specification - specifies how the service will find instances and execute them.
+     */
+    public FixtureScripts(final FixtureScriptsSpecification specification) {
+        this.specification = specification;
     }
 
     //endregion
 
+
     //region > packagePrefix, nonPersistedObjectsStrategy, multipleExecutionStrategy
 
-    private final String packagePrefix;
+    private FixtureScriptsSpecification specification;
 
     @Programmatic
-    public String getPackagePrefix() {
-        return packagePrefix;
+    public FixtureScriptsSpecification getSpecification() {
+        return specification;
     }
 
-    private final NonPersistedObjectsStrategy nonPersistedObjectsStrategy;
-    private final FixtureScripts.MultipleExecutionStrategy multipleExecutionStrategy;
+    /**
+     * Allows the specification to be overridden if required.
+     *
+     * <p>
+     *     This is used by {@link FixtureScriptsDefault}.
+     * </p>
+     *
+     * @param specification
+     */
+    protected void setSpecification(final FixtureScriptsSpecification specification) {
+        this.specification = specification;
+    }
 
     @Programmatic
+    public String getPackagePrefix() {
+        return specification.getPackagePrefix();
+    }
+    @Programmatic
     public NonPersistedObjectsStrategy getNonPersistedObjectsStrategy() {
-        return nonPersistedObjectsStrategy;
+        return specification.getNonPersistedObjectsStrategy();
     }
-
     @Programmatic
     public MultipleExecutionStrategy getMultipleExecutionStrategy() {
-        return multipleExecutionStrategy;
+        return specification.getMultipleExecutionStrategy();
     }
 
     //endregion
 
     //region > init
-
-
     @Programmatic
     @PostConstruct
     public void init() {
@@ -211,11 +255,12 @@ public abstract class FixtureScripts extends AbstractService {
 
     private List<FixtureScript> findAndInstantiateFixtureScripts() {
         final List<FixtureScript> fixtureScripts = Lists.newArrayList();
-        final Set<Class<? extends FixtureScript>> classes =
-                findSubTypesOfClasses();
-        for (final Class<? extends FixtureScript> fixtureScriptCls : classes) {
+        final Set<Class<? extends FixtureScript>> fixtureScriptSubtypes =
+                findFixtureScriptSubTypesInPackage();
+        for (final Class<? extends FixtureScript> fixtureScriptCls : fixtureScriptSubtypes) {
             final String packageName = fixtureScriptCls.getPackage().getName();
-            if(!packageName.startsWith(packagePrefix)) {
+            if(!packageName.startsWith(getPackagePrefix())) {
+                // redundant check if ClassDiscoveryService2 in use because already filtered out
                 continue;
             } 
             final FixtureScript fs = newFixtureScript(fixtureScriptCls);
@@ -232,12 +277,16 @@ public abstract class FixtureScripts extends AbstractService {
         return fixtureScripts;
     }
 
-    private Set<Class<? extends FixtureScript>> findSubTypesOfClasses() {
+    private Set<Class<? extends FixtureScript>> findFixtureScriptSubTypesInPackage() {
+        return findSubTypesOfClasses(FixtureScript.class, getPackagePrefix());
+    }
+
+    private <T> Set<Class<? extends T>> findSubTypesOfClasses(Class<T> cls, final String packagePrefix) {
         if(classDiscoveryService instanceof ClassDiscoveryService2) {
             final ClassDiscoveryService2 classDiscoveryService2 = (ClassDiscoveryService2) classDiscoveryService;
-            return classDiscoveryService2.findSubTypesOfClasses(FixtureScript.class, packagePrefix);
+            return classDiscoveryService2.findSubTypesOfClasses(cls, packagePrefix);
         } else {
-            return classDiscoveryService.findSubTypesOfClasses(FixtureScript.class);
+            return classDiscoveryService.findSubTypesOfClasses(cls);
         }
     }
 
@@ -303,7 +352,7 @@ public abstract class FixtureScripts extends AbstractService {
                 }));
     }
     public String disableRunFixtureScript(final FixtureScript fixtureScript, final String parameters) {
-        return getFixtureScriptList().isEmpty()? "No fixture scripts found under package '" + packagePrefix + "'": null;
+        return getFixtureScriptList().isEmpty()? "No fixture scripts found under package '" + getPackagePrefix() + "'": null;
     }
     public String validateRunFixtureScript(final FixtureScript fixtureScript, final String parameters) {
         return fixtureScript.validateRun(parameters);
@@ -377,7 +426,7 @@ public abstract class FixtureScripts extends AbstractService {
         if (object instanceof ViewModel || getContainer().isPersistent(object)) {
             // continue
         } else {
-            switch(nonPersistedObjectsStrategy) {
+            switch(getNonPersistedObjectsStrategy()) {
                 case PERSIST:
                     getContainer().flush();
                     break;

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsDefault.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsDefault.java b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsDefault.java
new file mode 100644
index 0000000..f97e255
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsDefault.java
@@ -0,0 +1,214 @@
+/*
+ *  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.services.fixturespec;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.apache.isis.applib.annotation.Action;
+import org.apache.isis.applib.annotation.ActionLayout;
+import org.apache.isis.applib.annotation.DomainServiceLayout;
+import org.apache.isis.applib.annotation.MemberOrder;
+import org.apache.isis.applib.annotation.MinLength;
+import org.apache.isis.applib.annotation.Optionality;
+import org.apache.isis.applib.annotation.Parameter;
+import org.apache.isis.applib.annotation.ParameterLayout;
+import org.apache.isis.applib.annotation.RestrictTo;
+import org.apache.isis.applib.fixturescripts.FixtureResult;
+import org.apache.isis.applib.fixturescripts.FixtureScript;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+
+/**
+ * Default instance of {@link FixtureScripts}, instantiated automatically by the framework if no custom user-defined instance was
+ * registered.
+ *
+ * <p>
+ *     The original design (pre 1.9.0) was to subclass {@link FixtureScripts} and specify the package prefix (and optionally other
+ *     settings) to search for {@link FixtureScript} subtypes.  The inherited functionality from the superclass then knew how to
+ *     find and execute fixture scripts.
+ * </p>
+ * <p>
+ *     The new (1.9.0+) design separates these responsibilities.  Rather than subclassing {@link FixtureScripts}, you can instead
+ *     rely on the framework to instantiate <i>this</i> default, fallback, implementation of {@link FixtureScripts}.  You can then
+ *     optionally (though typically) specify the package prefix and other settings by implementing the new {@link FixtureScriptsSpecificationProvider}
+ *     service.
+ * </p>
+ *
+ * <p>
+ *     Note that this class is deliberately <i>not</i> annotated with {@link org.apache.isis.applib.annotation.DomainService}; rather it is
+ *     automatically registered programmatically if no other instance of {@link FixtureScripts} is found.
+ * </p>
+ */
+@DomainServiceLayout(
+        named="Prototyping",
+        menuBar = DomainServiceLayout.MenuBar.SECONDARY,
+        menuOrder = "500"
+)
+public class FixtureScriptsDefault extends FixtureScripts {
+
+    //region > constructor, init
+    /**
+     * The package prefix to search for fixture scripts.  This default value will result in
+     * no fixture scripts being found.  However, normally it will be overridden.
+     */
+    public static final String PACKAGE_PREFIX = FixtureScriptsDefault.class.getPackage().getName();
+
+    public FixtureScriptsDefault() {
+        super(PACKAGE_PREFIX);
+    }
+
+
+    @PostConstruct
+    public void init() {
+        if(fixtureScriptsSpecificationProvider == null) {
+            return;
+        }
+        setSpecification(fixtureScriptsSpecificationProvider.getSpecification());
+    }
+    //endregion
+
+
+    //region > runFixtureScript (using choices as the drop-down policy)
+    @Override
+    public List<FixtureResult> runFixtureScript(
+            final FixtureScript fixtureScript,
+            @ParameterLayout(
+                named = "Parameters",
+                describedAs =
+                        "Script-specific parameters (if any).  The format depends on the script implementation (eg key=value, CSV, JSON, XML etc)",
+                multiLine = 10)
+            @Parameter(optionality = Optionality.OPTIONAL)
+            final String parameters) {
+        return super.runFixtureScript(fixtureScript, parameters);
+    }
+
+    /**
+     * Hide the actions of this service if no configuring {@link FixtureScriptsSpecificationProvider} was provided or is available.
+     */
+    public boolean hideRunFixtureScript() {
+        return hideIfPolicyNot(FixtureScriptsSpecification.DropDownPolicy.CHOICES);
+    }
+
+    @Override
+    public String disableRunFixtureScript(final FixtureScript fixtureScript, final String parameters) {
+        return super.disableRunFixtureScript(fixtureScript, parameters);
+    }
+
+    @Override
+    public FixtureScript default0RunFixtureScript() {
+        Class<? extends FixtureScript> defaultScript = getSpecification().getRunScriptDefaultScriptClass();
+        if(defaultScript == null) {
+            return null;
+        }
+        return findFixtureScriptFor(defaultScript);
+    }
+
+    /**
+     * Promote to public visibility.
+     */
+    @Override
+    public List<FixtureScript> choices0RunFixtureScript() {
+        return super.choices0RunFixtureScript();
+    }
+
+    @Override
+    public String validateRunFixtureScript(final FixtureScript fixtureScript, final String parameters) {
+        return super.validateRunFixtureScript(fixtureScript, parameters);
+    }
+
+    //endregion
+
+    //region > runFixtureScript (using autoComplete as drop-down policy)
+    @ActionLayout(
+            named = "Run Fixture Script"
+    )
+    public List<FixtureResult> runFixtureScriptWithAutoComplete(
+            final FixtureScript fixtureScript,
+            @ParameterLayout(
+                named = "Parameters",
+                describedAs =
+                        "Script-specific parameters (if any).  The format depends on the script implementation (eg key=value, CSV, JSON, XML etc)",
+                multiLine = 10)
+            @Parameter(optionality = Optionality.OPTIONAL)
+            final String parameters) {
+        return this.runFixtureScript(fixtureScript, parameters);
+    }
+
+    public boolean hideRunFixtureScriptWithAutoComplete() {
+        return hideIfPolicyNot(FixtureScriptsSpecification.DropDownPolicy.AUTO_COMPLETE);
+    }
+
+    public String disableRunFixtureScriptWithAutoComplete(final FixtureScript fixtureScript, final String parameters) {
+        return disableRunFixtureScript(fixtureScript, parameters);
+    }
+
+    public FixtureScript default0RunFixtureScriptWithAutoComplete() {
+        return default0RunFixtureScript();
+    }
+
+    public List<FixtureScript> autoComplete0RunFixtureScriptWithAutoComplete(final @MinLength(1) String arg) {
+        return autoComplete0RunFixtureScript(arg);
+    }
+
+    public String validateRunFixtureScriptWithAutoComplete(final FixtureScript fixtureScript, final String parameters) {
+        return super.validateRunFixtureScript(fixtureScript, parameters);
+    }
+    //endregion
+
+    //region > recreateObjectsAndReturnFirst
+
+    @Action(
+            restrictTo = RestrictTo.PROTOTYPING
+    )
+    @ActionLayout(
+            cssClassFa="fa fa-refresh"
+    )
+    @MemberOrder(sequence="20")
+    public Object recreateObjectsAndReturnFirst() {
+        Class<? extends FixtureScript> recreateScriptClass =  getSpecification().getRecreateScriptClass();
+        final FixtureScript recreateScript = findFixtureScriptFor(recreateScriptClass);
+        if(recreateScript == null) {
+            return null;
+        }
+        final List<FixtureResult> results = recreateScript.run(null);
+        if(results.isEmpty()) {
+            return null;
+        }
+        return results.get(0).getObject();
+    }
+    public boolean hideRecreateObjectsAndReturnFirst() {
+        return getSpecification().getRecreateScriptClass() == null;
+    }
+
+    //endregion
+
+    //region > helpers
+    private boolean hideIfPolicyNot(final FixtureScriptsSpecification.DropDownPolicy requiredPolicy) {
+        return fixtureScriptsSpecificationProvider == null || getSpecification().getRunScriptDropDownPolicy() != requiredPolicy;
+    }
+    //endregion
+
+    //region > injected services
+    @Inject
+    private FixtureScriptsSpecificationProvider fixtureScriptsSpecificationProvider;
+    //endregion
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecification.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecification.java b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecification.java
new file mode 100644
index 0000000..d6ace0a
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecification.java
@@ -0,0 +1,143 @@
+package org.apache.isis.applib.services.fixturespec;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.fixturescripts.FixtureResultList;
+import org.apache.isis.applib.fixturescripts.FixtureScript;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+
+/**
+ * Pulls together the various state that influences the behaviour of {@link FixtureScripts} service.
+ */
+public class FixtureScriptsSpecification {
+
+    /**
+     * In Whether to show available {@link FixtureScript}s using a choices or an autocomplete.
+     */
+    public enum DropDownPolicy {
+        AUTO_COMPLETE,
+        CHOICES;
+
+        public boolean isAutoComplete() {
+            return this == AUTO_COMPLETE;
+        }
+
+        public boolean isChoices() {
+            return this == CHOICES;
+        }
+    }
+
+    /**
+     * Typically preferable to use the create using the {@link FixtureScriptsSpecification.Builder}
+     * (obtained from {@link #builder(Class)}).
+     * @param packagePrefix  - to search for fixture script implementations, eg "com.mycompany"
+     * @param nonPersistedObjectsStrategy - how to handle any non-persisted objects that are {@link FixtureScripts#newFixtureResult(FixtureScript, String, Object, boolean) added} to a {@link FixtureResultList}.
+     * @param multipleExecutionStrategy - whether more than one instance of the same fixture script class can be run multiple times
+     * @param runScriptDefaultScriptClass - the fixture script to provide as a default in {@link FixtureScripts#runFixtureScript(FixtureScript, String)} action.
+     * @param runScriptDropDownPolicy - whether the {@link FixtureScripts#runFixtureScript(FixtureScript, String)} should use a choices or an autoComplete.
+     * @param recreateScriptClass - if specified, then make the {@link FixtureScriptsDefault#recreateObjectsAndReturnFirst()} action visible.
+     */
+    public FixtureScriptsSpecification(
+            final String packagePrefix,
+            final FixtureScripts.NonPersistedObjectsStrategy nonPersistedObjectsStrategy,
+            final FixtureScripts.MultipleExecutionStrategy multipleExecutionStrategy,
+            final Class<? extends FixtureScript> runScriptDefaultScriptClass,
+            final DropDownPolicy runScriptDropDownPolicy,
+            final Class<? extends FixtureScript> recreateScriptClass) {
+        this.packagePrefix = packagePrefix;
+        this.nonPersistedObjectsStrategy = nonPersistedObjectsStrategy;
+        this.multipleExecutionStrategy = multipleExecutionStrategy;
+        this.recreateScriptClass = recreateScriptClass;
+        this.runScriptDefaultScriptClass = runScriptDefaultScriptClass;
+        this.dropDownPolicy = runScriptDropDownPolicy;
+    }
+
+    private final String packagePrefix;
+    private final FixtureScripts.NonPersistedObjectsStrategy nonPersistedObjectsStrategy;
+    private final FixtureScripts.MultipleExecutionStrategy multipleExecutionStrategy;
+
+    private final Class<? extends FixtureScript> recreateScriptClass;
+    private final Class<? extends FixtureScript> runScriptDefaultScriptClass;
+    private final DropDownPolicy dropDownPolicy;
+
+    @Programmatic
+    public String getPackagePrefix() {
+        return packagePrefix;
+    }
+
+    @Programmatic
+    public FixtureScripts.NonPersistedObjectsStrategy getNonPersistedObjectsStrategy() {
+        return nonPersistedObjectsStrategy;
+    }
+
+    @Programmatic
+    public FixtureScripts.MultipleExecutionStrategy getMultipleExecutionStrategy() {
+        return multipleExecutionStrategy;
+    }
+
+    @Programmatic
+    public Class<? extends FixtureScript> getRunScriptDefaultScriptClass() {
+        return runScriptDefaultScriptClass;
+    }
+
+    @Programmatic
+    public DropDownPolicy getRunScriptDropDownPolicy() {
+        return dropDownPolicy;
+    }
+
+    @Programmatic
+    public Class<? extends FixtureScript> getRecreateScriptClass() {
+        return recreateScriptClass;
+    }
+
+    public static class Builder {
+        private final String packagePrefix;
+        private FixtureScripts.NonPersistedObjectsStrategy nonPersistedObjectsStrategy = FixtureScripts.NonPersistedObjectsStrategy.PERSIST;
+        private FixtureScripts.MultipleExecutionStrategy multipleExecutionStrategy = FixtureScripts.MultipleExecutionStrategy.IGNORE;
+        private Class<? extends FixtureScript> recreateScriptClass = null;
+        private Class<? extends FixtureScript> defaultScriptClass = null;
+        private DropDownPolicy dropDownPolicy = DropDownPolicy.CHOICES;
+
+        public Builder(final Class<?> contextClass) {
+            this(contextClass.getPackage().getName());
+        }
+        public Builder(final String packagePrefix) {
+            this.packagePrefix = packagePrefix;
+        }
+
+        public Builder with(FixtureScripts.NonPersistedObjectsStrategy nonPersistedObjectsStrategy) {
+            this.nonPersistedObjectsStrategy = nonPersistedObjectsStrategy;
+            return this;
+        }
+        public Builder with(FixtureScripts.MultipleExecutionStrategy multipleExecutionStrategy) {
+            this.multipleExecutionStrategy = multipleExecutionStrategy;
+            return this;
+        }
+        public Builder withRecreate(Class<? extends FixtureScript> recreateScriptClass) {
+            this.recreateScriptClass = recreateScriptClass;
+            return this;
+        }
+        public Builder withRunScriptDefault(Class<? extends FixtureScript> defaultScriptClass) {
+            this.defaultScriptClass = defaultScriptClass;
+            return this;
+        }
+        public Builder withRunScriptDropDown(DropDownPolicy dropDownPolicy) {
+            this.dropDownPolicy = dropDownPolicy;
+            return this;
+        }
+
+        public FixtureScriptsSpecification build() {
+            return new FixtureScriptsSpecification(
+                    packagePrefix,
+                    nonPersistedObjectsStrategy, multipleExecutionStrategy,
+                    defaultScriptClass, dropDownPolicy, recreateScriptClass
+            );
+        }
+    }
+
+    public static Builder builder(final Class<?> contextClass) {
+        return new Builder(contextClass);
+    }
+    public static Builder builder(final String packagePrefix) {
+        return new Builder(packagePrefix);
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecificationProvider.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecificationProvider.java b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecificationProvider.java
new file mode 100644
index 0000000..e72d07c
--- /dev/null
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/fixturespec/FixtureScriptsSpecificationProvider.java
@@ -0,0 +1,37 @@
+/*
+ *  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.services.fixturespec;
+
+import org.apache.isis.applib.annotation.Programmatic;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+
+/**
+ * Rather than subclassing {@link FixtureScripts} class, you can instead implement this interface as a service.
+ * 
+ * <p>
+ *     The framework will automatically instantiate {@link FixtureScriptsDefault} as a fallback, and use the
+ *     {@link FixtureScriptsSpecification} obtained from <i>this</i> service to configure itself.
+ * </p>
+ */
+public interface FixtureScriptsSpecificationProvider {
+
+    @Programmatic
+    FixtureScriptsSpecification getSpecification();
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
----------------------------------------------------------------------
diff --git a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
index 2976d7e..a96682b 100644
--- a/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
+++ b/core/applib/src/main/java/org/apache/isis/objectstore/jdo/applib/service/exceprecog/ExceptionRecognizerCompositeForJdoObjectStore.java
@@ -34,12 +34,16 @@ import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerComposite;
  * Convenience implementation of the {@link ExceptionRecognizer} domain service that
  * recognizes a number of common and non-fatal exceptions (such as unique constraint
  * violations).
- * 
+ *
  * <p>
- * If using the JDO Object store, either register in <tt>isis.properties</tt>, or
- * compose your own, out of the underlying more fine-grained {@link ExceptionRecognizer} implementations. 
+ *     Unlike most other domain services, the framework will consult <i>all</i>
+ *     registered implementations of this service (chain of responsibility pattern) (rather than
+ *     the first one found).
+ * </p>
  */
-@DomainService(nature = NatureOfService.DOMAIN)
+@DomainService(
+        nature = NatureOfService.DOMAIN
+)
 public class ExceptionRecognizerCompositeForJdoObjectStore extends ExceptionRecognizerComposite {
 
     public static final String KEY_DISABLE = "isis.services.ExceptionRecognizerCompositeForJdoObjectStore.disable";

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServicesInstallerAbstract.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServicesInstallerAbstract.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServicesInstallerAbstract.java
index da02a10..d6abda5 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServicesInstallerAbstract.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/services/ServicesInstallerAbstract.java
@@ -22,6 +22,7 @@ package org.apache.isis.core.runtime.services;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
+
 import org.apache.isis.core.commons.config.InstallerAbstract;
 import org.apache.isis.core.runtime.system.DeploymentType;
 
@@ -52,17 +53,14 @@ public abstract class ServicesInstallerAbstract extends InstallerAbstract implem
         }
     }
 
-    @Override
-    public List<Object> getServices(final DeploymentType deploymentType) {
-        return services;
-    }
-
     public void addServices(final List<Object> services) {
         addService(services);
     }
 
-    public void removeService(final Object service) {
-        services.remove(service);
+    @Override
+    public List<Object> getServices(final DeploymentType deploymentType) {
+        return services;
     }
 
+
 }

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisSystemAbstract.java
----------------------------------------------------------------------
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisSystemAbstract.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisSystemAbstract.java
index 2b2b62f..f4c2a16 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisSystemAbstract.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/systemusinginstallers/IsisSystemAbstract.java
@@ -25,6 +25,8 @@ import java.util.List;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.isis.applib.fixtures.LogonFixture;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+import org.apache.isis.applib.services.fixturespec.FixtureScriptsDefault;
 import org.apache.isis.core.commons.components.Installer;
 import org.apache.isis.core.commons.components.Noop;
 import org.apache.isis.core.commons.config.IsisConfiguration;
@@ -176,6 +178,9 @@ public abstract class IsisSystemAbstract extends IsisSystemFixturesHookAbstract
         final SpecificationLoaderSpi reflector = obtainSpecificationLoaderSpi(deploymentType, metaModelRefiners);
 
         final List<Object> services = obtainServices();
+        if(!contains(services, FixtureScripts.class)) {
+            services.add(new FixtureScriptsDefault());
+        }
 
         // bind metamodel to the (runtime) framework
         final RuntimeContextFromSession runtimeContext = obtainRuntimeContextFromSession();
@@ -191,6 +196,16 @@ public abstract class IsisSystemAbstract extends IsisSystemFixturesHookAbstract
                 services);
     }
 
+    static boolean contains(final List<Object> services, final Class<?> serviceClass) {
+        for (Object service : services) {
+            if(serviceClass.isAssignableFrom(service.getClass())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
     protected RuntimeContextFromSession obtainRuntimeContextFromSession() {
         return new RuntimeContextFromSession();
     }

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesProvider.java
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesProvider.java b/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesProvider.java
new file mode 100644
index 0000000..4407e4a
--- /dev/null
+++ b/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesProvider.java
@@ -0,0 +1,42 @@
+/*
+ *  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 domainapp.fixture;
+
+import org.apache.isis.applib.annotation.DomainService;
+import org.apache.isis.applib.annotation.NatureOfService;
+import org.apache.isis.applib.fixturescripts.FixtureScripts;
+import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecification;
+import org.apache.isis.applib.services.fixturespec.FixtureScriptsSpecificationProvider;
+
+/**
+ * Specifies where to find fixtures, and other settings.
+ */
+@DomainService(nature = NatureOfService.DOMAIN)
+public class DomainAppFixturesProvider implements FixtureScriptsSpecificationProvider {
+    @Override
+    public FixtureScriptsSpecification getSpecification() {
+        return FixtureScriptsSpecification
+                .builder(DomainAppFixturesProvider.class)
+                .with(FixtureScripts.MultipleExecutionStrategy.EXECUTE)
+                .withRunScriptDefault(RecreateSimpleObjects.class)
+                .withRunScriptDropDown(FixtureScriptsSpecification.DropDownPolicy.CHOICES)
+                .withRecreate(RecreateSimpleObjects.class)
+                .build();
+    }
+}

http://git-wip-us.apache.org/repos/asf/isis/blob/59659632/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesService.java
----------------------------------------------------------------------
diff --git a/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesService.java b/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesService.java
deleted file mode 100644
index 751bad3..0000000
--- a/example/application/simpleapp/fixture/src/main/java/domainapp/fixture/DomainAppFixturesService.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *  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 domainapp.fixture;
-
-import java.util.List;
-
-import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.applib.annotation.ActionLayout;
-import org.apache.isis.applib.annotation.DomainService;
-import org.apache.isis.applib.annotation.DomainServiceLayout;
-import org.apache.isis.applib.annotation.MemberOrder;
-import org.apache.isis.applib.annotation.RestrictTo;
-import org.apache.isis.applib.fixturescripts.FixtureResult;
-import org.apache.isis.applib.fixturescripts.FixtureScript;
-import org.apache.isis.applib.fixturescripts.FixtureScripts;
-
-import domainapp.fixture.scenarios.RecreateSimpleObjects;
-
-/**
- * Enables fixtures to be installed from the application.
- */
-@DomainService
-@DomainServiceLayout(
-        named="Prototyping",
-        menuBar = DomainServiceLayout.MenuBar.SECONDARY,
-        menuOrder = "500"
-)
-public class DomainAppFixturesService extends FixtureScripts {
-
-    public DomainAppFixturesService() {
-        super(DomainAppFixturesService.class.getPackage().getName(), MultipleExecutionStrategy.EXECUTE);
-    }
-
-    @Override
-    public FixtureScript default0RunFixtureScript() {
-        return findFixtureScriptFor(RecreateSimpleObjects.class);
-    }
-
-    @Override
-    public List<FixtureScript> choices0RunFixtureScript() {
-        return super.choices0RunFixtureScript();
-    }
-
-
-    // //////////////////////////////////////
-
-    @Action(
-            restrictTo = RestrictTo.PROTOTYPING
-    )
-    @ActionLayout(
-            cssClassFa="fa fa-refresh"
-    )
-    @MemberOrder(sequence="20")
-    public Object recreateObjectsAndReturnFirst() {
-        final List<FixtureResult> run = findFixtureScriptFor(RecreateSimpleObjects.class).run(null);
-        return run.get(0).getObject();
-    }
-
-
-}