    001// Copyright 2006-2013 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 java.util.Collections;
    018import java.util.Enumeration;
    019import java.util.List;
    020import java.util.Objects;
    021
    022import org.apache.tapestry5.commons.util.CollectionFactory;
    023import org.apache.tapestry5.http.services.Session;
    024import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    025
    026import javax.servlet.http.HttpServletRequest;
    027import javax.servlet.http.HttpSession;
    028
    029/**
    030 * A thin wrapper around {@link HttpSession}.
    031 */
    032public class SessionImpl implements Session
    033{
    034    private final HttpServletRequest request;
    035
    036    private final HttpSession session;
    037
    038    private boolean invalidated = false;
    039
    040    private final SessionLock lock;
    041
    042    public SessionImpl(HttpServletRequest request, HttpSession session, SessionLock lock)
    043    {
    044        this.request = request;
    045        this.session = session;
    046        this.lock = lock;
    047    }
    048
    049    @Override
    050    public Object getAttribute(String name)
    051    {
    052        return getAttribute(name, Session.LockMode.WRITE);
    053    }
    054
    055    @Override
    056    public Object getAttribute(String name, Session.LockMode lockMode)
    057    {
    058        Objects.requireNonNull(name, "name must be non-null");
    059
    060        // If a WRITE lock is requested, check first if the key exists
    061        // to prevent a lock upgrade if not necessary.
    062        if (lockMode == null || lockMode == Session.LockMode.WRITE)
    063        {
    064            if (!containsAttribute(name)) return null;
    065        }
    066
    067        acquireLock(lockMode, Session.LockMode.WRITE);
    068
    069        return session.getAttribute(name);
    070    }
    071
    072    @Override
    073    public List<String> getAttributeNames()
    074    {
    075        return getAttributeNames(Session.LockMode.READ);
    076    }
    077
    078    @Override
    079    public List<String> getAttributeNames(Session.LockMode lockMode)
    080    {
    081        acquireLock(lockMode, Session.LockMode.READ);
    082
    083        return InternalUtils.toList(session.getAttributeNames());
    084    }
    085
    086    @Override
    087    public void setAttribute(String name, Object value)
    088    {
    089        Objects.requireNonNull(name, "name must be non-null");
    090
    091        lock.acquireWriteLock();
    092
    093        session.setAttribute(name, value);
    094    }
    095
    096    @Override
    097    public boolean containsAttribute(String name)
    098    {
    099        return containsAttribute(name, Session.LockMode.READ);
    100    }
    101
    102    @Override
    103    public boolean containsAttribute(String name, Session.LockMode lockMode)
    104    {
    105        Objects.requireNonNull(name, "name must be non-null");
    106
    107        acquireLock(lockMode, Session.LockMode.READ);
    108
    109        Enumeration<String> e = session.getAttributeNames();
    110        while (e.hasMoreElements())
    111        {
    112            String attrName = e.nextElement();
    113            if (attrName.equals(name)) return true;
    114        }
    115
    116        return false;
    117    }
    118
    119    @Override
    120    public List<String> getAttributeNames(String prefix)
    121    {
    122        return getAttributeNames(prefix, Session.LockMode.READ);
    123    }
    124
    125    @Override
    126    public List<String> getAttributeNames(String prefix, Session.LockMode lockMode)
    127    {
    128        Objects.requireNonNull(prefix, "prefix must be non-null");
    129
    130        acquireLock(lockMode, Session.LockMode.READ);
    131
    132        List<String> result = CollectionFactory.newList();
    133
    134        Enumeration<String> e = session.getAttributeNames();
    135        while (e.hasMoreElements())
    136        {
    137            String name = e.nextElement();
    138
    139            if (name.startsWith(prefix)) result.add(name);
    140        }
    141
    142        Collections.sort(result);
    143
    144        return result;
    145    }
    146
    147    @Override
    148    public int getMaxInactiveInterval()
    149    {
    150        return session.getMaxInactiveInterval();
    151    }
    152
    153    @Override
    154    public void invalidate()
    155    {
    156        invalidated = true;
    157
    158        session.invalidate();
    159    }
    160
    161    @Override
    162    public boolean isInvalidated()
    163    {
    164        if (invalidated) return true;
    165
    166        // The easy case is when the session was invalidated through the Tapestry Session
    167        // object. The hard case is when the HttpSession was invalidated outside of Tapestry,
    168        // in which case, request.getSession() will return a new HttpSession instance (or null)
    169
    170        invalidated = request.getSession(false) != session;
    171
    172        return invalidated;
    173    }
    174
    175    @Override
    176    public void setMaxInactiveInterval(int seconds)
    177    {
    178        session.setMaxInactiveInterval(seconds);
    179    }
    180
    181    @Override
    182    public void restoreDirtyObjects()
    183    {
    184
    185    }
    186
    187    private void acquireLock(Session.LockMode requestedMode, Session.LockMode defaultMode) {
    188        if (requestedMode == null)
    189        {
    190            requestedMode = defaultMode;
    191        }
    192
    193        switch (requestedMode)
    194        {
    195            case NONE:
    196                break;
    197            case READ:
    198                this.lock.acquireReadLock();
    199                break;
    200            case WRITE:
    201                this.lock.acquireWriteLock();
    202                break;
    203        }
    204    }
    205}