001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.web.server;
018
019import java.time.Duration;
020import java.time.Instant;
021import java.util.Map;
022
023import reactor.core.publisher.Mono;
024
025import org.springframework.lang.Nullable;
026import org.springframework.util.Assert;
027
028/**
029 * Main contract for using a server-side session that provides access to session
030 * attributes across HTTP requests.
031 *
032 * <p>The creation of a {@code WebSession} instance does not automatically start
033 * a session thus causing the session id to be sent to the client (typically via
034 * a cookie). A session starts implicitly when session attributes are added.
035 * A session may also be created explicitly via {@link #start()}.
036 *
037 * @author Rossen Stoyanchev
038 * @since 5.0
039 */
040public interface WebSession {
041
042        /**
043         * Return a unique session identifier.
044         */
045        String getId();
046
047        /**
048         * Return a map that holds session attributes.
049         */
050        Map<String, Object> getAttributes();
051
052        /**
053         * Return the session attribute value if present.
054         * @param name the attribute name
055         * @param <T> the attribute type
056         * @return the attribute value
057         */
058        @SuppressWarnings("unchecked")
059        @Nullable
060        default <T> T getAttribute(String name) {
061                return (T) getAttributes().get(name);
062        }
063
064        /**
065         * Return the session attribute value or if not present raise an
066         * {@link IllegalArgumentException}.
067         * @param name the attribute name
068         * @param <T> the attribute type
069         * @return the attribute value
070         */
071        @SuppressWarnings("unchecked")
072        default <T> T getRequiredAttribute(String name) {
073                T value = getAttribute(name);
074                Assert.notNull(value, () -> "Required attribute '" + name + "' is missing.");
075                return value;
076        }
077
078        /**
079         * Return the session attribute value, or a default, fallback value.
080         * @param name the attribute name
081         * @param defaultValue a default value to return instead
082         * @param <T> the attribute type
083         * @return the attribute value
084         */
085        @SuppressWarnings("unchecked")
086        default <T> T getAttributeOrDefault(String name, T defaultValue) {
087                return (T) getAttributes().getOrDefault(name, defaultValue);
088        }
089
090        /**
091         * Force the creation of a session causing the session id to be sent when
092         * {@link #save()} is called.
093         */
094        void start();
095
096        /**
097         * Whether a session with the client has been started explicitly via
098         * {@link #start()} or implicitly by adding session attributes.
099         * If "false" then the session id is not sent to the client and the
100         * {@link #save()} method is essentially a no-op.
101         */
102        boolean isStarted();
103
104        /**
105         * Generate a new id for the session and update the underlying session
106         * storage to reflect the new id. After a successful call {@link #getId()}
107         * reflects the new session id.
108         * @return completion notification (success or error)
109         */
110        Mono<Void> changeSessionId();
111
112        /**
113         * Invalidate the current session and clear session storage.
114         * @return completion notification (success or error)
115         */
116        Mono<Void> invalidate();
117
118        /**
119         * Save the session through the {@code WebSessionStore} as follows:
120         * <ul>
121         * <li>If the session is new (i.e. created but never persisted), it must have
122         * been started explicitly via {@link #start()} or implicitly by adding
123         * attributes, or otherwise this method should have no effect.
124         * <li>If the session was retrieved through the {@code WebSessionStore},
125         * the implementation for this method must check whether the session was
126         * {@link #invalidate() invalidated} and if so return an error.
127         * </ul>
128         * <p>Note that this method is not intended for direct use by applications.
129         * Instead it is automatically invoked just before the response is
130         * committed.
131         * @return {@code Mono} to indicate completion with success or error
132         */
133        Mono<Void> save();
134
135        /**
136         * Return {@code true} if the session expired after {@link #getMaxIdleTime()
137         * maxIdleTime} elapsed.
138         * <p>Typically expiration checks should be automatically made when a session
139         * is accessed, a new {@code WebSession} instance created if necessary, at
140         * the start of request processing so that applications don't have to worry
141         * about expired session by default.
142         */
143        boolean isExpired();
144
145        /**
146         * Return the time when the session was created.
147         */
148        Instant getCreationTime();
149
150        /**
151         * Return the last time of session access as a result of user activity such
152         * as an HTTP request. Together with {@link #getMaxIdleTime()
153         * maxIdleTimeInSeconds} this helps to determine when a session is
154         * {@link #isExpired() expired}.
155         */
156        Instant getLastAccessTime();
157
158        /**
159         * Configure the max amount of time that may elapse after the
160         * {@link #getLastAccessTime() lastAccessTime} before a session is considered
161         * expired. A negative value indicates the session should not expire.
162         */
163        void setMaxIdleTime(Duration maxIdleTime);
164
165        /**
166         * Return the maximum time after the {@link #getLastAccessTime()
167         * lastAccessTime} before a session expires. A negative time indicates the
168         * session doesn't expire.
169         */
170        Duration getMaxIdleTime();
171
172}