You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by da...@apache.org on 2023/03/13 14:01:24 UTC

[causeway] 01/02: CAUSEWAY-3373: adds first-cut impl of PageRenderSubscriber

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

danhaywood pushed a commit to branch CAUSEWAY-3373
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit c4e8703e2322724fbae10ffe45faf734a97a6777
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Mon Mar 13 12:07:31 2023 +0000

    CAUSEWAY-3373: adds first-cut impl of PageRenderSubscriber
---
 .../modules/documentation/pages/tooling.adoc       |  6 +-
 ...sewayModuleApplibChangeAndExecutionLoggers.java |  9 +--
 .../services/publishing/log/ExecutionLogger.java   |  1 -
 .../publishing/log/ObjectRenderedLogger.java       |  0
 ...{ExecutionLogger.java => PageRenderLogger.java} | 48 +++++++------
 .../publishing/spi/ObjectRenderSubscriber.java     | 63 ----------------
 .../publishing/spi/PageRenderSubscriber.java       | 83 ++++++++++++++++++++++
 .../applib/services/publishing/spi}/PageType.java  | 32 ++++-----
 .../viewer/wicket/model/models/PageType.java       | 15 +++-
 .../viewer/wicket/ui/pages/PageAbstract.java       | 18 +++++
 .../viewer/wicket/ui/pages/PageClassRegistry.java  |  2 +
 .../viewer/wicket/ui/pages/entity/EntityPage.java  | 12 ++++
 .../StandaloneCollectionPage.java                  | 29 ++++++++
 .../viewer/wicket/ui/pages/value/ValuePage.java    | 10 +++
 .../registries/pages/PageClassRegistryDefault.java | 25 ++++---
 15 files changed, 236 insertions(+), 117 deletions(-)

diff --git a/antora/components/conguide/modules/documentation/pages/tooling.adoc b/antora/components/conguide/modules/documentation/pages/tooling.adoc
index 349a05e4c3..1271191e4c 100644
--- a/antora/components/conguide/modules/documentation/pages/tooling.adoc
+++ b/antora/components/conguide/modules/documentation/pages/tooling.adoc
@@ -2,5 +2,9 @@
 
 :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 [...]
 
+[CAUTION]
+====
+TODO - v2, to document... the stuff in the `tooling` mvn module.
+====
+
 
-CAUTION: TODO - v2, to document
\ No newline at end of file
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/CausewayModuleApplibChangeAndExecutionLoggers.java b/api/applib/src/main/java/org/apache/causeway/applib/CausewayModuleApplibChangeAndExecutionLoggers.java
index 188939f9bc..e7635251bb 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/CausewayModuleApplibChangeAndExecutionLoggers.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/CausewayModuleApplibChangeAndExecutionLoggers.java
@@ -18,14 +18,10 @@
  */
 package org.apache.causeway.applib;
 
+import org.apache.causeway.applib.services.publishing.log.*;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.causeway.applib.services.publishing.log.CommandLogger;
-import org.apache.causeway.applib.services.publishing.log.EntityChangesLogger;
-import org.apache.causeway.applib.services.publishing.log.EntityPropertyChangeLogger;
-import org.apache.causeway.applib.services.publishing.log.ExecutionLogger;
-
 /**
  * Registers logging subscribers for the command/execution/change publishing subsystem.
  *
@@ -36,11 +32,12 @@ import org.apache.causeway.applib.services.publishing.log.ExecutionLogger;
     // Modules
     CausewayModuleApplib.class,
 
-    // Execution/Change Loggers
+    // Execution/Change/Page Loggers
     CommandLogger.class,
     EntityChangesLogger.class,
     EntityPropertyChangeLogger.class,
     ExecutionLogger.class,
+    PageRenderLogger.class,
 })
 public class CausewayModuleApplibChangeAndExecutionLoggers {
 
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java
index 826ca81c30..8ae23feb11 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java
@@ -60,7 +60,6 @@ public class ExecutionLogger implements ExecutionSubscriber {
                 InteractionDtoUtils.newInteractionDto(execution, InteractionDtoUtils.Strategy.DEEP);
 
         log.debug(InteractionDtoUtils.dtoMapper().toString(interactionDto));
-
     }
 
 }
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ObjectRenderedLogger.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ObjectRenderedLogger.java
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/PageRenderLogger.java
similarity index 60%
copy from api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java
copy to api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/PageRenderLogger.java
index 826ca81c30..aa14bb29bf 100644
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/ExecutionLogger.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/log/PageRenderLogger.java
@@ -18,50 +18,58 @@
  */
 package org.apache.causeway.applib.services.publishing.log;
 
+import lombok.extern.log4j.Log4j2;
+import lombok.val;
+
+import java.util.List;
+import java.util.function.Supplier;
+
 import javax.annotation.Priority;
 import javax.inject.Named;
 
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.stereotype.Service;
-
 import org.apache.causeway.applib.CausewayModuleApplib;
 import org.apache.causeway.applib.annotation.PriorityPrecedence;
-import org.apache.causeway.applib.services.iactn.Execution;
-import org.apache.causeway.applib.services.publishing.spi.ExecutionSubscriber;
-import org.apache.causeway.applib.util.schema.InteractionDtoUtils;
-import org.apache.causeway.schema.ixn.v2.InteractionDto;
-
-import lombok.extern.log4j.Log4j2;
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.applib.services.publishing.spi.PageRenderSubscriber;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Service;
 
 /**
- * Simple implementation of {@link ExecutionSubscriber} that just logs out the {@link Execution}'s
- * DTO to a debug log.
+ * Simple implementation of {@link PageRenderSubscriber} that just
+ * logs to a debug log.
  *
  * @since 2.0 {@index}
  */
 @Service
-@Named(ExecutionLogger.LOGICAL_TYPE_NAME)
+@Named(PageRenderLogger.LOGICAL_TYPE_NAME)
 @Priority(PriorityPrecedence.LATE)
 @Qualifier("Logging")
 @Log4j2
-public class ExecutionLogger implements ExecutionSubscriber {
+public class PageRenderLogger implements PageRenderSubscriber {
 
-    static final String LOGICAL_TYPE_NAME = CausewayModuleApplib.NAMESPACE + ".ExecutionLogger";
+    static final String LOGICAL_TYPE_NAME = CausewayModuleApplib.NAMESPACE + ".ObjectRenderedLogger";
 
     @Override
     public boolean isEnabled() {
         return log.isDebugEnabled();
     }
 
+
     @Override
-    public void onExecution(final Execution<?, ?> execution) {
+    public void onRenderedDomainObject(Bookmark bookmark) {
+        log.debug("rendered object: {}", bookmark.stringify());
+    }
 
-        final InteractionDto interactionDto =
-                InteractionDtoUtils.newInteractionDto(execution, InteractionDtoUtils.Strategy.DEEP);
+    @Override
+    public void onRenderedCollection(Supplier<List<Bookmark>> bookmarkSupplier) {
+        val buf = new StringBuffer();
+        bookmarkSupplier.get().forEach(x -> buf.append(x.stringify()).append("\n"));
+        log.debug("rendered list: \n{}", buf.toString());
+    }
 
-        log.debug(InteractionDtoUtils.dtoMapper().toString(interactionDto));
 
+    @Override
+    public void onRenderedValue(Object value) {
+        log.debug("rendered value: \n{}", value.toString());
     }
-
 }
-
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/ObjectRenderSubscriber.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/ObjectRenderSubscriber.java
deleted file mode 100644
index f4ca48fd65..0000000000
--- a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/ObjectRenderSubscriber.java
+++ /dev/null
@@ -1,63 +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 org.apache.causeway.applib.services.publishing.spi;
-
-import org.apache.causeway.applib.services.command.Command;
-import org.apache.causeway.commons.having.HasEnabling;
-
-/**
- * Part of the <i>Publishing SPI</i>. A component to receive {@link Command}s
- * (with publishing enabled) that just completed.
- *
- * @since 2.0 {@index}
- */
-public interface CommandSubscriber extends HasEnabling {
-
-    /**
-     * Notifies that the command will be published, and has transitioned to {@link org.apache.causeway.applib.services.command.Command.CommandPublishingPhase#READY}.
-     *
-     * <p>
-     *     This is an opportunity for implementations to process the command,
-     *     for example to persist an initial representation of it.
-     * </p>
-     */
-    void onReady(Command command);
-
-    /**
-     * Notifies that the command has started to execute, and has transitioned to {@link org.apache.causeway.applib.services.command.Command.CommandPublishingPhase#STARTED}.
-     *
-     * <p>
-     *     This is an opportunity for implementations to process the command,
-     *     for example to update any persisted representation of it.
-     * </p>
-     */
-    void onStarted(Command command);
-
-
-    /**
-     * Notifies that the command has completed and has transitioned to {@link org.apache.causeway.applib.services.command.Command.CommandPublishingPhase#COMPLETED}
-     *
-     * <p>
-     *     This is an opportunity for implementations to process the command,
-     *     for example to update any persisted representations of it.
-     * </p>
-     */
-    void onCompleted(Command command);
-
-}
diff --git a/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageRenderSubscriber.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageRenderSubscriber.java
new file mode 100644
index 0000000000..c4713beadf
--- /dev/null
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageRenderSubscriber.java
@@ -0,0 +1,83 @@
+/*
+ *  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.causeway.applib.services.publishing.spi;
+
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.commons.having.HasEnabling;
+
+/**
+ * Part of the <i>Publishing SPI</i>. A component to receive notifaction that a domain object
+ * or a standalone list of domain objects has been rendered.
+ *
+ * @since 2.0 {@index}
+ */
+public interface PageRenderSubscriber extends HasEnabling {
+
+    /**
+     * Called just before the rendering process starts.
+     *
+     * <p>
+     *     Determines which of the <code>onRenderedXxx</code> callbacks (if any) will next be called:
+     *     <ul>
+     *         <li>if {@link PageType#DOMAIN_OBJECT}, then will call {@link #onRenderedDomainObject(Bookmark)} next</li>
+     *         <li>if {@link PageType#COLLECTION}, then will call {@link #onRenderedCollection(Supplier)} next</li>
+     *         <li>if {@link PageType#VALUE}, then will call {@link #onRenderedValue(Object)} next</li>
+     *     </ul>
+     *     However, if {@link PageType#OTHER}, then <b>NO</b> <code>onRenderedXxx</code> method will be called.
+     * </p>
+     *
+     * <p>
+     *     Also, if any of the pages fail to render (eg due to an authorization exception), then - again -
+     *     <b>NO</b> <code>onRenderedXxx</code> method will be called
+     * </p>
+     *
+     * <p>
+     *     Implementations could use this to start a stopwatch, for example, or to reset caches.
+     * </p>
+     *
+     * @param pageType - determines which of the subsequent <code>onRenderedXxx</code> callbacks (if any) will next be called.
+     */
+    default void onRendering(PageType pageType) {}
+
+
+    /**
+     * Indicates that the domain object represented by the {@link Bookmark} has been rendered.
+     *
+     * @param bookmark - representation of the domain object that has been rendered.
+     */
+    default void onRenderedDomainObject(Bookmark bookmark) {}
+
+    /**
+     * Indicates that a standalone list of domain objects (each represented by a {@link Bookmark} has been rendered.
+     *
+     * @param bookmarkSupplier - a supplier representations of the collection of domain objects that have been rendered.  The level of indirection is for performance (in case no implementation is interested)
+     */
+    default void onRenderedCollection(Supplier<List<Bookmark>> bookmarkSupplier) {}
+
+    /**
+     * Indicates that a value has been rendered.
+     *
+     * @param value - the actual value that has been rendered.
+     */
+    default void onRenderedValue(Object value) {}
+
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageType.java
similarity index 68%
copy from viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java
copy to api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageType.java
index 8db424a4be..8cf97de942 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java
+++ b/api/applib/src/main/java/org/apache/causeway/applib/services/publishing/spi/PageType.java
@@ -16,26 +16,26 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package org.apache.causeway.viewer.wicket.model.models;
+package org.apache.causeway.applib.services.publishing.spi;
 
 /**
  * Enumerates the different types of pages that can be rendered.
- *
- * <p>
- * Is used by {@link PageClassRegistry} to lookup the concrete page to render
- * different types of pages. This allows the large-scale structure of page
- * layout (eg headers, footers) to be altered.
  */
 public enum PageType {
-    SIGN_IN,
-    SIGN_UP,
-    SIGN_UP_VERIFY,
-    PASSWORD_RESET,
-    HOME,
-    HOME_AFTER_PAGETIMEOUT,
-    ABOUT,
-    ENTITY,
-    STANDALONE_COLLECTION,
+    /**
+     * Either a view model or an entity.
+     */
+    DOMAIN_OBJECT,
+    /**
+     * A collection of view models or entities.
+     */
+    COLLECTION,
+    /**
+     * A single value
+     */
     VALUE,
-    VOID_RETURN;
+    /**
+     * Anything else; might include void, or sign in pages.
+     */
+    OTHER;
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java
index 8db424a4be..b5d9797581 100644
--- a/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java
+++ b/viewers/wicket/model/src/main/java/org/apache/causeway/viewer/wicket/model/models/PageType.java
@@ -22,7 +22,7 @@ package org.apache.causeway.viewer.wicket.model.models;
  * Enumerates the different types of pages that can be rendered.
  *
  * <p>
- * Is used by {@link PageClassRegistry} to lookup the concrete page to render
+ * Is used by <code>PagePageClassRegistry</code> to lookup the concrete page to render
  * different types of pages. This allows the large-scale structure of page
  * layout (eg headers, footers) to be altered.
  */
@@ -38,4 +38,17 @@ public enum PageType {
     STANDALONE_COLLECTION,
     VALUE,
     VOID_RETURN;
+
+    public org.apache.causeway.applib.services.publishing.spi.PageType asApplibPageType() {
+        switch (this) {
+            case ENTITY:
+                return org.apache.causeway.applib.services.publishing.spi.PageType.DOMAIN_OBJECT;
+            case STANDALONE_COLLECTION:
+                return org.apache.causeway.applib.services.publishing.spi.PageType.COLLECTION;
+            case VALUE:
+                return org.apache.causeway.applib.services.publishing.spi.PageType.VALUE;
+            default:
+                return org.apache.causeway.applib.services.publishing.spi.PageType.OTHER;
+        }
+    }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageAbstract.java
index 1e9f356045..2241ec2a13 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageAbstract.java
@@ -22,6 +22,8 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 
+import org.apache.causeway.applib.services.publishing.spi.PageRenderSubscriber;
+import org.apache.causeway.commons.collections.Can;
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
 import org.apache.wicket.Page;
@@ -477,16 +479,24 @@ implements ActionPromptProvider {
 
     @Override
     public void renderPage() {
+        val enabledObjectRenderSubscribers = getServiceRegistry().select(PageRenderSubscriber.class)
+                .filter(PageRenderSubscriber::isEnabled);
+        enabledObjectRenderSubscribers
+                .forEach(subscriber -> {
+            subscriber.onRendering(getPageClassRegistry().getPageType(this).asApplibPageType());
+        });
         if(XrayUi.isXrayEnabled()){
             _Debug.log("about to render %s ..", this.getClass().getSimpleName());
             val stopWatch = _Timing.now();
             onNewRequestCycle();
             super.renderPage();
+            onRendered(enabledObjectRenderSubscribers);
             stopWatch.stop();
             _Debug.log(".. rendering took %s", stopWatch.toString());
         } else {
             onNewRequestCycle();
             super.renderPage();
+            onRendered(enabledObjectRenderSubscribers);
         }
     }
 
@@ -499,4 +509,12 @@ implements ActionPromptProvider {
         // implemented only by EntityPage
     }
 
+    /**
+     * Hook to call {@link PageRenderSubscriber} implementations
+     *
+     * @param enabledObjectRenderSubscribers  - those {@link PageRenderSubscriber}s that are {@link PageRenderSubscriber#isEnabled() enabled}
+     */
+    public void onRendered(Can<PageRenderSubscriber> enabledObjectRenderSubscribers) {
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageClassRegistry.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageClassRegistry.java
index 209985da27..eab9e80378 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageClassRegistry.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/PageClassRegistry.java
@@ -34,5 +34,7 @@ public interface PageClassRegistry extends Serializable {
      * registry.
      */
     public Class<? extends Page> getPageClass(PageType pageType);
+    public PageType getPageType(Class<? extends Page> pageClass);
+    public PageType getPageType(PageAbstract page);
 
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/entity/EntityPage.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/entity/EntityPage.java
index 7315353908..461eef51b2 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/entity/EntityPage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/entity/EntityPage.java
@@ -18,6 +18,8 @@
  */
 package org.apache.causeway.viewer.wicket.ui.pages.entity;
 
+import org.apache.causeway.applib.services.publishing.spi.PageRenderSubscriber;
+import org.apache.causeway.commons.collections.Can;
 import org.apache.wicket.Application;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
@@ -214,6 +216,16 @@ public class EntityPage extends PageAbstract {
                         .orElseThrow());
     }
 
+    @Override
+    public void onRendered(Can<PageRenderSubscriber> objectRenderSubscribers) {
+        final ManagedObject objectAdapter;
+        objectAdapter = model.getObject();
+        val bookmarkIfAny = objectAdapter.getBookmark();
+
+        objectRenderSubscribers
+                .forEach(objectRenderSubscriber -> objectRenderSubscriber.onRenderedDomainObject(bookmarkIfAny.get()));
+    }
+
     // -- HELPER
 
     private void addBreadcrumbIfShown(final UiObjectWkt entityModel) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
index d1efe3c3df..1c4f1ff612 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/standalonecollection/StandaloneCollectionPage.java
@@ -18,6 +18,16 @@
  */
 package org.apache.causeway.viewer.wicket.ui.pages.standalonecollection;
 
+import lombok.val;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.applib.services.publishing.spi.PageRenderSubscriber;
+import org.apache.causeway.commons.collections.Can;
+import org.apache.causeway.commons.internal.base._Lazy;
 import org.apache.wicket.Component;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 
@@ -35,6 +45,8 @@ public class StandaloneCollectionPage extends PageAbstract {
 
     private static final long serialVersionUID = 1L;
 
+    private final EntityCollectionModelStandalone collectionModel;
+
     /**
      * For use with {@link Component#setResponsePage(org.apache.wicket.request.component.IRequestablePage)}
      */
@@ -42,9 +54,26 @@ public class StandaloneCollectionPage extends PageAbstract {
         super(PageParameterUtils.newPageParameters(),
                 collectionModel.getName(),
                 UiComponentType.STANDALONE_COLLECTION);
+        this.collectionModel = collectionModel;
 
         addChildComponents(themeDiv, collectionModel);
         addBookmarkedPages(themeDiv);
     }
 
+    @Override
+    public void onRendered(Can<PageRenderSubscriber> objectRenderSubscribers) {
+
+        Supplier<List<Bookmark>> bookmarkSupplier = _Lazy.threadSafe(
+                () -> {
+                    val bookmarks = new ArrayList<Bookmark>();
+                    collectionModel.getObject().getDataElements().getValue().forEach(x -> {
+                        x.getBookmark().ifPresent(bookmarks::add);
+                    });
+                    return bookmarks;
+                });
+
+        objectRenderSubscribers
+                .forEach(subscriber -> subscriber.onRenderedCollection(bookmarkSupplier));
+    }
+
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/value/ValuePage.java b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/value/ValuePage.java
index 967c3dde7a..fb8d88a859 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/value/ValuePage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/causeway/viewer/wicket/ui/pages/value/ValuePage.java
@@ -18,6 +18,8 @@
  */
 package org.apache.causeway.viewer.wicket.ui.pages.value;
 
+import org.apache.causeway.applib.services.publishing.spi.PageRenderSubscriber;
+import org.apache.causeway.commons.collections.Can;
 import org.apache.wicket.Component;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 
@@ -38,6 +40,7 @@ public class ValuePage extends PageAbstract {
     private static final long serialVersionUID = 1L;
 
     private static final String ID_ACTION_NAME = "actionName";
+    private final ValueModel valueModel;
 
     /**
      * For use with {@link Component#setResponsePage(org.apache.wicket.request.component.IRequestablePage)}
@@ -49,6 +52,7 @@ public class ValuePage extends PageAbstract {
 
     private ValuePage(final ValueModel valueModel, final String actionName) {
         super(PageParameterUtils.newPageParameters(), actionName, UiComponentType.VALUE);
+        this.valueModel = valueModel;
 
         Wkt.labelAdd(themeDiv, ID_ACTION_NAME, actionName);
 
@@ -64,4 +68,10 @@ public class ValuePage extends PageAbstract {
         return "Results"; // fallback, probably not required because hint should always exist on the model.
     }
 
+    @Override
+    public void onRendered(Can<PageRenderSubscriber> enabledObjectRenderSubscribers) {
+        enabledObjectRenderSubscribers.forEach(objectRenderSubscriber -> {
+            objectRenderSubscriber.onRenderedValue(valueModel.getObject().getPojo());
+        });
+    }
 }
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/registries/pages/PageClassRegistryDefault.java b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/registries/pages/PageClassRegistryDefault.java
index 99a6b8fb93..bd75963214 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/registries/pages/PageClassRegistryDefault.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/causeway/viewer/wicket/viewer/registries/pages/PageClassRegistryDefault.java
@@ -25,6 +25,7 @@ import javax.annotation.Priority;
 import javax.inject.Inject;
 import javax.inject.Named;
 
+import org.apache.causeway.viewer.wicket.ui.pages.PageAbstract;
 import org.apache.wicket.Page;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.stereotype.Service;
@@ -49,7 +50,8 @@ public class PageClassRegistryDefault implements PageClassRegistry, PageClassReg
     private static final long serialVersionUID = 1L;
 
     private final PageClassList pageClassList; // serializable
-    private final Map<PageType, Class<? extends Page>> pagesByType = _Maps.newHashMap();
+    private final Map<PageType, Class<? extends Page>> pageClassByType = _Maps.newHashMap();
+    private final Map<Class<? extends Page>, PageType> typeByPageClass = _Maps.newHashMap();
 
     @Inject
     public PageClassRegistryDefault(PageClassList pageClassList) {
@@ -70,21 +72,26 @@ public class PageClassRegistryDefault implements PageClassRegistry, PageClassReg
         }
     }
 
-    // /////////////////////////////////////////////////////////
-    // API
-    // /////////////////////////////////////////////////////////
 
     @Override
     public final Class<? extends Page> getPageClass(final PageType pageType) {
-        return pagesByType.get(pageType);
+        return pageClassByType.get(pageType);
+    }
+
+    @Override
+    public PageType getPageType(Class<? extends Page> pageClass) {
+        return typeByPageClass.get(pageClass);
+    }
+
+    @Override
+    public PageType getPageType(PageAbstract page) {
+        return getPageType(page.getClass());
     }
 
-    // /////////////////////////////////////////////////////////
-    // API
-    // /////////////////////////////////////////////////////////
 
     @Override
     public final void registerPage(final PageType pageType, final Class<? extends Page> pageClass) {
-        pagesByType.put(pageType, pageClass);
+        pageClassByType.put(pageType, pageClass);
+        typeByPageClass.put(pageClass, pageType);
     }
 }