[
https://issues.apache.org/jira/browse/WW-5716?focusedWorklogId=1039589&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1039589
]
ASF GitHub Bot logged work on WW-5716:
--------------------------------------
Author: ASF GitHub Bot
Created on: 04/Sep/26 08:48
Start Date: 04/Sep/26 08:48
Worklog Time Spent: 10m
Work Description: lukaszlenart opened a new pull request, #1902:
URL: https://github.com/apache/struts/pull/1902
The Tiles definition caches are keyed by the resolved `Locale`, which by
default derives from the request. Two maps grew without limit and were never
reduced for the lifetime of the web application:
- `CachingLocaleUrlDefinitionDAO#locale2definitionMap` — populated on each
cache miss, only cleared under the (default-off) `checkRefresh` path.
- `AbstractPatternDefinitionResolver#localePatternPaths` — populated via
`computeIfAbsent` per locale key, never swept.
The `TilesContainer` holding the DAO lives in application scope, so both
maps persisted for the application lifetime, and the number of distinct keys
was bounded only by the number of distinct locales encountered.
### Change
- Bound `locale2definitionMap` with an insertion-order `LinkedHashMap`
capped at `maxCachedLocales` (default `1000`, configurable via
`setMaxCachedLocales`). Insertion-order (not access-order) keeps the existing
unsynchronized `getDefinitions` read unchanged.
- On eviction the DAO removes the same key from the pattern resolver through
the new `PatternDefinitionResolver#removePatternPaths`, keeping both maps in
lockstep — the resolver's keys are always a subset of the DAO's, since a
pattern-paths entry is stored right before every `locale2definitionMap` put.
- `localePatternPaths` becomes a `ConcurrentHashMap`, as the DAO now removes
keys off the request thread.
Eviction only re-incurs a load on next access; it never changes rendering.
Both concrete resolvers (`BasicPatternDefinitionResolver`,
`PrefixedPatternDefinitionResolver`) inherit the new behaviour from
`AbstractPatternDefinitionResolver`.
Tests cover the bound and that both maps evict together; the full
`struts2-tiles-plugin` module suite passes (547 tests).
Fixes [WW-5716](https://issues.apache.org/jira/browse/WW-5716)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Issue Time Tracking
-------------------
Worklog Id: (was: 1039589)
Remaining Estimate: 0h
Time Spent: 10m
> Bound the per-locale definition caches in the Tiles plugin
> ----------------------------------------------------------
>
> Key: WW-5716
> URL: https://issues.apache.org/jira/browse/WW-5716
> Project: Struts 2
> Issue Type: Improvement
> Reporter: Lukasz Lenart
> Assignee: Lukasz Lenart
> Priority: Major
> Fix For: 6.12.0, 7.4.0
>
> Time Spent: 10m
> Remaining Estimate: 0h
>
> The Tiles plugin caches parsed definitions per resolved {{Locale}} in two
> maps that grow without limit and are never reduced during the lifetime of the
> web application:
> *
> {{org.apache.tiles.core.definition.dao.CachingLocaleUrlDefinitionDAO#locale2definitionMap}}
> — a {{HashMap}} keyed by {{Locale}}, populated on each cache miss and never
> evicted. It is only cleared when {{checkRefresh}} is enabled and a refresh is
> required, and {{checkRefresh}} is {{false}} by default.
> *
> {{org.apache.tiles.core.definition.pattern.AbstractPatternDefinitionResolver#localePatternPaths}}
> — populated via {{computeIfAbsent}} per locale customization key and never
> swept.
> The {{TilesContainer}} that holds the DAO is stored in application scope, so
> both maps persist for the lifetime of the web application. With the default
> {{StrutsTilesLocaleResolver}}, the resolved locale comes from the
> {{ActionContext}} locale, which derives from {{request.getLocale()}}. In that
> setup the number of distinct cache keys is bounded only by the number of
> distinct locales encountered, and every new locale adds an entry that is
> retained indefinitely, so the caches' memory footprint grows over time with
> no upper bound.
> h3. Proposed change
> Bound both per-locale maps in the plugin's vendored Tiles code — for example
> a configurable maximum size with eviction — and ensure {{localePatternPaths}}
> is bounded/cleared alongside {{locale2definitionMap}}. Both maps sit on the
> same code path, so they must be bounded together; fixing only one leaves the
> other unbounded.
> h3. Notes
> * Affects every version that ships the Tiles plugin; the vendored caching DAO
> is unbounded across all of them.
> * Deployments that pin a fixed locale via {{struts.locale}}, or that enable
> {{struts.locale.validateRequestLocale=true}} (7.3.0+/6.11.0+), already
> constrain the key set. This change makes the plugin robust by default without
> requiring that configuration.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)