You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/12/08 17:54:49 UTC

[isis] branch master updated: ISIS-2911: Xray: different icons for different event types

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 59587f5  ISIS-2911: Xray: different icons for different event types
59587f5 is described below

commit 59587f5d559f930d7d3138a0e474edc8ed633dc5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Dec 8 18:54:37 2021 +0100

    ISIS-2911: Xray: different icons for different event types
---
 .../apache/isis/commons/internal/debug/_Debug.java |  45 +---------
 .../isis/commons/internal/debug/_IconResource.java |  35 ++++++++
 .../apache/isis/commons/internal/debug/_Xray.java  |   3 +-
 .../debug/{_Debug.java => _XrayEvent.java}         |  87 +++++++-----------
 .../commons/internal/debug/xray/XrayDataModel.java |   5 +-
 commons/src/main/resources/xray/evnt.png           | Bin 0 -> 673 bytes
 commons/src/main/resources/xray/ia-close.png       | Bin 0 -> 460 bytes
 commons/src/main/resources/xray/ia-open.png        | Bin 0 -> 521 bytes
 commons/src/main/resources/xray/tx.png             | Bin 0 -> 445 bytes
 ...ableObjectFacetForXmlRootElementAnnotation.java |   2 +-
 .../identify/ObjectBookmarker_builtinHandlers.java |   2 +-
 .../org/apache/isis/core/runtime/events/_Xray.java |   6 +-
 .../command/SchemaValueMarshallerDefault.java      |   2 +-
 .../isis/core/runtimeservices/session/_Xray.java   |   7 +-
 .../metamodel/facets/entity/JdoEntityFacet.java    |   2 +-
 .../jdo/integration/changetracking/_Xray.java      |   4 +-
 .../isis/testdomain/jdo/entities/JdoBook.java      |   2 +-
 .../viewer/wicket/model/models/ScalarModel.java    |  11 +++
 .../models/interaction/BookmarkedObjectWkt.java    |  11 +--
 .../interaction/_ViewmodelEntityReattacher.java    |  98 +++++++++++++++++++++
 .../widgets/linkandlabel/ActionLink.java           |   2 +-
 .../viewer/wicket/ui/pages/entity/EntityPage.java  |  39 +++-----
 .../wicket/ui/panels/FormExecutorDefault.java      |  21 +++--
 23 files changed, 231 insertions(+), 153 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java b/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java
index 43e5616..861df11 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java
@@ -20,12 +20,9 @@ package org.apache.isis.commons.internal.debug;
 
 import java.util.stream.Collectors;
 
-import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.handler.ChainOfResponsibility;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.debug.xray.XrayUi;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import lombok.val;
 import lombok.experimental.UtilityClass;
@@ -65,30 +62,11 @@ public class _Debug {
         dump(x, 0);
     }
 
+    /**
+     * General purpose log entry.
+     */
     public void log(final String format, final Object...args) {
-        log(1, format, args);
-    }
-
-    public void log(final int depth, final String format, final Object...args) {
-        val stackTrace = _Exceptions.streamStackTrace()
-                .skip(3)
-                .filter(_Debug::accept)
-                .collect(Can.toCan());
-                //.reverse();
-
-        val logMessage = String.format(format, args);
-
-        _Xray.recordDebugLogEvent(logMessage, stackTrace);
-
-        val context = String.format("%s|| %s",
-                Thread.currentThread().getName(),
-                stackTrace.stream()
-                .limit(depth)
-                .map(_Debug::stringify)
-                .collect(Collectors.joining(" <- ")));
-
-        System.err.println(context);
-        System.err.println("| " + logMessage);
+        _XrayEvent.record(1, _IconResource.LOG, format, args);
     }
 
     // -- HELPER
@@ -118,19 +96,4 @@ public class _Debug {
 
     }
 
-    private boolean accept(final StackTraceElement se) {
-        return se.getLineNumber()>1
-                && !se.getClassName().equals(_Debug.class.getName())
-                && !se.getClassName().contains("_Xray") // suppress _Xray local helpers
-                && !se.getClassName().startsWith(ChainOfResponsibility.class.getName())
-                && !se.getClassName().startsWith("java.util.stream") // suppress Stream processing details
-                && !se.getClassName().startsWith("org.junit") // suppress Junit processing details
-                && !se.getClassName().startsWith("org.eclipse.jdt.internal") // suppress IDE processing details
-                ;
-    }
-
-    private String stringify(final StackTraceElement se) {
-        return _Exceptions.abbreviate(se.toString());
-    }
-
 }
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/debug/_IconResource.java b/commons/src/main/java/org/apache/isis/commons/internal/debug/_IconResource.java
new file mode 100644
index 0000000..0c6eeef
--- /dev/null
+++ b/commons/src/main/java/org/apache/isis/commons/internal/debug/_IconResource.java
@@ -0,0 +1,35 @@
+/*
+ *  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.commons.internal.debug;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+@Getter
+@RequiredArgsConstructor
+enum _IconResource {
+    EVENT               ("/xray/evnt.png"),
+    INTERACTION_OPEN    ("/xray/ia-open.png"),
+    INTERACTION_CLOSE   ("/xray/ia-close.png"),
+    LOG                 ("/xray/log.png"),
+    TRANSACTION         ("/xray/tx.png");
+
+    private final String resourcePath;
+
+}
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Xray.java b/commons/src/main/java/org/apache/isis/commons/internal/debug/_Xray.java
index a64688d..1bde01e 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Xray.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/debug/_Xray.java
@@ -34,6 +34,7 @@ import lombok.experimental.UtilityClass;
 final class _Xray {
 
     void recordDebugLogEvent(
+            final _IconResource icon,
             final String logMessage,
             final Can<StackTraceElement> stackTrace) {
 
@@ -49,7 +50,7 @@ final class _Xray {
 
             val logModel = model.addDataNode(parentNode,
                     new XrayDataModel.LogEntry(
-                            "debug-log", timeStamp,
+                            "debug-log", timeStamp, icon.getResourcePath(),
                             _Strings.ellipsifyAtEnd(logMessage, 80, "..."),
                             logMessage,
                             Stickiness.CAN_DELETE_NODE));
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java b/commons/src/main/java/org/apache/isis/commons/internal/debug/_XrayEvent.java
similarity index 61%
copy from commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java
copy to commons/src/main/java/org/apache/isis/commons/internal/debug/_XrayEvent.java
index 43e5616..fa8063a 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/debug/_Debug.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/debug/_XrayEvent.java
@@ -22,8 +22,6 @@ import java.util.stream.Collectors;
 
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.handler.ChainOfResponsibility;
-import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 
@@ -33,7 +31,7 @@ import lombok.experimental.UtilityClass;
 /**
  * <h1>- internal use only -</h1>
  * <p>
- * Utility for adding temporary debug code,
+ * Utility for adding event debug code,
  * that needs to be removed later. Also integrates with {@link XrayUi}, if enabled.
  * </p>
  * <p>
@@ -43,84 +41,67 @@ import lombok.experimental.UtilityClass;
  * @since 2.0
  */
 @UtilityClass
-public class _Debug {
+public class _XrayEvent {
 
-    public void onCondition(
-            final boolean condition,
-            final Runnable runnable) {
-
-        if(condition) {
-            runnable.run();
-        }
+    /**
+     * General purpose event entry.
+     */
+    public void event(final String format, final Object...args) {
+        record(1, _IconResource.EVENT, format, args);
     }
 
-    public void onClassSimpleNameMatch(
-            final Class<?> correspondingClass,
-            final String classSimpleName,
-            final Runnable runnable) {
-        onCondition(correspondingClass.getSimpleName().equals(classSimpleName), runnable);
+    /**
+     * Interaction open event entry.
+     */
+    public void interactionOpen(final String format, final Object...args) {
+        record(1, _IconResource.INTERACTION_OPEN, format, args);
     }
 
-    public void dump(final Object x) {
-        dump(x, 0);
+    /**
+     * Interaction close event entry.
+     */
+    public void interactionClose(final String format, final Object...args) {
+        record(1, _IconResource.INTERACTION_CLOSE, format, args);
     }
 
-    public void log(final String format, final Object...args) {
-        log(1, format, args);
+    /**
+     * General purpose transaction event entry.
+     */
+    public void transaction(final String format, final Object...args) {
+        record(1, _IconResource.TRANSACTION, format, args);
     }
 
-    public void log(final int depth, final String format, final Object...args) {
+    // -- HELPER
+
+    /**
+     * General purpose event log entry.
+     * @param depthLimit - max call stack depth printed out to console
+     */
+    void record(final int depthLimit, final _IconResource icon, final String format, final Object...args) {
         val stackTrace = _Exceptions.streamStackTrace()
                 .skip(3)
-                .filter(_Debug::accept)
+                .filter(_XrayEvent::accept)
                 .collect(Can.toCan());
                 //.reverse();
 
         val logMessage = String.format(format, args);
 
-        _Xray.recordDebugLogEvent(logMessage, stackTrace);
+        _Xray.recordDebugLogEvent(icon, logMessage, stackTrace);
 
         val context = String.format("%s|| %s",
                 Thread.currentThread().getName(),
                 stackTrace.stream()
-                .limit(depth)
-                .map(_Debug::stringify)
+                .limit(depthLimit)
+                .map(_XrayEvent::stringify)
                 .collect(Collectors.joining(" <- ")));
 
         System.err.println(context);
         System.err.println("| " + logMessage);
     }
 
-    // -- HELPER
-
-    private void dump(Object x, final int indent) {
-        if(x instanceof Iterable) {
-            _NullSafe.streamAutodetect(x)
-            .forEach(element->dump(element, indent+1));
-            return;
-        }
-        if(x!=null
-                && x.getClass().isArray()) {
-
-            val array = _NullSafe.streamAutodetect(x)
-            .map(e->""+e)
-            .collect(Collectors.joining(", "));
-
-            x = String.format("[%s]", array);
-        }
-
-        if(indent==0) {
-            System.err.printf("%s%n", x);
-        } else {
-            val suffix = _Strings.padEnd("", indent, '-');
-            System.err.printf("%s %s%n", suffix, x);
-        }
-
-    }
-
     private boolean accept(final StackTraceElement se) {
         return se.getLineNumber()>1
-                && !se.getClassName().equals(_Debug.class.getName())
+                && !se.getClassName().equals(_XrayEvent.class.getName())
                 && !se.getClassName().contains("_Xray") // suppress _Xray local helpers
                 && !se.getClassName().startsWith(ChainOfResponsibility.class.getName())
                 && !se.getClassName().startsWith("java.util.stream") // suppress Stream processing details
diff --git a/commons/src/main/java/org/apache/isis/commons/internal/debug/xray/XrayDataModel.java b/commons/src/main/java/org/apache/isis/commons/internal/debug/xray/XrayDataModel.java
index c5677cd..7fe08a9 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/debug/xray/XrayDataModel.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/debug/xray/XrayDataModel.java
@@ -104,13 +104,12 @@ public abstract class XrayDataModel extends HasIdAndLabel {
 
         private final String id;
         private final LocalDateTime timestamp;
+        @EqualsAndHashCode.Exclude
+        private final String iconResource;
         private final String label;
         private final String logMessage;
         private final @NonNull Stickiness stickiness;
 
-        @EqualsAndHashCode.Exclude
-        private final String iconResource = "/xray/log.png";
-
         @Override
         public void render(final JScrollPane panel) {
 
diff --git a/commons/src/main/resources/xray/evnt.png b/commons/src/main/resources/xray/evnt.png
new file mode 100644
index 0000000..0a8f2c9
Binary files /dev/null and b/commons/src/main/resources/xray/evnt.png differ
diff --git a/commons/src/main/resources/xray/ia-close.png b/commons/src/main/resources/xray/ia-close.png
new file mode 100644
index 0000000..151bbc6
Binary files /dev/null and b/commons/src/main/resources/xray/ia-close.png differ
diff --git a/commons/src/main/resources/xray/ia-open.png b/commons/src/main/resources/xray/ia-open.png
new file mode 100644
index 0000000..9cfef5e
Binary files /dev/null and b/commons/src/main/resources/xray/ia-open.png differ
diff --git a/commons/src/main/resources/xray/tx.png b/commons/src/main/resources/xray/tx.png
new file mode 100644
index 0000000..d7458d7
Binary files /dev/null and b/commons/src/main/resources/xray/tx.png differ
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
index 75a7e42..83e4b50 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetForXmlRootElementAnnotation.java
@@ -52,7 +52,7 @@ extends RecreatableObjectFacetAbstract {
         final String encoded = getUrlEncodingService().encodeString(xml);
         //FIXME[ISIS-2903] gets called about 4 times per same object, why?
         _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(100, "%s => %s",
+            _Debug.log("%s => %s",
                     super.getMetaModelContext().getInteractionProvider().getInteractionId()
                     .map(UUID::toString)
                     .orElse("no-interaction"),
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker_builtinHandlers.java
index a8d2e93..a8fc328 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker_builtinHandlers.java
@@ -113,7 +113,7 @@ class ObjectBookmarker_builtinHandlers {
                 //entityFacet.persist(spec, entityPojo);
 
                 _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                    _Debug.log(10, "detached entity detected %s", entityPojo);
+                    _Debug.log("detached entity detected %s", entityPojo);
                 });
 
                 throw _Exceptions.illegalArgument(
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/events/_Xray.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/events/_Xray.java
index 4c2876a..7692e2b 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/events/_Xray.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/events/_Xray.java
@@ -20,7 +20,7 @@ package org.apache.isis.core.runtime.events;
 
 import org.apache.isis.applib.services.confview.ConfigurationViewService;
 import org.apache.isis.applib.services.iactnlayer.InteractionLayerTracker;
-import org.apache.isis.commons.internal.debug._Debug;
+import org.apache.isis.commons.internal.debug._XrayEvent;
 import org.apache.isis.commons.internal.debug.xray.XrayDataModel;
 import org.apache.isis.commons.internal.debug.xray.XrayModel.Stickiness;
 import org.apache.isis.commons.internal.debug.xray.XrayUi;
@@ -59,7 +59,7 @@ final class _Xray {
             return;
         }
 
-        _Debug.log(10, txInfo);
+        _XrayEvent.transaction(txInfo);
 
         //val threadId = ThreadMemento.fromCurrentThread();
 
@@ -99,7 +99,7 @@ final class _Xray {
             return;
         }
 
-        _Debug.log(10, txInfo);
+        _XrayEvent.transaction(txInfo);
 
         //val threadId = ThreadMemento.fromCurrentThread();
 
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/SchemaValueMarshallerDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/SchemaValueMarshallerDefault.java
index b9cf262..c3e03c4 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/SchemaValueMarshallerDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/SchemaValueMarshallerDefault.java
@@ -420,7 +420,7 @@ implements SchemaValueMarshaller {
         case REFERENCE: {
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "NULL reference detected %s", pojo);
+                _Debug.log("NULL reference detected %s", pojo);
             });
 
             // at this point, we know the value has no bookmark
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/_Xray.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/_Xray.java
index 58cea06..b05dd23 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/_Xray.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/session/_Xray.java
@@ -21,7 +21,7 @@ package org.apache.isis.core.runtimeservices.session;
 import java.util.Stack;
 
 import org.apache.isis.applib.services.iactnlayer.InteractionLayer;
-import org.apache.isis.commons.internal.debug._Debug;
+import org.apache.isis.commons.internal.debug._XrayEvent;
 import org.apache.isis.commons.internal.debug.xray.XrayDataModel;
 import org.apache.isis.commons.internal.debug.xray.XrayModel.ThreadMemento;
 import org.apache.isis.commons.internal.debug.xray.XrayUi;
@@ -43,7 +43,7 @@ final class _Xray {
         val interactionId = afterEnter.peek().getInteraction().getInteractionId();
         val executionContext = afterEnter.peek().getInteractionContext();
 
-        _Debug.log(10, "open interaction %s", interactionId);
+        _XrayEvent.interactionOpen("open interaction %s", interactionId);
 
         val threadId = ThreadMemento.fromCurrentThread();
 
@@ -99,7 +99,8 @@ final class _Xray {
         val interactionId = beforeClose.peek().getInteraction().getInteractionId();
         val sequenceId = XrayUtil.sequenceId(interactionId);
 
-        _Debug.log(10, "close interaction %s", interactionId);
+
+        _XrayEvent.interactionClose("close interaction %s", interactionId);
 
         XrayUi.updateModel(model->{
 
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
index d21bfc3..c4987ae 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/metamodel/facets/entity/JdoEntityFacet.java
@@ -117,7 +117,7 @@ implements EntityFacet {
         if(primaryKey==null) {
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "detached entity detected %s", pojo);
+                _Debug.log("detached entity detected %s", pojo);
             });
 
             throw _Exceptions.illegalArgument(
diff --git a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/_Xray.java b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/_Xray.java
index 8131c22..34c1632 100644
--- a/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/_Xray.java
+++ b/persistence/jdo/integration/src/main/java/org/apache/isis/persistence/jdo/integration/changetracking/_Xray.java
@@ -23,7 +23,7 @@ import java.awt.Color;
 import javax.inject.Provider;
 
 import org.apache.isis.applib.services.iactn.InteractionProvider;
-import org.apache.isis.commons.internal.debug._Debug;
+import org.apache.isis.commons.internal.debug._XrayEvent;
 import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
@@ -121,7 +121,7 @@ final class _Xray {
                             entity.getSpecification().getLogicalTypeName(),
                             "" + entity.getPojo()));
 
-        _Debug.log(10, enteringLabel);
+        _XrayEvent.event(enteringLabel);
 
         XrayUtil.createSequenceHandle(interactionProviderProvider.get(), "ec-tracker")
         .ifPresent(handle->{
diff --git a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jdo/entities/JdoBook.java b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jdo/entities/JdoBook.java
index b5fa157..2e2de9f 100644
--- a/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jdo/entities/JdoBook.java
+++ b/regressiontests/stable/src/main/java/org/apache/isis/testdomain/jdo/entities/JdoBook.java
@@ -169,7 +169,7 @@ implements IBook {
         this.publisher = publisher;
 
         _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(10, "new JdoBook instance %s", this);
+            _Debug.log("new JdoBook instance %s", this);
         });
 
     }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index c5fe80c..1a9188e 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -27,6 +27,8 @@ import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
+import org.apache.isis.commons.internal.debug._Debug;
+import org.apache.isis.commons.internal.debug.xray.XrayUi;
 import org.apache.isis.core.metamodel.commons.ScalarRepresentation;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
@@ -142,7 +144,16 @@ implements HasRenderingHints, ScalarUiModel, LinksProvider, FormExecutorContext
      */
     @Override
     public final void setObject(final ManagedObject newValue) {
+
+        _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
+            _Debug.log("about to set new value: %s", newValue.getPojo());
+        });
+
         proposedValue().getValue().setValue(newValue);
+
+        _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
+            _Debug.log("new value set to property");
+        });
     }
 
     @Override
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/BookmarkedObjectWkt.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/BookmarkedObjectWkt.java
index 357528a..8cf1eff 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/BookmarkedObjectWkt.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/BookmarkedObjectWkt.java
@@ -147,14 +147,9 @@ extends ModelAbstract<ManagedObject> {
         //EntityUtil.assertAttachedWhenEntity()//guard
         val entityOrViewmodel = super.getObject();
 
-        val spec = entityOrViewmodel.getSpecification();
-
-//XXX experimental
-//        if(spec.getCorrespondingClass()
-//        .getSimpleName().contains("InventoryJaxb")) {
-//            return _JaxbViewmodel.computeIfDetached(entityOrViewmodel, this::reload);
-//        };
-
+        if(_ViewmodelEntityReattacher.appliesTo(entityOrViewmodel)) {
+            return _ViewmodelEntityReattacher.reattach(entityOrViewmodel, this::reload);
+        }
 
         return EntityUtil.computeIfDetached(entityOrViewmodel, this::reload);
     }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/_ViewmodelEntityReattacher.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/_ViewmodelEntityReattacher.java
new file mode 100644
index 0000000..e8375da
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/interaction/_ViewmodelEntityReattacher.java
@@ -0,0 +1,98 @@
+/*
+ *  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.viewer.wicket.model.models.interaction;
+
+import java.util.UUID;
+import java.util.function.UnaryOperator;
+
+import org.apache.isis.commons.internal.debug._Debug;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+
+import lombok.val;
+import lombok.experimental.UtilityClass;
+
+@UtilityClass
+final class _ViewmodelEntityReattacher {
+
+    public static boolean appliesTo(final ManagedObject entityOrViewmodel) {
+        val spec = entityOrViewmodel.getSpecification();
+        //FIXME actually we are interested in whether the viewmodel contains entities or not
+        if(!spec.getCorrespondingClass()
+                .getSimpleName().contains("InventoryJaxb")) {
+            return false;
+        }
+        return false;
+    }
+
+    public static ManagedObject reattach(
+            final ManagedObject viewmodel,
+            final UnaryOperator<ManagedObject> onDetachedEntity) {
+
+        val spec = viewmodel.getSpecification();
+
+        val currentInteractionId = spec.getMetaModelContext().getInteractionProvider().getInteractionId().get();
+
+        // check whether we have done this already for this request-cycle, and if so skip
+        if(canSkip(currentInteractionId)){
+            return viewmodel;
+        }
+
+        _Debug.log("JAXB reattach for %s", currentInteractionId.toString());
+
+//        spec.streamAssociations(MixedIn.EXCLUDED)
+//        .forEach(assoc->{
+//            if(assoc.isOneToOneAssociation()) {
+//                val prop = assoc.get(viewmodel);
+//                EntityUtil.reattach(prop);
+//                System.err.printf("reattached (prop) %s->%s%n", assoc.getId(), prop);
+//            } else {
+//                val coll = assoc.get(viewmodel);
+//                EntityUtil.reattach(coll);
+//                System.err.printf("reattached (coll) %s->%s%n", assoc.getId(), coll);
+//            }
+//        });
+
+        return onDetachedEntity.apply(viewmodel);
+    }
+
+    // -- HELPER
+
+    /**
+     * keeps track of the latest interactionId, for which re-attaching was executed;
+     * such that we do that only once per interaction;
+     * @implNote future work might use the current interaction and set a custom flag active
+     */
+    private static final ThreadLocal<UUID> THREAD_LOCAL =
+            InheritableThreadLocal.withInitial(()->null);
+
+    /**
+     * Returns whether we have done this already for this request-cycle.
+     */
+    private static boolean canSkip(final UUID currentInteractionId) {
+        val previousInteractionId = THREAD_LOCAL.get();
+        if(previousInteractionId!=null
+                && previousInteractionId.equals(currentInteractionId)) {
+            // skip
+            return true;
+        }
+        THREAD_LOCAL.set(currentInteractionId);
+        return false;
+    }
+
+}
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
index 0b75633..2b71ba6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLink.java
@@ -225,7 +225,7 @@ extends IndicatingAjaxLink<ManagedObject> {
         if(outcome.isFailure()) {
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "render the target entity again, outcome: %s", outcome);
+                _Debug.log("render the target entity again, outcome: %s", outcome);
             });
 
             // render the target entity again
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
index dfa75fc..e13d37c 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/entity/EntityPage.java
@@ -19,7 +19,6 @@
 package org.apache.isis.viewer.wicket.ui.pages.entity;
 
 import org.apache.wicket.Application;
-import org.apache.wicket.Component;
 import org.apache.wicket.RestartResponseException;
 import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeInstantiation;
 import org.apache.wicket.markup.head.CssHeaderItem;
@@ -30,9 +29,6 @@ import org.apache.wicket.markup.repeater.RepeatingView;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 import org.apache.wicket.request.resource.CssResourceReference;
 import org.apache.wicket.util.string.Strings;
-import org.apache.wicket.util.visit.IVisit;
-import org.apache.wicket.util.visit.IVisitor;
-import org.apache.wicket.util.visit.Visits;
 
 import org.apache.isis.commons.internal.base._Timing;
 import org.apache.isis.commons.internal.debug._Debug;
@@ -49,7 +45,6 @@ import org.apache.isis.viewer.wicket.model.modelhelpers.WhereAmIHelper;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.util.PageParameterUtils;
 import org.apache.isis.viewer.wicket.ui.components.entity.icontitle.EntityIconAndTitlePanel;
-import org.apache.isis.viewer.wicket.ui.components.scalars.reference.ReferencePanel;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
 import org.apache.isis.viewer.wicket.ui.util.Wkt;
 
@@ -85,7 +80,7 @@ public class EntityPage extends PageAbstract {
             final PageParameters pageParameters) {
 
         _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(10, "new EntityPage from PageParameters %s", pageParameters);
+            _Debug.log("new EntityPage from PageParameters %s", pageParameters);
         });
 
         final String oid = EntityModel.oidStr(pageParameters);
@@ -106,7 +101,7 @@ public class EntityPage extends PageAbstract {
             final ManagedObject adapter) {
 
         _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(10, "new EntityPage from Adapter %s", adapter.getSpecification());
+            _Debug.log("new EntityPage from Adapter %s", adapter.getSpecification());
         });
 
         return new EntityPage(
@@ -133,27 +128,15 @@ public class EntityPage extends PageAbstract {
 
     @Override
     public void renderPage() {
-        _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(10, "about to render EntityPage ..");
-            Visits.visitChildren(this, new IVisitor<Component, Void>(){
-                @Override
-                public void component(final Component component, final IVisit<Void> visit){
-                    if(component.getClass().getSimpleName().equals("ReferencePanel")) {
-                        val scalarModel = ((ReferencePanel)component).getModel();
-                        val value = scalarModel.getObject();
-                        _Debug.log(10, "value = %s", value.getPojo());
-                    }
-                }
-            });
-        });
-
-        val stopWatch = _Timing.now();
-        super.renderPage();
-        stopWatch.stop();
-
-        _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-            _Debug.log(10, ".. rendering took %s", stopWatch.toString());
-        });
+        if(XrayUi.isXrayEnabled()){
+            _Debug.log("about to render EntityPage ..");
+            val stopWatch = _Timing.now();
+            super.renderPage();
+            stopWatch.stop();
+            _Debug.log(".. rendering took %s", stopWatch.toString());
+        } else {
+            super.renderPage();
+        }
     }
 
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index f40772a..eba1387 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -102,13 +102,12 @@ implements FormExecutor {
             }
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-
                 final String whatIsExecuted = actionOrPropertyModel
                 .fold(
                         act->act.getFriendlyName(),
                         prop->prop.getFriendlyName());
 
-                _Debug.log(10, "execute %s ...", whatIsExecuted);
+                _Debug.log("execute %s ...", whatIsExecuted);
             });
 
             //
@@ -124,10 +123,21 @@ implements FormExecutor {
             //
             // (The DB exception might actually be thrown by the flush() that follows.
             //
+            //XXX triggers BookmarkedObjectWkt.getObjectAndReAttach() down the call-stack
             val resultAdapter = actionOrPropertyModel.fold(
                     act->act.executeActionAndReturnResult(),
                     prop->prop.applyValueThenReturnOwner());
 
+            _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
+
+                final String whatIsExecuted = actionOrPropertyModel
+                .fold(
+                        act->act.getFriendlyName(),
+                        prop->prop.getFriendlyName());
+
+                _Debug.log("resultAdapter created for %s", whatIsExecuted);
+            });
+
             // if we are in a nested dialog/form, that supports an action parameter,
             // the result must be fed back into the calling dialog's/form's parameter
             // negotiation model (instead of redirecting to a new page)
@@ -144,9 +154,10 @@ implements FormExecutor {
             }
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "interpret result ...");
+                _Debug.log("interpret result ...");
             });
 
+            //XXX triggers ManagedObject.getBookmarkRefreshed()
             val resultResponse = actionOrPropertyModel.fold(
                     act->ActionResultResponseType
                             .determineAndInterpretResult(act, ajaxTarget, resultAdapter, act.snapshotArgs()),
@@ -154,7 +165,7 @@ implements FormExecutor {
                             .toEntityPage(resultAdapter));
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "handle result ...");
+                _Debug.log("handle result ...");
             });
 
             // redirect using associated strategy
@@ -163,7 +174,7 @@ implements FormExecutor {
                 .handleResults(getCommonContext(), resultResponse);
 
             _Debug.onCondition(XrayUi.isXrayEnabled(), ()->{
-                _Debug.log(10, "... return");
+                _Debug.log("... return");
             });
 
             return FormExecutionOutcome.SUCCESS_AND_REDIRECED_TO_RESULT_PAGE; // success (valid args), allow redirect