[ 
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)

Reply via email to