This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/struts-site.git
The following commit(s) were added to refs/heads/asf-site by this push:
new 219c96fbaa Automatic Site Publish by Buildbot
219c96fbaa is described below
commit 219c96fbaa643f650217b38bc73c413230785693
Author: buildbot <[email protected]>
AuthorDate: Sun Oct 11 14:25:48 2026 +0000
Automatic Site Publish by Buildbot
---
output/core-developers/constant-configuration.html | 3 +
output/core-developers/default-properties.html | 3 +
output/core-developers/package-configuration.html | 126 ++++++++++++++++
output/dtds/struts-6.5.dtd | 158 ++++++++++++++++++++
output/dtds/struts-7.5.dtd | 164 +++++++++++++++++++++
output/plugins/plugins-architecture.html | 6 +
6 files changed, 460 insertions(+)
diff --git a/output/core-developers/constant-configuration.html
b/output/core-developers/constant-configuration.html
index b8daa7ee39..cf3cc0c30e 100644
--- a/output/core-developers/constant-configuration.html
+++ b/output/core-developers/constant-configuration.html
@@ -205,6 +205,9 @@ for subsequent files to override previous ones:</p>
<p>In the <a href="web-xml">web.xml</a> file, any FilterDispatcher
initialization parameters are loaded as constants.</p>
+<p>Since Struts 7.5.0 a package can override selected constants for its own
actions, see
+<a href="package-configuration#scoped-constants">Scoped constants</a>.</p>
+
<h3 id="value-substitution">Value substitution</h3>
<p>Since Apache Struts 2.5.6 it is possible to use value substitution when
defining <code class="language-plaintext highlighter-rouge">constant</code>s in
<code class="language-plaintext highlighter-rouge">struts.xml</code> file.
diff --git a/output/core-developers/default-properties.html
b/output/core-developers/default-properties.html
index f650141efb..d2a2676d44 100644
--- a/output/core-developers/default-properties.html
+++ b/output/core-developers/default-properties.html
@@ -502,6 +502,9 @@ struts.proxy.cacheFactory=struts
### Specifies the ProxyService implementation class.
struts.proxyService=struts
+### Name of the ScopedConstantProvider bean resolving package-scoped constants
(since 7.5.0)
+struts.scopedConstantProvider=struts
+
### Indicates if Dispatcher should handle unexpected exceptions by calling
sendError()
### or simply rethrow it as a ServletException to allow future processing by
other frameworks like Spring Security
struts.handle.exception=true
diff --git a/output/core-developers/package-configuration.html
b/output/core-developers/package-configuration.html
index 1d7d80b358..a77481d8c4 100644
--- a/output/core-developers/package-configuration.html
+++ b/output/core-developers/package-configuration.html
@@ -255,6 +255,132 @@ by an “extends” should be defined <em>above</em> the
package which extends
<span class="nt"></struts></span>
</code></pre></div></div>
+<h2 id="scoped-constants">Scoped constants</h2>
+
+<p>Since Struts 7.5.0 a package can override selected <a
href="constant-configuration">constants</a> for its own actions with
+the <code class="language-plaintext
highlighter-rouge"><scoped-constant></code> element. Packages that <code
class="language-plaintext highlighter-rouge">extends</code> it inherit the
override, and an override declared in
+the child package wins. When a package extends several packages (<code
class="language-plaintext highlighter-rouge">extends="a, b"</code>) and they
override the same
+constant, the first listed package wins, the same rule as for result types.</p>
+
+<p>Packages created by the <a href="../plugins/convention/">Convention
plugin</a> have no <code class="language-plaintext
highlighter-rouge"><scoped-constant></code> of their own.
+They only get overrides from their parent package, set with <code
class="language-plaintext highlighter-rouge">@ParentPackage</code> or
+<code class="language-plaintext
highlighter-rouge">struts.convention.default.parent.package</code>.</p>
+
+<p>The element requires the <a
href="../dtds/struts-7.5.dtd">struts-7.5.dtd</a> and must come before any other
child of
+<code class="language-plaintext highlighter-rouge"><package></code>:</p>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="cp"><!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "https://struts.apache.org/dtds/struts-7.5.dtd"></span>
+<span class="nt"><struts></span>
+ <span class="nt"><package</span> <span class="na">name=</span><span
class="s">"admin"</span> <span class="na">extends=</span><span
class="s">"struts-default"</span> <span class="na">namespace=</span><span
class="s">"/admin"</span><span class="nt">></span>
+ <span class="nt"><scoped-constant</span> <span
class="na">name=</span><span class="s">"some.scopable.constant"</span> <span
class="na">value=</span><span class="s">"x"</span><span class="nt">/></span>
+ ...
+ <span class="nt"></package></span>
+<span class="nt"></struts></span>
+</code></pre></div></div>
+
+<table>
+ <thead>
+ <tr>
+ <th>Attribute</th>
+ <th>Required</th>
+ <th>Description</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>name</td>
+ <td><strong>yes</strong></td>
+ <td>the name of a scopable constant</td>
+ </tr>
+ <tr>
+ <td>value</td>
+ <td><strong>yes</strong></td>
+ <td>the value used for actions of the package</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>Scoped constants are not a way to override an arbitrary constant per
package. Constants are injected into
+framework components once, at startup, so a package value only takes effect
where a component explicitly reads
+it per request. Such a component declares the constants it reads as
<em>scopable</em>, and only those can appear
+in <code class="language-plaintext
highlighter-rouge"><scoped-constant></code>.</p>
+
+<p class="alert alert-warning">Struts core does not declare any constant as
scopable yet. A <code class="language-plaintext
highlighter-rouge"><scoped-constant></code> only works with a constant
+declared scopable by a plugin or by your own application code.</p>
+
+<p>The configuration is validated at startup, and loading fails when:</p>
+
+<ul>
+ <li>a package declares a constant that nothing has declared scopable. This
also applies to abstract packages.
+The error message lists the scopable constants that are available.</li>
+ <li>a package declares the same constant more than once.</li>
+</ul>
+
+<p>Values are used as they are. Unlike in <code class="language-plaintext
highlighter-rouge"><constant></code>, <code class="language-plaintext
highlighter-rouge">${...}</code> <a
href="constant-configuration#value-substitution">value substitution</a>
+is not supported.</p>
+
+<h3 id="making-a-constant-scopable">Making a constant scopable</h3>
+
+<p>A component makes a constant scopable in two steps. First, register a bean
that implements
+<code class="language-plaintext
highlighter-rouge">org.apache.struts2.config.ScopableConstants</code> and
returns the constant names. You can register more than one
+such bean. The scopable set is the union of all of them.</p>
+
+<div class="language-java highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="kn">import</span> <span
class="nn">org.apache.struts2.config.ScopableConstants</span><span
class="o">;</span>
+
+<span class="kn">import</span> <span class="nn">java.util.Set</span><span
class="o">;</span>
+
+<span class="kd">public</span> <span class="kd">class</span> <span
class="nc">MyScopableConstants</span> <span class="kd">implements</span> <span
class="nc">ScopableConstants</span> <span class="o">{</span>
+ <span class="nd">@Override</span>
+ <span class="kd">public</span> <span class="nc">Set</span><span
class="o"><</span><span class="nc">String</span><span class="o">></span>
<span class="nf">getNames</span><span class="o">()</span> <span
class="o">{</span>
+ <span class="k">return</span> <span class="nc">Set</span><span
class="o">.</span><span class="na">of</span><span class="o">(</span><span
class="s">"myplugin.theme"</span><span class="o">);</span>
+ <span class="o">}</span>
+<span class="o">}</span>
+</code></pre></div></div>
+
+<div class="language-xml highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="nt"><bean</span> <span
class="na">type=</span><span
class="s">"org.apache.struts2.config.ScopableConstants"</span> <span
class="na">name=</span><span class="s">"myplugin"</span>
+ <span class="na">class=</span><span
class="s">"com.example.MyScopableConstants"</span><span class="nt">/></span>
+</code></pre></div></div>
+
+<p>Second, read the value per request through <code class="language-plaintext
highlighter-rouge">org.apache.struts2.config.ScopedConstantProvider</code>, not
through
+an <code class="language-plaintext highlighter-rouge">@Inject</code>-ed
constant:</p>
+
+<div class="language-java highlighter-rouge"><div class="highlight"><pre
class="highlight"><code><span class="kn">import</span> <span
class="nn">org.apache.struts2.config.ScopedConstantProvider</span><span
class="o">;</span>
+<span class="kn">import</span> <span
class="nn">org.apache.struts2.inject.Inject</span><span class="o">;</span>
+
+<span class="kd">private</span> <span class="nc">ScopedConstantProvider</span>
<span class="n">scopedConstantProvider</span><span class="o">;</span>
+
+<span class="nd">@Inject</span>
+<span class="kd">public</span> <span class="kt">void</span> <span
class="nf">setScopedConstantProvider</span><span class="o">(</span><span
class="nc">ScopedConstantProvider</span> <span
class="n">scopedConstantProvider</span><span class="o">)</span> <span
class="o">{</span>
+ <span class="k">this</span><span class="o">.</span><span
class="na">scopedConstantProvider</span> <span class="o">=</span> <span
class="n">scopedConstantProvider</span><span class="o">;</span>
+<span class="o">}</span>
+
+<span class="kd">public</span> <span class="nc">String</span> <span
class="nf">getTheme</span><span class="o">()</span> <span class="o">{</span>
+ <span class="k">return</span> <span
class="n">scopedConstantProvider</span><span class="o">.</span><span
class="na">getValue</span><span class="o">(</span><span
class="s">"myplugin.theme"</span><span class="o">);</span>
+<span class="o">}</span>
+</code></pre></div></div>
+
+<p class="alert alert-info">Use <code class="language-plaintext
highlighter-rouge">org.apache.struts2.inject.Inject</code>. The Struts
container ignores <code class="language-plaintext
highlighter-rouge">jakarta.inject.Inject</code> and
+<code class="language-plaintext highlighter-rouge">javax.inject.Inject</code>,
so the setter would never be called.</p>
+
+<p><code class="language-plaintext highlighter-rouge">getValue(name)</code>
returns the value for the package of the action being executed, taking <code
class="language-plaintext highlighter-rouge">extends</code> into account.
+Outside an action invocation, or when no package in the hierarchy overrides
the constant, it returns the global
+constant, or <code class="language-plaintext highlighter-rouge">null</code>
when that is not set. It throws <code class="language-plaintext
highlighter-rouge">IllegalArgumentException</code> for a name that is not
scopable.
+The global value injected elsewhere is never changed.</p>
+
+<p>Some constants can never be scoped, because they are read before the
package of a request is known, for
+example the <a href="action-mapper">ActionMapper</a> or the multipart upload
limits. To use a different mapper per URL space,
+use the <a
href="action-mapper#prefixbasedactionmapper">PrefixBasedActionMapper</a>
instead.</p>
+
+<p class="alert alert-danger">Do not declare security-related constants
scopable, such as <code class="language-plaintext
highlighter-rouge">struts.parameters.requireAnnotations</code>,
+<code class="language-plaintext
highlighter-rouge">struts.enable.DynamicMethodInvocation</code> or <code
class="language-plaintext highlighter-rouge">struts.devMode</code>. Otherwise a
single package can relax a setting
+meant to protect the whole application.</p>
+
+<p>The default <code class="language-plaintext
highlighter-rouge">ScopedConstantProvider</code> implementation can be replaced
with the <code class="language-plaintext
highlighter-rouge">struts.scopedConstantProvider</code>
+<a href="../plugins/plugins-architecture#extension-points">extension
point</a>. For now this works only from XML or
+properties configuration. Java-based configuration cannot set it yet.</p>
+
</section>
</article>
diff --git a/output/dtds/struts-6.5.dtd b/output/dtds/struts-6.5.dtd
new file mode 100644
index 0000000000..6c2ef0d05b
--- /dev/null
+++ b/output/dtds/struts-6.5.dtd
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<!-- START SNIPPET: strutsDtd -->
+
+<!--
+ Struts configuration DTD.
+ Use the following DOCTYPE
+
+ <!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 6.5//EN"
+ "https://struts.apache.org/dtds/struts-6.5.dtd">
+-->
+
+<!ELEMENT struts ((package|include|bean|constant)*,bean-selection?,
unknown-handler-stack?)>
+<!ATTLIST struts
+ order CDATA #IMPLIED
+>
+
+<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?,
default-action-ref?, default-class-ref?, global-results?,
global-allowed-methods?, global-exception-mappings?, action*)>
+<!ATTLIST package
+ name CDATA #REQUIRED
+ extends CDATA #IMPLIED
+ namespace CDATA #IMPLIED
+ abstract CDATA #IMPLIED
+ final CDATA #IMPLIED
+ strict-method-invocation (true|false) "true"
+>
+
+<!ELEMENT result-types (result-type+)>
+
+<!ELEMENT result-type (param*)>
+<!ATTLIST result-type
+ name CDATA #REQUIRED
+ class CDATA #REQUIRED
+ default (true|false) "false"
+>
+
+<!ELEMENT interceptors (interceptor|interceptor-stack)+>
+
+<!ELEMENT interceptor (param*)>
+<!ATTLIST interceptor
+ name CDATA #REQUIRED
+ class CDATA #REQUIRED
+>
+
+<!ELEMENT interceptor-stack (interceptor-ref*)>
+<!ATTLIST interceptor-stack
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT interceptor-ref (param*)>
+<!ATTLIST interceptor-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-interceptor-ref (#PCDATA)>
+<!ATTLIST default-interceptor-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-action-ref (#PCDATA)>
+<!ATTLIST default-action-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-class-ref (#PCDATA)>
+<!ATTLIST default-class-ref
+ class CDATA #REQUIRED
+>
+
+<!ELEMENT global-results (result+)>
+
+<!ELEMENT global-allowed-methods (#PCDATA)>
+
+<!ELEMENT global-exception-mappings (exception-mapping+)>
+
+<!ELEMENT action
((param|result|interceptor-ref|exception-mapping)*,allowed-methods?)>
+<!ATTLIST action
+ name CDATA #REQUIRED
+ class CDATA #IMPLIED
+ method CDATA #IMPLIED
+ converter CDATA #IMPLIED
+>
+
+<!ELEMENT param (#PCDATA)>
+<!ATTLIST param
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT result (#PCDATA|param)*>
+<!ATTLIST result
+ name CDATA #IMPLIED
+ type CDATA #IMPLIED
+>
+
+<!ELEMENT exception-mapping (#PCDATA|param)*>
+<!ATTLIST exception-mapping
+ name CDATA #IMPLIED
+ exception CDATA #REQUIRED
+ result CDATA #REQUIRED
+>
+
+<!ELEMENT allowed-methods (#PCDATA)>
+
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include
+ file CDATA #REQUIRED
+>
+
+<!ELEMENT bean (#PCDATA)>
+<!ATTLIST bean
+ type CDATA #IMPLIED
+ name CDATA #IMPLIED
+ class CDATA #REQUIRED
+ scope CDATA #IMPLIED
+ static CDATA #IMPLIED
+ optional CDATA #IMPLIED
+>
+
+<!ELEMENT bean-selection (#PCDATA)>
+<!ATTLIST bean-selection
+ name CDATA #IMPLIED
+ class CDATA #IMPLIED
+>
+
+<!ELEMENT constant (#PCDATA)>
+<!ATTLIST constant
+ name CDATA #REQUIRED
+ value CDATA #REQUIRED
+>
+
+<!ELEMENT unknown-handler-stack (unknown-handler-ref*)>
+<!ELEMENT unknown-handler-ref (#PCDATA)>
+<!ATTLIST unknown-handler-ref
+ name CDATA #REQUIRED
+>
+
+<!-- END SNIPPET: strutsDtd -->
+
diff --git a/output/dtds/struts-7.5.dtd b/output/dtds/struts-7.5.dtd
new file mode 100644
index 0000000000..307f5f0e0a
--- /dev/null
+++ b/output/dtds/struts-7.5.dtd
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/*
+ * 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.
+ */
+-->
+<!-- START SNIPPET: strutsDtd -->
+
+<!--
+ Struts configuration DTD.
+ Use the following DOCTYPE
+
+ <!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "https://struts.apache.org/dtds/struts-7.5.dtd">
+-->
+
+<!ELEMENT struts ((package|include|bean|constant)*,bean-selection?,
unknown-handler-stack?)>
+<!ATTLIST struts
+ order CDATA #IMPLIED
+>
+
+<!ELEMENT package (scoped-constant*, result-types?, interceptors?,
default-interceptor-ref?, default-action-ref?, default-class-ref?,
global-results?, global-allowed-methods?, global-exception-mappings?, action*)>
+<!ATTLIST package
+ name CDATA #REQUIRED
+ extends CDATA #IMPLIED
+ namespace CDATA #IMPLIED
+ abstract CDATA #IMPLIED
+ final CDATA #IMPLIED
+ strict-method-invocation (true|false) "true"
+>
+
+<!ELEMENT scoped-constant EMPTY>
+<!ATTLIST scoped-constant
+ name CDATA #REQUIRED
+ value CDATA #REQUIRED
+>
+
+<!ELEMENT result-types (result-type+)>
+
+<!ELEMENT result-type (param*)>
+<!ATTLIST result-type
+ name CDATA #REQUIRED
+ class CDATA #REQUIRED
+ default (true|false) "false"
+>
+
+<!ELEMENT interceptors (interceptor|interceptor-stack)+>
+
+<!ELEMENT interceptor (param*)>
+<!ATTLIST interceptor
+ name CDATA #REQUIRED
+ class CDATA #REQUIRED
+>
+
+<!ELEMENT interceptor-stack (interceptor-ref*)>
+<!ATTLIST interceptor-stack
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT interceptor-ref (param*)>
+<!ATTLIST interceptor-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-interceptor-ref (#PCDATA)>
+<!ATTLIST default-interceptor-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-action-ref (#PCDATA)>
+<!ATTLIST default-action-ref
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT default-class-ref (#PCDATA)>
+<!ATTLIST default-class-ref
+ class CDATA #REQUIRED
+>
+
+<!ELEMENT global-results (result+)>
+
+<!ELEMENT global-allowed-methods (#PCDATA)>
+
+<!ELEMENT global-exception-mappings (exception-mapping+)>
+
+<!ELEMENT action
((param|result|interceptor-ref|exception-mapping)*,allowed-methods?)>
+<!ATTLIST action
+ name CDATA #REQUIRED
+ class CDATA #IMPLIED
+ method CDATA #IMPLIED
+ converter CDATA #IMPLIED
+>
+
+<!ELEMENT param (#PCDATA)>
+<!ATTLIST param
+ name CDATA #REQUIRED
+>
+
+<!ELEMENT result (#PCDATA|param)*>
+<!ATTLIST result
+ name CDATA #IMPLIED
+ type CDATA #IMPLIED
+>
+
+<!ELEMENT exception-mapping (#PCDATA|param)*>
+<!ATTLIST exception-mapping
+ name CDATA #IMPLIED
+ exception CDATA #REQUIRED
+ result CDATA #REQUIRED
+>
+
+<!ELEMENT allowed-methods (#PCDATA)>
+
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include
+ file CDATA #REQUIRED
+>
+
+<!ELEMENT bean (#PCDATA)>
+<!ATTLIST bean
+ type CDATA #IMPLIED
+ name CDATA #IMPLIED
+ class CDATA #REQUIRED
+ scope CDATA #IMPLIED
+ static CDATA #IMPLIED
+ optional CDATA #IMPLIED
+>
+
+<!ELEMENT bean-selection (#PCDATA)>
+<!ATTLIST bean-selection
+ name CDATA #IMPLIED
+ class CDATA #IMPLIED
+>
+
+<!ELEMENT constant (#PCDATA)>
+<!ATTLIST constant
+ name CDATA #REQUIRED
+ value CDATA #REQUIRED
+>
+
+<!ELEMENT unknown-handler-stack (unknown-handler-ref*)>
+<!ELEMENT unknown-handler-ref (#PCDATA)>
+<!ATTLIST unknown-handler-ref
+ name CDATA #REQUIRED
+>
+
+<!-- END SNIPPET: strutsDtd -->
+
diff --git a/output/plugins/plugins-architecture.html
b/output/plugins/plugins-architecture.html
index 02097687b4..e120110c60 100644
--- a/output/plugins/plugins-architecture.html
+++ b/output/plugins/plugins-architecture.html
@@ -508,6 +508,12 @@ For example, a plugin could provide a new class to create
Action classes or map
<td>singleton</td>
<td>ognl.MethodAccessor</td>
</tr>
+ <tr>
+ <td>struts.scopedConstantProvider</td>
+ <td>Resolves package-scoped constants declared with <code
class="language-plaintext highlighter-rouge"><scoped-constant></code>
(since 7.5.0)</td>
+ <td>singleton</td>
+ <td>org.apache.struts2.config.ScopedConstantProvider</td>
+ </tr>
</tbody>
</table>