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;
027import org.jgrapes.http.LanguageSelector.Selection;
028
029/**
030 * Represents a browser session. Session objects are used to store
031 * data related to the browser session. Servers with a small number
032 * of clients usually keep session objects and the associated data
033 * in memory. Servers with a large number of clients may choose to
034 * only keep a LRU cache of session objects in memory and swap
035 * out (persist) other session objects. Therefore the keys and
036 * values stored using a session object must be serializable.
037 * 
038 * Occasionally, data associated with a session object is already
039 * persisted anyway, because its lifetime is beyond that of a session.
040 * To avoid persisting such data twice, the session provides a special
041 * area for "transient data". If components choose to store data
042 * in this area, they must always check before use if the data is
043 * available and recover it if necessary. Using this approach, the
044 * components automatically profit from the LRU caching mechanism
045 * provided by the session manager. As an alternative, components
046 * can use the session {@link #id()} as key to manage the data
047 * on their own.
048 * 
049 * Implementations should override {@link Object#hashCode()}
050 * and {@link Object#equals(Object)} in such a way
051 * that the session id is the only relevant attribute (cannot be
052 * done by default methods of the interface).
053 */
054public interface Session extends Map<Serializable, Serializable> {
055
056    /**
057     * Returns the session id.
058     * 
059     * @return the id
060     */
061    @SuppressWarnings("PMD.ShortMethodName")
062    String id();
063
064    /**
065     * Returns the creation time stamp.
066     * 
067     * @return the creation time stamp
068     */
069    Instant createdAt();
070
071    /**
072     * Returns the last used (referenced in request) time stamp. 
073     * 
074     * @return the last used timestamp
075     */
076    Instant lastUsedAt();
077
078    /**
079     * Updates the last used time stamp.
080     */
081    void updateLastUsedAt();
082
083    /**
084     * Return the storage area for transient data. Usually implemented
085     * by a {@link ConcurrentHashMap}. Other implementations must
086     * at least provide the same support for concurrency as 
087     * {@link ConcurrentHashMap}.
088     * 
089     * @return the storage area
090     */
091    Map<?, ?> transientData();
092
093    /**
094     * Convenience method for retrieving the locale 
095     * set by {@link LanguageSelector} from the session.
096     * 
097     * @return the locale
098     */
099    default Locale locale() {
100        return Optional.ofNullable((Selection) get(Selection.class))
101            .map(selection -> selection.get()[0]).orElse(Locale.getDefault());
102    }
103
104}