[
https://issues.apache.org/jira/browse/WW-3476?focusedWorklogId=1046849&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1046849
]
ASF GitHub Bot logged work on WW-3476:
--------------------------------------
Author: ASF GitHub Bot
Created on: 11/Oct/26 08:23
Start Date: 11/Oct/26 08:23
Worklog Time Spent: 10m
Work Description: lukaszlenart commented on code in PR #351:
URL: https://github.com/apache/struts-site/pull/351#discussion_r4240861150
##########
source/core-developers/package-configuration.md:
##########
@@ -80,3 +80,100 @@ The optional `abstract` attribute creates a base package
that can omit the actio
</package>
</struts>
```
+
+## Scoped constants
+
+Since Struts 7.5.0 a package can override selected
[constants](constant-configuration) for its own actions with
+the `<scoped-constant>` element. Packages that `extends` it inherit the
override, and an override declared in
Review Comment:
Two small additions could go here:
- With several parents (`extends="a,b"`), the first listed parent wins on a
conflict, the same rule as result types.
- Packages built by the Convention plugin get overrides only by inheriting
them from their XML parent package (`@ParentPackage`).
##########
source/core-developers/package-configuration.md:
##########
@@ -80,3 +80,100 @@ The optional `abstract` attribute creates a base package
that can omit the actio
</package>
</struts>
```
+
+## Scoped constants
+
+Since Struts 7.5.0 a package can override selected
[constants](constant-configuration) for its own actions with
+the `<scoped-constant>` element. Packages that `extends` it inherit the
override, and an override declared in
+the child package wins.
+
+The element requires the [struts-7.5.dtd](../dtds/struts-7.5.dtd) and must
come before any other child of
+`<package>`:
+
+```xml
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "https://struts.apache.org/dtds/struts-7.5.dtd">
+<struts>
+ <package name="admin" extends="struts-default" namespace="/admin">
+ <scoped-constant name="some.scopable.constant" value="x"/>
+ ...
+ </package>
+</struts>
+```
+
+| Attribute | Required | Description |
+|-----------|----------|-------------------------------------------|
+| name | **yes** | the name of a scopable constant |
+| value | **yes** | the value used for actions of the package |
+
+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
_scopable_, and only those can appear
+in `<scoped-constant>`.
+
+{:.alert .alert-warning}
+Struts core does not declare any constant as scopable yet. A
`<scoped-constant>` only works with a constant
+declared scopable by a plugin or by your own application code.
+
+The configuration is validated at startup, and loading fails when:
+
+- 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.
+- a package declares the same constant more than once.
+
+Values are used as they are. Unlike in `<constant>`, `${...}` [value
substitution](constant-configuration#value-substitution)
Review Comment:
Accurate for the current code. Filed
[WW-5767](https://issues.apache.org/jira/browse/WW-5767) to apply the same
load-time value substitution as `<constant>` (environment variables and system
properties). That is not the per-request evaluation WW-3476 ruled out. If it
lands before 7.5.0, this sentence goes away.
##########
source/core-developers/package-configuration.md:
##########
@@ -80,3 +80,100 @@ The optional `abstract` attribute creates a base package
that can omit the actio
</package>
</struts>
```
+
+## Scoped constants
+
+Since Struts 7.5.0 a package can override selected
[constants](constant-configuration) for its own actions with
+the `<scoped-constant>` element. Packages that `extends` it inherit the
override, and an override declared in
+the child package wins.
+
+The element requires the [struts-7.5.dtd](../dtds/struts-7.5.dtd) and must
come before any other child of
+`<package>`:
+
+```xml
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "https://struts.apache.org/dtds/struts-7.5.dtd">
+<struts>
+ <package name="admin" extends="struts-default" namespace="/admin">
+ <scoped-constant name="some.scopable.constant" value="x"/>
+ ...
+ </package>
+</struts>
+```
+
+| Attribute | Required | Description |
+|-----------|----------|-------------------------------------------|
+| name | **yes** | the name of a scopable constant |
+| value | **yes** | the value used for actions of the package |
+
+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
_scopable_, and only those can appear
+in `<scoped-constant>`.
+
+{:.alert .alert-warning}
+Struts core does not declare any constant as scopable yet. A
`<scoped-constant>` only works with a constant
+declared scopable by a plugin or by your own application code.
+
+The configuration is validated at startup, and loading fails when:
+
+- 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.
+- a package declares the same constant more than once.
+
+Values are used as they are. Unlike in `<constant>`, `${...}` [value
substitution](constant-configuration#value-substitution)
+is not supported.
+
+### Making a constant scopable
+
+A component makes a constant scopable in two steps. First, register a bean
that implements
+`org.apache.struts2.config.ScopableConstants` and returns the constant names.
You can register more than one
+such bean. The scopable set is the union of all of them.
+
+```java
+public class MyScopableConstants implements ScopableConstants {
+ @Override
+ public Set<String> getNames() {
+ return Set.of("myplugin.theme");
+ }
+}
+```
+
+```xml
+<bean type="org.apache.struts2.config.ScopableConstants" name="myplugin"
+ class="com.example.MyScopableConstants"/>
+```
+
+Second, read the value per request through
`org.apache.struts2.config.ScopedConstantProvider`, not through
+an `@Inject`-ed constant:
+
+```java
+private ScopedConstantProvider scopedConstantProvider;
+
+@Inject
Review Comment:
Suggest showing the imports here, at least `import
org.apache.struts2.inject.Inject;`. Readers tend to reach for
`jakarta.inject.Inject` / `javax.inject.Inject`, which the Struts container
ignores, so the setter would silently never be called. Adding the
`ScopableConstants` / `ScopedConstantProvider` imports to the two snippets
would help too.
##########
source/core-developers/package-configuration.md:
##########
@@ -80,3 +80,100 @@ The optional `abstract` attribute creates a base package
that can omit the actio
</package>
</struts>
```
+
+## Scoped constants
+
+Since Struts 7.5.0 a package can override selected
[constants](constant-configuration) for its own actions with
+the `<scoped-constant>` element. Packages that `extends` it inherit the
override, and an override declared in
+the child package wins.
+
+The element requires the [struts-7.5.dtd](../dtds/struts-7.5.dtd) and must
come before any other child of
+`<package>`:
+
+```xml
+<!DOCTYPE struts PUBLIC
+ "-//Apache Software Foundation//DTD Struts Configuration 7.5//EN"
+ "https://struts.apache.org/dtds/struts-7.5.dtd">
+<struts>
+ <package name="admin" extends="struts-default" namespace="/admin">
+ <scoped-constant name="some.scopable.constant" value="x"/>
+ ...
+ </package>
+</struts>
+```
+
+| Attribute | Required | Description |
+|-----------|----------|-------------------------------------------|
+| name | **yes** | the name of a scopable constant |
+| value | **yes** | the value used for actions of the package |
+
+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
_scopable_, and only those can appear
+in `<scoped-constant>`.
+
+{:.alert .alert-warning}
+Struts core does not declare any constant as scopable yet. A
`<scoped-constant>` only works with a constant
+declared scopable by a plugin or by your own application code.
+
+The configuration is validated at startup, and loading fails when:
+
+- 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.
+- a package declares the same constant more than once.
+
+Values are used as they are. Unlike in `<constant>`, `${...}` [value
substitution](constant-configuration#value-substitution)
+is not supported.
+
+### Making a constant scopable
+
+A component makes a constant scopable in two steps. First, register a bean
that implements
+`org.apache.struts2.config.ScopableConstants` and returns the constant names.
You can register more than one
+such bean. The scopable set is the union of all of them.
+
+```java
+public class MyScopableConstants implements ScopableConstants {
+ @Override
+ public Set<String> getNames() {
+ return Set.of("myplugin.theme");
+ }
+}
+```
+
+```xml
+<bean type="org.apache.struts2.config.ScopableConstants" name="myplugin"
+ class="com.example.MyScopableConstants"/>
+```
+
+Second, read the value per request through
`org.apache.struts2.config.ScopedConstantProvider`, not through
+an `@Inject`-ed constant:
+
+```java
+private ScopedConstantProvider scopedConstantProvider;
+
+@Inject
+public void setScopedConstantProvider(ScopedConstantProvider
scopedConstantProvider) {
+ this.scopedConstantProvider = scopedConstantProvider;
+}
+
+public String getTheme() {
+ return scopedConstantProvider.getValue("myplugin.theme");
+}
+```
+
+`getValue(name)` returns the value for the package of the action being
executed, taking `extends` into account.
+Outside an action invocation, or when no package in the hierarchy overrides
the constant, it returns the global
+constant, or `null` when that is not set. It throws `IllegalArgumentException`
for a name that is not scopable.
+The global value injected elsewhere is never changed.
+
+Some constants can never be scoped, because they are read before the package
of a request is known, for
+example the [ActionMapper](action-mapper) or the multipart upload limits. To
use a different mapper per URL space,
+use the [PrefixBasedActionMapper](action-mapper#prefixbasedactionmapper)
instead.
+
+{:.alert .alert-danger}
+Do not declare security-related constants scopable, such as
`struts.parameters.requireAnnotations`,
+`struts.enable.DynamicMethodInvocation` or `struts.devMode`. Otherwise a
single package can relax a setting
+meant to protect the whole application.
+
+The default `ScopedConstantProvider` implementation can be replaced with the
`struts.scopedConstantProvider`
Review Comment:
This currently holds for XML and properties configuration only. Java-based
configuration cannot set `struts.scopedConstantProvider` yet, because
`ConstantConfig` has no mapping for it
([WW-5766](https://issues.apache.org/jira/browse/WW-5766), 7.5.0). Either add a
short note, or update this when WW-5766 ships.
Issue Time Tracking
-------------------
Worklog Id: (was: 1046849)
Time Spent: 2h 50m (was: 2h 40m)
> Allow overwriting of constants for each package
> -----------------------------------------------
>
> Key: WW-3476
> URL: https://issues.apache.org/jira/browse/WW-3476
> Project: Struts 2
> Issue Type: New Feature
> Components: XML Configuration
> Affects Versions: 2.2.1
> Reporter: Johannes Geppert
> Assignee: Lukasz Lenart
> Priority: Major
> Fix For: 7.5.0
>
> Time Spent: 2h 50m
> Remaining Estimate: 0h
>
> Allow to overwriting of constants for each package.
> So I can specify as example for each package an other ActionMapper, Local or
> other location for the JSP Files.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)