Simultaneous definition requests to multiple locales causes 
NoSuchDefinitionException on anonymousDefinition
------------------------------------------------------------------------------------------------------------

                 Key: TILES-513
                 URL: https://issues.apache.org/jira/browse/TILES-513
             Project: Tiles
          Issue Type: Bug
          Components: tiles-core
    Affects Versions: 2.2.2, 2.1.4
            Reporter: Jamie Goodfellow


When simultaneously loading the same tiles definition for two locales (in my 
case, en_CA and es_CO) and a third empty locale, they empty locale request 
results in a stack trace claiming an anonymous definition could not be found.  
I traced this to a synchronization issue in CachingLocaleUrlDefinitionDAO and 
ResolvingLocaleUrlDefinitionDAO.  The issue seems to be that the 
loadParentDefinitions method loads the parent locale definitions into the 
locale2definitionMap map regardless if the map already contains an entry for 
the requested locale.  Alone this is fine, since the update is synchronized in 
a previous method call in the stack trace.  However when the three requests 
come in simultaneously, and the requested definition has nested anonymous 
definitions, there is a timing issue.

The first request (say en_CA) requests the root definition (in this case 
'security/login').  This causes the root, en, and en_CA definition maps to be 
loaded.  At the same time, the second request (es_CO) requests the 
'security/login' definition.  This will cause the root, es, and es_CO 
definitions to be loaded (overwriting the root locale with new anonymous 
definitions).  The third request (empty locale) will request the 
'security/login' definition as well.  The definition processing will then see 
that the security/login definition references other definitions, and begin 
requesting anonymous definitions.  However, since the root locale has been 
overwritten, the requested definitions no longer appear in the root map.  This 
results in the stack trace below.

Appended below are my tiles definition configurations and the stack trace, for 
reference.  I've also applied a fix for myself.  In Tiles 2.2.2, I updated the 
loadParentDefinitions in ResolvingLocaleUrlDefinitionDAO to check if the map 
already contains an entry for the requested locale, and returns the existing 
entry if so:

    @Override
    protected Map<String, Definition> loadParentDefinitions(Locale 
parentLocale) {
        if(locale2definitionMap.containsKey(parentLocale)) {
                return 
copyDefinitionMap(locale2definitionMap.get(parentLocale));
        } else {
                return loadDefinitionsFromURLs(parentLocale);
        }
    }

I've verified this fixes my issue.


        <!-- Authentication Layout -->
        <definition name="authLayout" template="/WEB-INF/layouts/auth.jsp">
                <put-attribute name="header">
                        <definition template="/WEB-INF/layouts/auth/header.jsp" 
/>
                </put-attribute>
                <put-attribute name="localnav">
                        <definition 
template="/WEB-INF/layouts/auth/localnav.jsp" />
                </put-attribute>
                <put-attribute name="footer">
                        <definition template="/WEB-INF/layouts/auth/footer.jsp" 
/>
                </put-attribute>
        </definition>

        <!-- index page -->
        <definition name="security/login" extends="authLayout">
                <put-attribute name="title" value="page.title.security.login" />
                <put-attribute name="navTab" value="security" />
                <put-attribute name="main" 
value="/WEB-INF/views/security/login.jsp" />
        </definition>

org.apache.tiles.definition.NoSuchDefinitionException: $anonymousDefinition7
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:625)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:321)
        
org.apache.tiles.renderer.impl.DefinitionAttributeRenderer.write(DefinitionAttributeRenderer.java:56)
        
org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:670)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:336)
        
org.apache.tiles.template.InsertAttributeModel.renderAttribute(InsertAttributeModel.java:210)
        
org.apache.tiles.template.InsertAttributeModel.end(InsertAttributeModel.java:126)
        
org.apache.tiles.jsp.taglib.InsertAttributeTag.doTag(InsertAttributeTag.java:311)
        
org.apache.jsp.WEB_002dINF.layouts.auth_jsp._jspx_meth_tiles_005finsertAttribute_005f0(auth_jsp.java:899)
        
org.apache.jsp.WEB_002dINF.layouts.auth_jsp._jspService(auth_jsp.java:228)
        org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:374)
        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        
org.apache.tiles.servlet.context.ServletTilesRequestContext.forward(ServletTilesRequestContext.java:241)
        
org.apache.tiles.servlet.context.ServletTilesRequestContext.dispatch(ServletTilesRequestContext.java:222)
        
org.apache.tiles.renderer.impl.TemplateAttributeRenderer.write(TemplateAttributeRenderer.java:44)
        
org.apache.tiles.renderer.impl.AbstractBaseAttributeRenderer.render(AbstractBaseAttributeRenderer.java:106)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:670)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:690)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:644)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:627)
        
org.apache.tiles.impl.BasicTilesContainer.render(BasicTilesContainer.java:321)
        
org.springframework.web.servlet.view.tiles2.TilesView.renderMergedOutputModel(TilesView.java:124)
        
org.springframework.js.ajax.tiles2.AjaxTilesView.renderMergedOutputModel(AjaxTilesView.java:115)
        
org.springframework.web.servlet.view.AbstractView.render(AbstractView.java:250)
        
org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1063)
        
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:801)
        
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719)
        
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644)
        
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:549)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        
com.truecontext.prontoforms.pes.aspect.audit.impl.filter.AuditContextSettingFilter.doFilterInternal(AuditContextSettingFilter.java:50)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:113)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
com.truecontext.prontoforms.pes.web.filter.IncompleteUserFilter.doFilterInternal(IncompleteUserFilter.java:50)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
org.springframework.web.filter.AbstractRequestLoggingFilter.doFilterInternal(AbstractRequestLoggingFilter.java:193)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:343)
        
org.springframework.security.web.authentication.switchuser.SwitchUserFilter.doFilter(SwitchUserFilter.java:177)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:109)
        
org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:83)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:97)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:100)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:78)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter.doFilter(RememberMeAuthenticationFilter.java:112)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:54)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:35)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
com.truecontext.common.web.aspects.security.authentication.www.UrlSpecificBasicAuthenticationFilter.doFilter(UrlSpecificBasicAuthenticationFilter.java:105)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:188)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:79)
        
org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
        
org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
        
org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
        
org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
        
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
        
org.springframework.web.filter.ShallowEtagHeaderFilter.doFilterInternal(ShallowEtagHeaderFilter.java:57)
        
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to