    001//  Copyright 2011, 2013, 2020 The Apache Software Foundation
    002//
    003//  Licensed under the Apache License, Version 2.0 (the "License");
    004//  you may not use this file except in compliance with the License.
    005//  You may obtain a copy of the License at
    006//
    007//  http://www.apache.org/licenses/LICENSE-2.0
    008//
    009//  Unless required by applicable law or agreed to in writing, software
    010//  distributed under the License is distributed on an "AS IS" BASIS,
    011//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012//  See the License for the specific language governing permissions and
    013//  limitations under the License.
    014
    015package org.apache.tapestry5.http.internal.services;
    016
    017import org.apache.tapestry5.commons.util.CollectionFactory;
    018import org.apache.tapestry5.http.services.SessionPersistedObjectAnalyzer;
    019import org.apache.tapestry5.ioc.services.PerthreadManager;
    020
    021import javax.servlet.http.HttpServletRequest;
    022import javax.servlet.http.HttpSession;
    023import java.util.Map;
    024
    025/**
    026 * A thin wrapper around {@link javax.servlet.http.HttpSession} that supports re-storing of mutable
    027 * session attributes at the end of the request (see {@link #restoreDirtyObjects()}). This is only
    028 * used when {@linkplain org.apache.tapestry5.SymbolConstants#CLUSTERED_SESSIONS clustering}.
    029 *
    030 * @since 5.3
    031 * @see SessionPersistedObjectAnalyzer
    032 */
    033public class ClusteredSessionImpl extends SessionImpl
    034{
    035    private final SessionPersistedObjectAnalyzer analyzer;
    036
    037    /**
    038     * Cache of attribute objects read from, or written to, the real session.
    039     * This is needed for end-of-request
    040     * processing.
    041     */
    042    private final Map<String, Object> sessionAttributeCache = CollectionFactory.newMap();
    043
    044    public ClusteredSessionImpl(HttpServletRequest request,
    045            HttpSession session,
    046            SessionLock lock, SessionPersistedObjectAnalyzer analyzer)
    047    {
    048        super(request, session, lock);
    049
    050        this.analyzer = analyzer;
    051    }
    052
    053    @Override
    054    public Object getAttribute(String name)
    055    {
    056        Object result = super.getAttribute(name);
    057
    058        sessionAttributeCache.put(name, result);
    059
    060        return result;
    061    }
    062
    063    public void setAttribute(String name, Object value)
    064    {
    065        super.setAttribute(name, value);
    066
    067        sessionAttributeCache.put(name, value);
    068    }
    069
    070    public void invalidate()
    071    {
    072        super.invalidate();
    073
    074        sessionAttributeCache.clear();
    075    }
    076
    077    public void restoreDirtyObjects()
    078    {
    079        if (isInvalidated())
    080        {
    081            return;
    082        }
    083
    084        if (sessionAttributeCache.isEmpty())
    085        {
    086            return;
    087        }
    088
    089        for (Map.Entry<String, Object> entry : sessionAttributeCache.entrySet())
    090        {
    091            String attributeName = entry.getKey();
    092
    093            Object attributeValue = entry.getValue();
    094
    095            if (attributeValue == null)
    096            {
    097                continue;
    098            }
    099
    100            if (analyzer.checkAndResetDirtyState(attributeValue))
    101            {
    102                super.setAttribute(attributeName, attributeValue);
    103            }
    104        }
    105    }
    106}