001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2017-2018 Michael N. Lipp
004 * 
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 * 
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 * 
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.http;
020
021import java.io.Serializable;
022import java.time.Instant;
023import java.util.Locale;
024import java.util.Map;
025import java.util.Optional;
026import java.util.concurrent.ConcurrentHashMap;
027
028import org.jgrapes.http.LanguageSelector.Selection;
029
030/**
031 * Represents a browser session. Session objects are used to store
032 * data related to the browser session. Servers with a small number
033 * of clients usually keep session objects and the associated data
034 * in memory. Servers with a large number of clients may choose to
035 * only keep a LRU cache of session objects in memory and swap
036 * out (persist) other session objects. Therefore the keys and
037 * values stored using a session object must be serializable.
038 * 
039 * Occasionally, data associated with a session object is already
040 * persisted anyway, because its lifetime is beyond that of a session.
041 * To avoid persisting such data twice, the session provides a special
042 * area for "transient data". If components choose to store data
043 * in this area, they must always check before use if the data is
044 * available and recover it if necessary. Using this approach, the
045 * components automatically profit from the LRU caching mechanism
046 * provided by the session manager. As an alternative, components
047 * can use the session {@link #id()} as key to manage the data
048 * on their own.
049 * 
050 * Implementations should override {@link Object#hashCode()}
051 * and {@link Object#equals(Object)} in such a way
052 * that the session id is the only relevant attribute (cannot be
053 * done by default methods of the interface).
054 */
055public interface Session extends Map<Serializable, Serializable> {
056
057    /**
058     * Returns the session id.
059     * 
060     * @return the id
061     */
062    @SuppressWarnings("PMD.ShortMethodName")
063    String id();
064
065    /**
066     * Returns the creation time stamp.
067     * 
068     * @return the creation time stamp
069     */
070    Instant createdAt();
071
072    /**
073     * Returns the last used (referenced in request) time stamp. 
074     * 
075     * @return the last used timestamp
076     */
077    Instant lastUsedAt();
078
079    /**
080     * Updates the last used time stamp.
081     */
082    void updateLastUsedAt();
083
084    /**
085     * Return the storage area for transient data. Usually implemented
086     * by a {@link ConcurrentHashMap}. Other implementations must
087     * at least provide the same support for concurrency as 
088     * {@link ConcurrentHashMap}.
089     * 
090     * @return the storage area
091     */
092    Map<?, ?> transientData();
093
094    /**
095     * Convenience method for retrieving the locale 
096     * set by {@link LanguageSelector} from the session.
097     * 
098     * @return the locale
099     */
100    default Locale locale() {
101        return Optional.ofNullable((Selection) get(Selection.class))
102            .map(selection -> selection.get()[0]).orElse(Locale.getDefault());
103    }
104
105}