You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2020/02/21 14:52:31 UTC

[isis] 02/04: ISIS-2062: refguide docs on ClockService and "mocking-the-clock"; remove framework usages of the Clock singleton.

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 6b5688e7aacee0147205e7de4122bb894f4d5a2c
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Feb 21 10:25:01 2020 +0000

    ISIS-2062: refguide docs on ClockService and "mocking-the-clock"; remove framework usages of the Clock singleton.
---
 .../services/bookmarkui/BookmarkUiService.java     |  4 +-
 .../examples/services/clock/ClockService.java      |  1 +
 .../applib-svc/pages/AcceptHeaderService.adoc      |  3 +-
 .../pages/ApplicationFeatureRepository.adoc        |  4 +-
 .../modules/applib-svc/pages/AuditerService.adoc   |  4 +-
 .../modules/applib-svc/pages/BookmarkService.adoc  |  2 +-
 .../modules/applib-svc/pages/ClockService.adoc     | 77 ++--------------------
 .../services/bookmarkui/BookmarkUiService.java     |  4 +-
 .../isis/applib/services/clock/ClockService.java   |  1 +
 .../isis/applib/services/command/Command.java      |  4 +-
 .../ValueSemanticsProviderAndFacetAbstract.java    |  8 ---
 .../datesql/JavaSqlDateValueSemanticsProvider.java | 20 ++----
 .../JavaUtilDateValueSemanticsProvider.java        |  6 +-
 .../timesql/JavaSqlTimeValueSemanticsProvider.java |  7 +-
 .../demotodoitem/DemoToDoItemRowHandler.java       |  7 +-
 .../demoapp/todomodule/dom/ExcelDemoToDoItem.java  |  8 ++-
 .../ExcelDemoToDoItem_recreate5_for.java           | 19 +++---
 .../adoc/modules/fixtures/pages/about.adoc         |  2 +-
 .../pages/fixture-scripts/mocking-the-clock.adoc   | 49 ++++++++++++++
 .../fixture-scripts/ticking-clock-fixture.adoc     | 21 ------
 .../applib/services/FixturesLifecycleService.java  | 29 ++++----
 .../AuthenticatedWebSessionForIsis.java            | 20 +++++-
 22 files changed, 128 insertions(+), 172 deletions(-)

diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmarkui/BookmarkUiService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmarkui/BookmarkUiService.java
index bfca5bb..e21431b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmarkui/BookmarkUiService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/bookmarkui/BookmarkUiService.java
@@ -23,8 +23,6 @@ import org.apache.isis.applib.annotation.Programmatic;
 
 // tag::refguide[]
 public interface BookmarkUiService {
-
-    void clear();
-
+    void clear();                   // <1>
 }
 // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/examples/services/clock/ClockService.java b/api/applib/src/main/adoc/modules/applib-svc/examples/services/clock/ClockService.java
index d90cb5c..597a56b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/examples/services/clock/ClockService.java
+++ b/api/applib/src/main/adoc/modules/applib-svc/examples/services/clock/ClockService.java
@@ -82,5 +82,6 @@ public class ClockService {
         final DateTimeZone timeZone = DateTimeZone.forTimeZone(TimeZone.getDefault());
         return new org.joda.time.LocalDate(nowAsMillis(), timeZone);
     }
+
 }
 // end::refguide[]
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/AcceptHeaderService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/AcceptHeaderService.adoc
index a0bacd4..fdace7b 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/AcceptHeaderService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/AcceptHeaderService.adoc
@@ -27,7 +27,8 @@ Otherwise the service will likely return `null`.
 
 == Implementation
 
-The default implementation is provided by `o.a.i.viewer.restfulobjects.rendering.service.acceptheader.AcceptHeaderServiceForRest`, and is xref:refguide:applib-ant:RequestScoped.adoc[`@RequestScoped`].
+The xref:vro:ROOT:about.adoc[Restful Objects] viewer provides an implementation of this API, `o.a.i.viewer.restfulobjects.rendering.service.acceptheader.AcceptHeaderServiceForRest`.
+
 
 == Usage
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ApplicationFeatureRepository.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ApplicationFeatureRepository.adoc
index 34b77e2..726bf8a 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ApplicationFeatureRepository.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ApplicationFeatureRepository.adoc
@@ -26,9 +26,9 @@ These methods are designed primarily to return lists of strings for use in drop-
 
 == Implementation
 
-The default implementation of this domain service is `o.a.i.core.metamodel.services.appfeat.ApplicationFeatureRepositoryDefault`.
+The core framework (xref:core:metamodel:about.adoc[MetaModel] module) provides a default implementation, `o.a.i.core.metamodel.services.appfeat.ApplicationFeatureRepositoryDefault`.
 
-It supports the following configuration properties:
+This implementation supports the following configuration properties:
 
 * xref:refguide:config:sections/isis.core.runtime-services.adoc#isis.core.runtime-services.application-features.init[`isis.core.runtime-services.application-features.init`]
 
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/AuditerService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/AuditerService.adoc
index e199834..1aaa662 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/AuditerService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/AuditerService.adoc
@@ -35,8 +35,8 @@ The framework allows multiple implementations of this service to be registered;
 
 There are two implementations provided by the framework:
 
-* The core framework provides the `AuditerServiceLogging` (in `o.a.i.applib.services.audit` package).
-This simply logs the messages to a link:https://logging.apache.org/log4j/log4j-2.2/manual/configuration.html[Log4j2] logger.
+* The core framework provides a fallback implementation, `o.a.i.applib.services.audit.AuditerServiceLogging`.
+This simply logs the messages using a link:https://logging.apache.org/log4j/log4j-2.2/manual/configuration.html[Log4j2] logger.
 +
 [source,xml]
 .log4j2-spring.xml
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
index f4d807c..a1c8594 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/BookmarkService.adoc
@@ -35,7 +35,7 @@ include::refguide:applib-svc:example$services/bookmark/BookmarkService.java[tags
 
 == Implementation
 
-The core framework provides a default implementation of this API, namely `o.a.i.core.metamodel.services.bookmarks.BookmarkServiceInternalDefault`
+The core framework (xref:core:runtime-services:about.adoc[Runtime Services] module) provides a default implementation of this API, namely `o.a.i.core.runtimeservices.bookmarks.BookmarkServiceDefault`
 
 
 == `BookmarkHolder`
diff --git a/api/applib/src/main/adoc/modules/applib-svc/pages/ClockService.adoc b/api/applib/src/main/adoc/modules/applib-svc/pages/ClockService.adoc
index 8ba4ddf..76f761f 100644
--- a/api/applib/src/main/adoc/modules/applib-svc/pages/ClockService.adoc
+++ b/api/applib/src/main/adoc/modules/applib-svc/pages/ClockService.adoc
@@ -1,4 +1,3 @@
-[[ClockService]]
 = `ClockService`
 :Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
 :page-partial:
@@ -19,85 +18,21 @@ This service can be injected into any domain object (and can be mocked out for u
 Apache Isis provides such a facade through the `ClockService`.
 
 
-
-== API & Implementation
+== API
 
 The API defined by `ClockService` is:
 
 [source,java]
 ----
-@DomainService(nature = NatureOfService.DOMAIN)
-public class ClockService {
-    @Programmatic
-    public LocalDate now() { /* ... */ }
-    @Programmatic
-    public LocalDateTime nowAsLocalDateTime() { /* ... */ }
-    @Programmatic
-    public DateTime nowAsDateTime() { /* ... */ }
-    @Programmatic
-    public Timestamp nowAsJavaSqlTimestamp() { /* ... */ }
-    @Programmatic
-    public long nowAsMillis() { /* ... */ }
-}
+include::refguide:applib-svc:example$services/clock/ClockService.java[tags="refguide"]
 ----
 
-This class (`o.a.i.applib.services.clock.ClockService`) is also the default implementation.  The time provided by this default implementation is based on the system clock.
-
-
-
-
-== Testing Support
-
-The default `ClockService` implementation in fact simply delegates to another class defined in the API, namely the `o.a.i.applib.clock.Clock`, an abstract singleton class.
-It is not recommended that your code use the `Clock` directly, but it's worth understanding how this all works.
-
-If running in xref:refguide:config:deployment-types.adoc[production] (server) mode, then the framework will (lazily) instantiate the ``SystemClock` when first required.
-This is a read-only clock that reads from the system time.
-The instance registers itself as the singleton and cannot be replaced.
-
-If running in xref:refguide:config:deployment-types.adoc[prototype] mode, though, then the framework will instead instantiate `FixtureClock`.
-This is a read-write clock that will behave as the system clock, unless it is explicitly set using eg, `FixtureClock#setDate(...)` or `FixtureClock#setTime(...)` etc.
-
-Moreover, `FixtureClock` singleton can be replaced with another implementation.
-And, it is sometimes useful to replace it using `TickingFixtureClock`, a subclass that is very similar to `FixtureClock` (in that the time can be changed) but which will continue to tick once set.
-
-To use `TickingFixtureClock` instead of `FixtureClock`, use the `TickingClockFixture` fixture script.
+Note that this domain service is also used by the framework itself to obtain the time, so it acts as an SPI as well.
 
+== Implementation
 
-
-
-=== Alternative Implementations
-
-Suppose you want (as discussed in the introduction to this service) to use a clock that delegates to NNTP.
-For most domain services this would amount to implementing the appropriate service and registering the owning module so that it is used in preference to any implementations provided by default by the framework.
-
-In the case of the `ClockService`, though, this approach (unfortunately) will not work, because parts of Apache Isis (still) delegate to the `Clock` singleton rather than using the `ClockService` domain service.
-
-The workaround, therefore, is to implement your functionality as a subclass of `Clock`.
-You can write a domain service that will ensure that your implementation is used ahead of any implementations provided by the framework.
-
-For example:
-
-[source,java]
-----
-@DomainService(nature=NatureOfService.DOMAIN)
-public class NntpClockServiceInitializer  {
-    @Programmatic
-    @PostConstruct
-    public void postConstruct(Map<String,String> properties) {
-        new NntpClock(properties);                       // <1>
-    }
-    private static class NntpClock extends Clock {
-        NntpClock(Map<String,String> properties) { /* ... */ } // <2>
-        protected long time() { /* ... */ }                    // <3>
-            ... NNTP stuff here ...
-        }
-    }
-}
-----
-<1> enough to simply instantiate the `Clock`; it will register itself as singleton
-<2> connect to NNTP service using configuration properties from `isis.properties`
-<3> call to NNTP service here
+This class (`o.a.i.applib.services.clock.ClockService`) is also the default implementation.
+The time provided by this default implementation is based on the system clock.
 
 
 
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmarkui/BookmarkUiService.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmarkui/BookmarkUiService.java
index bfca5bb..e21431b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmarkui/BookmarkUiService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmarkui/BookmarkUiService.java
@@ -23,8 +23,6 @@ import org.apache.isis.applib.annotation.Programmatic;
 
 // tag::refguide[]
 public interface BookmarkUiService {
-
-    void clear();
-
+    void clear();                   // <1>
 }
 // end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java b/api/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
index d90cb5c..597a56b 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/clock/ClockService.java
@@ -82,5 +82,6 @@ public class ClockService {
         final DateTimeZone timeZone = DateTimeZone.forTimeZone(TimeZone.getDefault());
         return new org.joda.time.LocalDate(nowAsMillis(), timeZone);
     }
+
 }
 // end::refguide[]
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
index a58f241..61644f6 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/command/Command.java
@@ -24,8 +24,6 @@ import org.apache.isis.applib.Identifier;
 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.annotation.Programmatic;
-import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.events.domain.ActionDomainEvent;
 import org.apache.isis.applib.services.HasUniqueId;
 import org.apache.isis.applib.services.background.BackgroundCommandService;
@@ -300,7 +298,7 @@ public interface Command extends HasUniqueId {
          * <b>NOT API</b>: intended to be called only by the framework.
          *
          * <p>
-         * Implementation notes: set when the Isis PersistenceSession is opened.  Uses the applib {@link Clock}.
+         * Implementation notes: set when the Isis PersistenceSession is opened.
          */
         void setTimestamp(Timestamp timestamp);
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueSemanticsProviderAndFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueSemanticsProviderAndFacetAbstract.java
index 3cdc95d..3fd077c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueSemanticsProviderAndFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/value/vsp/ValueSemanticsProviderAndFacetAbstract.java
@@ -26,7 +26,6 @@ import org.apache.isis.applib.adapters.DefaultsProvider;
 import org.apache.isis.applib.adapters.EncoderDecoder;
 import org.apache.isis.applib.adapters.Parser;
 import org.apache.isis.applib.adapters.ValueSemanticsProvider;
-import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.core.commons.exceptions.UnknownTypeException;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
@@ -279,13 +278,6 @@ implements ValueSemanticsProvider<T>, EncoderDecoder<T>, Parser<T>, DefaultsProv
         }
     }
 
-    // //////////////////////////////////////////////////////////
-    // Dependencies (from singleton)
-    // //////////////////////////////////////////////////////////
-
-    protected static Clock getClock() {
-        return Clock.getInstance();
-    }
 
     @Override public void appendAttributesTo(final Map<String, Object> attributeMap) {
         super.appendAttributesTo(attributeMap);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datesql/JavaSqlDateValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datesql/JavaSqlDateValueSemanticsProvider.java
index 93b59f9..3a8a913 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datesql/JavaSqlDateValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/datesql/JavaSqlDateValueSemanticsProvider.java
@@ -29,7 +29,7 @@ import java.util.Map;
 
 import org.apache.isis.applib.adapters.EncoderDecoder;
 import org.apache.isis.applib.adapters.Parser;
-import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.value.ValueSemanticsProviderAbstractTemporal;
@@ -78,9 +78,6 @@ public class JavaSqlDateValueSemanticsProvider extends ValueSemanticsProviderAbs
         }
     }
 
-    // //////////////////////////////////////////////////////////////////
-    // temporal-specific stuff
-    // //////////////////////////////////////////////////////////////////
 
     @Override
     protected void clearFields(final Calendar cal) {
@@ -141,16 +138,6 @@ public class JavaSqlDateValueSemanticsProvider extends ValueSemanticsProviderAbs
     }
 
 
-
-
-
-
-
-
-
-
-    private static final Date DEFAULT_VALUE = null; // no default
-
     @Override
     protected Date add(final Date original, final int years, final int months, final int days, final int hours, final int minutes) {
         final Date date = original;
@@ -181,7 +168,10 @@ public class JavaSqlDateValueSemanticsProvider extends ValueSemanticsProviderAbs
 
     @Override
     protected Date now() {
-        return new Date(Clock.getEpochMillis());
+        return getServiceRegistry().lookupService(ClockService.class)
+                .map(ClockService::nowAsMillis)
+                .map(Date::new)
+                .get();
     }
 
     @Override //[ISIS-2005] java.sql.Date requires special treatment, so overriding the default
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/dateutil/JavaUtilDateValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/dateutil/JavaUtilDateValueSemanticsProvider.java
index fa131fc..6b1ef08 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/dateutil/JavaUtilDateValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/dateutil/JavaUtilDateValueSemanticsProvider.java
@@ -30,7 +30,7 @@ import java.util.TimeZone;
 
 import org.apache.isis.applib.adapters.EncoderDecoder;
 import org.apache.isis.applib.adapters.Parser;
-import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.value.ValueSemanticsProviderAbstractTemporal;
@@ -164,7 +164,9 @@ public class JavaUtilDateValueSemanticsProvider extends ValueSemanticsProviderAb
 
     @Override
     protected Date now() {
-        return new Date(Clock.getEpochMillis());
+        return getServiceRegistry().lookupService(ClockService.class)
+                .map(ClockService::nowAsJavaUtilDate)
+                .get();
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/timesql/JavaSqlTimeValueSemanticsProvider.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/timesql/JavaSqlTimeValueSemanticsProvider.java
index cbed5c5..f11cb56 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/timesql/JavaSqlTimeValueSemanticsProvider.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/timesql/JavaSqlTimeValueSemanticsProvider.java
@@ -30,7 +30,7 @@ import java.util.Map;
 
 import org.apache.isis.applib.adapters.EncoderDecoder;
 import org.apache.isis.applib.adapters.Parser;
-import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.value.ValueSemanticsProviderAbstractTemporal;
@@ -156,7 +156,10 @@ public class JavaSqlTimeValueSemanticsProvider extends ValueSemanticsProviderAbs
 
     @Override
     protected Time now() {
-        return new java.sql.Time(Clock.getEpochMillis());
+        return getServiceRegistry().lookupService(ClockService.class)
+                .map(ClockService::nowAsMillis)
+                .map(Time::new)
+                .get();
     }
 
     @Override
diff --git a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/demomodule/fixturehandlers/demotodoitem/DemoToDoItemRowHandler.java b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/demomodule/fixturehandlers/demotodoitem/DemoToDoItemRowHandler.java
index 0f63a30..ea7cdcd 100644
--- a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/demomodule/fixturehandlers/demotodoitem/DemoToDoItemRowHandler.java
+++ b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/demomodule/fixturehandlers/demotodoitem/DemoToDoItemRowHandler.java
@@ -8,7 +8,7 @@ import java.util.List;
 import javax.inject.Inject;
 
 import org.apache.isis.applib.annotation.ViewModel;
-import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.user.UserService;
 import org.apache.isis.subdomains.excel.fixtures.demoapp.todomodule.dom.Category;
 import org.apache.isis.subdomains.excel.fixtures.demoapp.todomodule.dom.ExcelDemoToDoItem;
@@ -69,15 +69,16 @@ public class DemoToDoItemRowHandler implements ExcelFixtureRowHandler {
         return Collections.<Object>singletonList(toDoItem);
     }
 
-    private static LocalDate daysFromToday(final Integer i) {
+    private LocalDate daysFromToday(final Integer i) {
         if(i == null) {
             return null;
         }
-        final LocalDate date = Clock.getTimeAsLocalDate();
+        final LocalDate date = clockService.now();
         return date.plusDays(i);
     }
 
 
     @Inject private ExcelDemoToDoItemMenu toDoItemRepository;
     @Inject private UserService userService;
+    @Inject private ClockService clockService;
 }
diff --git a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/dom/ExcelDemoToDoItem.java b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/dom/ExcelDemoToDoItem.java
index ed388e3..6a871ce 100644
--- a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/dom/ExcelDemoToDoItem.java
+++ b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/dom/ExcelDemoToDoItem.java
@@ -27,6 +27,7 @@ import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.annotation.SemanticsOf;
 import org.apache.isis.applib.clock.Clock;
 import org.apache.isis.applib.jaxbadapters.PersistentEntityAdapter;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.repository.RepositoryService;
 import org.apache.isis.applib.services.title.TitleService;
@@ -110,7 +111,8 @@ public class ExcelDemoToDoItem implements Comparable<ExcelDemoToDoItem> /*, Cale
     @Inject private RepositoryService repositoryService;
     @Inject private TitleService titleService;
     @Inject private ExcelDemoToDoItemMenu toDoItems;
-    
+    @Inject private ClockService clockService;
+
     //region > title, iconName
 
     public String title() {
@@ -346,12 +348,12 @@ public class ExcelDemoToDoItem implements Comparable<ExcelDemoToDoItem> /*, Cale
     //region > Programmatic Helpers
     private static final long ONE_WEEK_IN_MILLIS = 7 * 24 * 60 * 60 * 1000L;
 
-    private static boolean isMoreThanOneWeekInPast(final LocalDate dueBy) {
+    private boolean isMoreThanOneWeekInPast(final LocalDate dueBy) {
         
         long epochMillisAtStartOfDay = 
                 dueBy.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                 
-        return epochMillisAtStartOfDay < (Clock.getEpochMillis() - ONE_WEEK_IN_MILLIS);
+        return epochMillisAtStartOfDay < (clockService.nowAsMillis() - ONE_WEEK_IN_MILLIS);
     }
 
     //endregion
diff --git a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/fixturescripts/ExcelDemoToDoItem_recreate5_for.java b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/fixturescripts/ExcelDemoToDoItem_recreate5_for.java
index 27841e5..2f253ad 100644
--- a/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/fixturescripts/ExcelDemoToDoItem_recreate5_for.java
+++ b/subdomains/excel/fixture/src/main/java/org/apache/isis/subdomains/excel/fixtures/demoapp/todomodule/fixturescripts/ExcelDemoToDoItem_recreate5_for.java
@@ -3,7 +3,10 @@ package org.apache.isis.subdomains.excel.fixtures.demoapp.todomodule.fixturescri
 import java.math.BigDecimal;
 import java.time.LocalDate;
 
+import javax.inject.Inject;
+
 import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.persistence.jdo.applib.services.IsisJdoSupport;
 import org.apache.isis.subdomains.excel.fixtures.demoapp.todomodule.dom.Category;
 import org.apache.isis.subdomains.excel.fixtures.demoapp.todomodule.dom.ExcelDemoToDoItem;
@@ -78,20 +81,14 @@ public class ExcelDemoToDoItem_recreate5_for extends FixtureScript {
         return toDoItem;
     }
 
-    private static LocalDate daysFromToday(final int i) {
-        final LocalDate date = Clock.getTimeAsLocalDate();
+    private LocalDate daysFromToday(final int i) {
+        final LocalDate date = clockService.now();
         return date.plusDays(i);
     }
 
 
-    // //////////////////////////////////////
-    // Injected services
-    // //////////////////////////////////////
-
-    @javax.inject.Inject
-    private ExcelDemoToDoItemMenu demoToDoItemMenu;
-
-    @javax.inject.Inject
-    private IsisJdoSupport isisJdoSupport;
+    @Inject private ExcelDemoToDoItemMenu demoToDoItemMenu;
+    @Inject private IsisJdoSupport isisJdoSupport;
+    @Inject private ClockService clockService;
 
 }
diff --git a/testing/fixtures/adoc/modules/fixtures/pages/about.adoc b/testing/fixtures/adoc/modules/fixtures/pages/about.adoc
index 7e44470..81efd5b 100644
--- a/testing/fixtures/adoc/modules/fixtures/pages/about.adoc
+++ b/testing/fixtures/adoc/modules/fixtures/pages/about.adoc
@@ -39,7 +39,7 @@ The following  sections explain the API and how to go about using the API.
 
 
 include::fixture-scripts/api-and-usage.adoc[leveloffset=+1]
-include::fixture-scripts/ticking-clock-fixture.adoc[leveloffset=+1]
+include::fixture-scripts/mocking-the-clock.adoc[leveloffset=+1]
 include::fixture-scripts/sudo-service.adoc[leveloffset=+1]
 
 
diff --git a/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/mocking-the-clock.adoc b/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/mocking-the-clock.adoc
new file mode 100644
index 0000000..2bef6c6
--- /dev/null
+++ b/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/mocking-the-clock.adoc
@@ -0,0 +1,49 @@
+= Mocking the Clock
+:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
+
+
+It's often useful to be able to change the effective time that a test runs.
+The framework itself uses the xref:refguide:applib-svc:ClockService.adoc[`ClockService`] to obtain the current time, and applications should also use this domain service for a consistent view of the current time.
+
+This page describes how to change the current time, and how to set up tests using fixture scripts with a mocked time.
+
+== FixtureClock
+
+The default xref:refguide:applib-svc:ClockService.adoc[`ClockService`] implementation in fact simply delegates to another class defined in the API, namely the `o.a.i.applib.clock.Clock`, an abstract singleton class.
+It is not recommended that your code use the `Clock` directly, but it's worth understanding how this all works.
+
+* If running in xref:refguide:config:deployment-types.adoc[production] (server) mode, then the framework will (lazily) instantiate the ``SystemClock` when first required.
+This is a read-only clock that reads from the system time.
+The instance registers itself as the singleton and cannot be replaced.
+
+* If running in xref:refguide:config:deployment-types.adoc[prototype] mode, though, then the framework (using `FixturesLifecycleService`) will instead instantiate `FixtureClock`.
+This is a read-write clock that will behave as the system clock, unless it is explicitly set using eg, `FixtureClock#setDate(...)` or `FixtureClock#setTime(...)` etc.
++
+WARNING: TODO: v2 - looking now to remove Clock singleton, so refactor FixtureClock and TickingFixtureClock with alternative implementations of ClockService.
+
+Moreover, the `FixtureClock` singleton can be replaced with another implementation.
+And, it is sometimes useful to replace it using `TickingFixtureClock`, a subclass that is very similar to `FixtureClock` (in that the time can be changed) but which will continue to tick once set.
+
+WARNING: TODO: v2 - this is currently broken; there is nothing that actually instantiates and installs the TickingFixtureClock.
+Will be superceded as a requirement if refactor to provide alternative ClockService implementations instead.
+
+== TickingClockFixture
+
+The `TickingClockFixture` is a pre-built fixture script that resets the date/time returned by the xref:refguide:applib-svc:ClockService.adoc[`ClockService`] to a known value.
+
+Thereafter the time returned continues to tick forward (as would the real clock) until reset once more.
+
+For example, to set the clock to return "3 Sept 2014", use:
+
+[source,java]
+----
+executionContext.executeChild(this, new TickingClockFixture().setTo("2014-09-03"));
+----
+
+A variety of format strings are supported; the format "YYYY-MM-DD" (as shown above) will work in every locale.
+
+NOTE: This fixture script requires that a `TickingFixtureClock` is initialized during bootstrapping.
+
+
+
+
diff --git a/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/ticking-clock-fixture.adoc b/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/ticking-clock-fixture.adoc
deleted file mode 100644
index 4421a6b..0000000
--- a/testing/fixtures/adoc/modules/fixtures/pages/fixture-scripts/ticking-clock-fixture.adoc
+++ /dev/null
@@ -1,21 +0,0 @@
-= Ticking Clock Fixture
-:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or ag [...]
-
-
-
-The `TickingClockFixture` is a pre-built fixture script that resets the date/time returned by the xref:refguide:applib-svc:ClockService.adoc[`ClockService`] to a known value.
-
-Thereafter the time returned continues to tick forward (as would the real clock) until reset once more.
-
-For example, to set the clock to return "3 Sept 2014", use:
-
-[source,java]
-----
-executionContext.executeChild(this, new TickingClockFixture().setTo("2014-09-03"));
-----
-
-A variety of format strings are supported; the format "YYYY-MM-DD" (as shown above) will work in every locale.
-
-The fixture script requires that a `TickingFixtureClock` is initialized during bootstrapping.
-This is done automatically in `HeadlessWithBootstrappingAbstract` (the superclass of `IntegrationTestAbstract3` and for BDD bootstrapping classes).
-
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/services/FixturesLifecycleService.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/services/FixturesLifecycleService.java
index be77226..83133f8 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/services/FixturesLifecycleService.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/services/FixturesLifecycleService.java
@@ -59,27 +59,20 @@ import lombok.extern.log4j.Log4j2;
 public class FixturesLifecycleService {
 
     @SuppressWarnings("unused")
-    private final IsisSessionFactory isisSessionFactory; // depends on relationship
-    private final IsisSystemEnvironment isisSystemEnvironment;
-    private final IsisConfiguration isisConfiguration;
-    private final ServiceInjector serviceInjector;
-    private final FixtureScripts fixtureScripts;
+
+    @Inject
+    private IsisSessionFactory isisSessionFactory; // depends on relationship
+    @Inject
+    private IsisSystemEnvironment isisSystemEnvironment;
+    @Inject
+    private IsisConfiguration isisConfiguration;
+    @Inject
+    private ServiceInjector serviceInjector;
+    @Inject
+    private FixtureScripts fixtureScripts;
 
     private FixtureScript initialFixtureScript;
 
-    @Inject
-    public FixturesLifecycleService(
-            final IsisSessionFactory isisSessionFactory,
-            final IsisSystemEnvironment isisSystemEnvironment,
-            final IsisConfiguration isisConfiguration,
-            final ServiceInjector serviceInjector,
-            final FixtureScripts fixtureScripts) {
-        this.isisSessionFactory = isisSessionFactory;
-        this.isisSystemEnvironment = isisSystemEnvironment;
-        this.isisConfiguration = isisConfiguration;
-        this.serviceInjector = serviceInjector;
-        this.fixtureScripts = fixtureScripts;
-    }
 
     @PostConstruct
     public void postConstruct() {
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
index 4c5dbad..9523658 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/AuthenticatedWebSessionForIsis.java
@@ -29,6 +29,7 @@ import org.apache.wicket.request.Request;
 import org.apache.wicket.request.cycle.RequestCycle;
 
 import org.apache.isis.applib.clock.Clock;
+import org.apache.isis.applib.services.clock.ClockService;
 import org.apache.isis.applib.services.session.SessionLoggingService;
 import org.apache.isis.core.runtime.session.IsisSessionFactory;
 import org.apache.isis.core.security.authentication.AuthenticationRequest;
@@ -245,7 +246,7 @@ implements BreadcrumbModelProvider, BookmarkedPagesModelProvider, IsisWebAppComm
         final Runnable loggingTask = ()->{
             // use hashcode as session identifier, to avoid re-binding http sessions if using Session#getId()
             int sessionHashCode = System.identityHashCode(AuthenticatedWebSessionForIsis.this);
-            sessionLoggingService.log(type, username, new Date(Clock.getEpochMillis()), causedBy, Integer.toString(sessionHashCode));
+            sessionLoggingService.log(type, username, now(), causedBy, Integer.toString(sessionHashCode));
         };
 
         if(isisSessionFactory!=null) {
@@ -266,13 +267,28 @@ implements BreadcrumbModelProvider, BookmarkedPagesModelProvider, IsisWebAppComm
             // fallback to System.err
             return new SessionLoggingService.Stderr();
         }
-
     }
     
     protected IsisSessionFactory getIsisSessionFactory() {
         return commonContext.lookupServiceElseFail(IsisSessionFactory.class);
     }
 
+
+    private Date now() {
+        try {
+            return commonContext.getServiceRegistry()
+                    .lookupService(ClockService.class)
+                    .map(ClockService::nowAsJavaUtilDate)
+                    .orElse(nowFallback());
+        } catch (Exception e) {
+            return nowFallback();
+        }
+    }
+
+    private Date nowFallback() {
+        return new Date(Clock.getEpochMillis());
+    }
+
     @Override
     public void replaceSession() {
         // do nothing here because this will lead to problems with Shiro