[ 
https://issues.apache.org/jira/browse/WW-5692?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Lukasz Lenart updated WW-5692:
------------------------------
    Fix Version/s: 8.0.0
                       (was: 7.4.0)
      Description: 
Part of the WW-5689 lean-core work. Retargeted from 7.4.0 to 8.0.0 and 
re-scoped from an in-place rewrite to a module move.

{{DebuggingInterceptor}} holds an injected {{FreemarkerManager}} and constructs 
{{FreemarkerResult}} directly to render {{console.ftl}} and {{browser.ftl}}. It 
is the third of the three places core reaches into {{views.freemarker}}, after 
WW-5690/WW-5693 and WW-5691.

h2. Why a move rather than a rewrite

The sibling tickets replace their template with a plain-Java renderer. That is 
the wrong trade here:
* {{browser.ftl}} is 91 lines and {{console.ftl}} 34 — substantially more than 
{{wait.ftl}}, and {{console.ftl}} uses the tag library too ({{s.url 
value="/static"}}), not just FreeMarker.
* A rewrite inherits the escaping trap described in WW-5691 and WW-5693: 
{{FreemarkerManager}} sets {{HTMLOutputFormat}} with 
{{ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY}}, so these templates are HTML-escaped 
today by configuration. Hand-written renderers lose that, and this one renders 
the entire value stack.
* Moving the interceptor takes its templates with it. No rewrite, no escaping 
change, and existing template overrides keep working.

This is also the better fit for WW-5689's direction: a devMode-only diagnostic 
tool is a plugin, not core.

h2. The package is already clean

{{org.apache.struts2.interceptor.debugging}} contains exactly three classes — 
{{DebuggingInterceptor}}, {{ObjectToHTMLWriter}}, {{PrettyPrintWriter}} — and 
the two writers are referenced nowhere else in core, the plugins or the apps. 
So the whole-package cut that WW-4759 requires is available here with no 
de-mixing work first, unlike most of WW-5689.

What it needs from core is ordinary published API: {{ActionContext}}, 
{{ActionInvocation}}, {{ServletActionContext}}, {{AbstractInterceptor}}, 
{{ValueStack}}, {{ReflectionProvider}}, {{ThreadAllowlist}}, and some 
{{dispatcher}} types. Nothing that would invert the dependency.

h2. The open design question: defaultStack membership

This is the part that must be settled before any code moves.

{{struts-default.xml}} declares the interceptor (line 57) and references it 
from *{{defaultStack}}* (line 230). A plugin cannot simply take that with it — 
core's {{defaultStack}} cannot reference an interceptor that may not be on the 
classpath, and every application extends {{struts-default}}.

Candidate resolutions, none obviously correct:
# Core's {{defaultStack}} drops {{debugging}}; the plugin publishes its own 
stack that applications opt into. Simple and honest, but devMode debugging 
stops working out of the box — a real regression for a well-liked tool.
# The plugin redefines {{defaultStack}}. Fragile, and it collides with any 
other plugin doing the same.
# Add a core extension point letting a plugin append an interceptor to a named 
stack. Cleanest for users, but it is new framework machinery and deserves its 
own ticket rather than riding along on this one.

Option 1 is the least surprising if the assembly keeps bundling the plugin by 
default, since a stock distribution would still ship it — but that only shifts 
the problem to anyone building a dependency list by hand.

h2. Notes
* {{struts.devMode}} gates the whole interceptor, so no production behaviour is 
at stake either way.
* The new plugin depends on the FreeMarker plugin and on core's static content 
serving ({{console.ftl}} points its {{baseUrl}} at {{/static}}).
* Sequencing against WW-5689's module split needs care: this plugin is a 
consumer of {{struts2-freemarker-plugin}}, so it should land after that module 
exists, or carry the dependency temporarily.

  was:
Part of the WW-5689 lean-core work, but self-contained and shippable in 7.x. 
See WW-5690 for the shared scope note — this concerns _core's own_ FreeMarker 
dependency only; tag-library users still require FreeMarker via the default FTL 
themes.

h2. Current behaviour

{{DebuggingInterceptor}} holds an injected {{FreemarkerManager}} and constructs 
{{FreemarkerResult}} directly in two places to render its diagnostic pages:
* the {{console}} mode, rendering 
{{/org/apache/struts2/interceptor/debugging/console.ftl}}
* the {{browser}} mode, rendering 
{{/org/apache/struts2/interceptor/debugging/browser.ftl}}

This is the third and last hard {{views.freemarker}} import left in core 
outside the view packages, after WW-5690 and WW-5691.

h2. Proposal

Same treatment as the other two: render the debug pages without instantiating a 
{{FreemarkerResult}}, keeping the output identical.

Worth considering as an alternative: this interceptor is a devMode-only 
diagnostic tool and is arguably a plugin in its own right. Moving it out of 
core wholesale would resolve the dependency without rewriting the templates, 
and fits the WW-5689 direction. That is the larger change though — for 7.x, 
removing the hard dependency in place is the safer scope, and the decision can 
be revisited for 8.0.0.

h2. Compatibility

Both templates are internal. {{struts.devMode}} gates the whole interceptor, so 
no production path is affected.

          Summary: Move DebuggingInterceptor into its own plugin  (was: Remove 
core's FreeMarker dependency from DebuggingInterceptor)

> Move DebuggingInterceptor into its own plugin
> ---------------------------------------------
>
>                 Key: WW-5692
>                 URL: https://issues.apache.org/jira/browse/WW-5692
>             Project: Struts 2
>          Issue Type: Task
>          Components: Core
>            Reporter: Lukasz Lenart
>            Priority: Major
>             Fix For: 8.0.0
>
>
> Part of the WW-5689 lean-core work. Retargeted from 7.4.0 to 8.0.0 and 
> re-scoped from an in-place rewrite to a module move.
> {{DebuggingInterceptor}} holds an injected {{FreemarkerManager}} and 
> constructs {{FreemarkerResult}} directly to render {{console.ftl}} and 
> {{browser.ftl}}. It is the third of the three places core reaches into 
> {{views.freemarker}}, after WW-5690/WW-5693 and WW-5691.
> h2. Why a move rather than a rewrite
> The sibling tickets replace their template with a plain-Java renderer. That 
> is the wrong trade here:
> * {{browser.ftl}} is 91 lines and {{console.ftl}} 34 — substantially more 
> than {{wait.ftl}}, and {{console.ftl}} uses the tag library too ({{s.url 
> value="/static"}}), not just FreeMarker.
> * A rewrite inherits the escaping trap described in WW-5691 and WW-5693: 
> {{FreemarkerManager}} sets {{HTMLOutputFormat}} with 
> {{ENABLE_IF_DEFAULT_AUTO_ESCAPING_POLICY}}, so these templates are 
> HTML-escaped today by configuration. Hand-written renderers lose that, and 
> this one renders the entire value stack.
> * Moving the interceptor takes its templates with it. No rewrite, no escaping 
> change, and existing template overrides keep working.
> This is also the better fit for WW-5689's direction: a devMode-only 
> diagnostic tool is a plugin, not core.
> h2. The package is already clean
> {{org.apache.struts2.interceptor.debugging}} contains exactly three classes — 
> {{DebuggingInterceptor}}, {{ObjectToHTMLWriter}}, {{PrettyPrintWriter}} — and 
> the two writers are referenced nowhere else in core, the plugins or the apps. 
> So the whole-package cut that WW-4759 requires is available here with no 
> de-mixing work first, unlike most of WW-5689.
> What it needs from core is ordinary published API: {{ActionContext}}, 
> {{ActionInvocation}}, {{ServletActionContext}}, {{AbstractInterceptor}}, 
> {{ValueStack}}, {{ReflectionProvider}}, {{ThreadAllowlist}}, and some 
> {{dispatcher}} types. Nothing that would invert the dependency.
> h2. The open design question: defaultStack membership
> This is the part that must be settled before any code moves.
> {{struts-default.xml}} declares the interceptor (line 57) and references it 
> from *{{defaultStack}}* (line 230). A plugin cannot simply take that with it 
> — core's {{defaultStack}} cannot reference an interceptor that may not be on 
> the classpath, and every application extends {{struts-default}}.
> Candidate resolutions, none obviously correct:
> # Core's {{defaultStack}} drops {{debugging}}; the plugin publishes its own 
> stack that applications opt into. Simple and honest, but devMode debugging 
> stops working out of the box — a real regression for a well-liked tool.
> # The plugin redefines {{defaultStack}}. Fragile, and it collides with any 
> other plugin doing the same.
> # Add a core extension point letting a plugin append an interceptor to a 
> named stack. Cleanest for users, but it is new framework machinery and 
> deserves its own ticket rather than riding along on this one.
> Option 1 is the least surprising if the assembly keeps bundling the plugin by 
> default, since a stock distribution would still ship it — but that only 
> shifts the problem to anyone building a dependency list by hand.
> h2. Notes
> * {{struts.devMode}} gates the whole interceptor, so no production behaviour 
> is at stake either way.
> * The new plugin depends on the FreeMarker plugin and on core's static 
> content serving ({{console.ftl}} points its {{baseUrl}} at {{/static}}).
> * Sequencing against WW-5689's module split needs care: this plugin is a 
> consumer of {{struts2-freemarker-plugin}}, so it should land after that 
> module exists, or carry the dependency temporarily.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to