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

benweidig pushed a commit to branch TAP5-2838
in repository https://gitbox.apache.org/repos/asf/tapestry-5.git

commit 25f24b40e3758f2b15d4a03966e856e354f44820
Author: Ben Weidig <[email protected]>
AuthorDate: Sat Aug 8 12:55:49 2026 +0200

    TAP5-2838: Add Pipelines page to T5Dashboard
---
 .../apache/tapestry5/corelib/pages/Pipelines.java  | 73 ++++++++++++++++++++++
 .../apache/tapestry5/modules/DashboardModule.java  |  1 +
 .../apache/tapestry5/corelib/pages/Pipelines.tml   | 60 ++++++++++++++++++
 .../integration/app1/CoreBehaviorsTests.java       | 16 +++++
 4 files changed, 150 insertions(+)

diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/Pipelines.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/Pipelines.java
new file mode 100644
index 000000000..bb2ccfa5b
--- /dev/null
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/corelib/pages/Pipelines.java
@@ -0,0 +1,73 @@
+// Copyright 2026 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.corelib.pages;
+
+import java.util.List;
+
+import org.apache.tapestry5.annotations.Cached;
+import org.apache.tapestry5.annotations.Property;
+import org.apache.tapestry5.annotations.UnknownActivationContextCheck;
+import org.apache.tapestry5.annotations.WhitelistAccessOnly;
+import org.apache.tapestry5.http.TapestryHttpSymbolConstants;
+import org.apache.tapestry5.ioc.annotations.Inject;
+import org.apache.tapestry5.ioc.annotations.Symbol;
+import org.apache.tapestry5.ioc.services.AssembledPipeline;
+import org.apache.tapestry5.ioc.services.PipelineBuilder;
+
+/**
+ * Page used to see the pipelines assembled by the {@link PipelineBuilder}: 
which filters are in each pipeline, and
+ * in which order they are invoked.
+ *
+ * A pipeline is assembled when the service it implements is first realized, 
so this page shows more as the
+ * application runs.
+ *
+ * @since 5.10
+ */
+@UnknownActivationContextCheck(false)
+@WhitelistAccessOnly
+public class Pipelines
+{
+    @Inject
+    private PipelineBuilder pipelineBuilder;
+
+    @Property
+    @Inject
+    @Symbol(TapestryHttpSymbolConstants.PRODUCTION_MODE)
+    private boolean productionMode;
+
+    @Property
+    private AssembledPipeline pipeline;
+
+    @Property
+    private int pipelineIndex;
+
+    @Property
+    private String filter;
+
+    @Cached
+    public List<AssembledPipeline> getPipelines()
+    {
+        return pipelineBuilder.getAssembledPipelines();
+    }
+
+    /**
+     * Identifies the panel of the current pipeline, for the links at the top 
of the page. The index is used rather
+     * than the service interface, since the same interface may be the basis 
of more than one pipeline.
+     */
+    public String getPipelineClientId()
+    {
+        return "pipeline-" + pipelineIndex;
+    }
+}
diff --git 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
index c2938bf1e..01de67160 100644
--- 
a/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
+++ 
b/tapestry-core/src/main/java/org/apache/tapestry5/modules/DashboardModule.java
@@ -40,6 +40,7 @@ public class DashboardModule
     {
         configuration.add("Pages", new DashboardTab("Pages", 
"core/PageCatalog"));
         configuration.add("Services", new DashboardTab("Services", 
"core/ServiceStatus"));
+        configuration.add("Pipelines", new DashboardTab("Pipelines", 
"core/Pipelines"));
         configuration.add("Libraries", new DashboardTab("ComponentLibraries", 
"core/ComponentLibraries"));
         configuration.add("PageDependencyGraph", new 
DashboardTab("PageDependencyGraph", "core/PageDependencyGraph"));
         if (!productionMode && multipleClassLoaders)
diff --git 
a/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/Pipelines.tml
 
b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/Pipelines.tml
new file mode 100644
index 000000000..555bbbb2b
--- /dev/null
+++ 
b/tapestry-core/src/main/resources/org/apache/tapestry5/corelib/pages/Pipelines.tml
@@ -0,0 +1,60 @@
+<t:block id="content"
+         xmlns:t="http://tapestry.apache.org/schema/tapestry_5_3.xsd"; 
xmlns:p="tapestry:parameter">
+
+    <t:unless test="productionMode">
+        <p:then>
+            <p>
+                <strong>${pipelines.size()}</strong> pipelines assembled so 
far.
+                A pipeline is assembled when the service it implements is 
first realized,
+                so this list grows as the application runs.
+            </p>
+            <ul class="list-group">
+                <li class="list-group-item" t:type="Loop" t:source="pipelines" 
t:value="pipeline"
+                    index="pipelineIndex">
+                    <span class="badge">${pipeline.filters.size()}</span>
+                    <a href="#${pipelineClientId}">
+                        <code>${pipeline.serviceInterface.simpleName}</code>
+                    </a>
+                </li>
+            </ul>
+
+            <div class="panel panel-default" t:type="Loop" 
t:source="pipelines" t:value="pipeline"
+                 index="pipelineIndex" id="${pipelineClientId}">
+
+                <div class="panel-heading">
+                    <code>${pipeline.serviceInterface.name}</code>
+                </div>
+
+                <div class="panel-body">
+                    <p>
+                        Filtered by: 
<code>${pipeline.filterInterface.name}</code>
+                    </p>
+
+                    <t:if test="pipeline.filters.empty">
+                        <p:then>
+                            <p class="text-muted">No filters contributed; the 
pipeline is just its terminator.</p>
+                        </p:then>
+                        <p:else>
+                            <ol>
+                                <li t:type="Loop" t:source="pipeline.filters" 
t:value="filter">
+                                    <code>${filter}</code>
+                                </li>
+                            </ol>
+                        </p:else>
+                    </t:if>
+
+                    <p>
+                        Terminator:
+                        <code>${pipeline.terminator}</code>
+                    </p>
+                </div>
+            </div>
+        </p:then>
+        <p:else>
+            <p>
+                <em>The filters of each pipeline are only shown in development 
mode.</em>
+            </p>
+        </p:else>
+    </t:unless>
+
+</t:block>
diff --git 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
index a7a538510..b46c1c0e9 100644
--- 
a/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
+++ 
b/tapestry-core/src/test/java/org/apache/tapestry5/integration/app1/CoreBehaviorsTests.java
@@ -14,6 +14,7 @@ package org.apache.tapestry5.integration.app1;
 
 import org.apache.tapestry5.corelib.mixins.RenderDisabled;
 import org.apache.tapestry5.integration.app1.pages.RenderErrorDemo;
+import org.apache.tapestry5.services.ComponentRequestHandler;
 import org.openqa.selenium.By;
 import org.openqa.selenium.support.ui.ExpectedConditions;
 import org.testng.annotations.Test;
@@ -743,6 +744,21 @@ public class CoreBehaviorsTests extends App1TestCase
         assertTextPresent("services defined in the IoC Registry");
     }
 
+    /**
+     * This basically checks that the pipelines page does not error.
+     */
+    @Test
+    public void pipelines()
+    {
+        open(getBaseURL() + "t5dashboard/pipelines");
+
+        assertTextPresent("pipelines assembled so far");
+
+        // Every request goes through this pipeline, so it has certainly been 
assembled by now.
+
+        assertTextPresent(ComponentRequestHandler.class.getName());
+    }
+
     /**
      * Tests TAPESTRY-1934.
      */

Reply via email to