/* * Copyright 2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package ratpack.session; import ratpack.exec.Operation; import java.io.Serializable; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; /** * The data associated with the user session. * <p> * The session data can be obtained via the {@link Session#getData()} method. * <p> * Every item is stored with a {@link SessionKey}. * A key is comprised of a type (as a {@code Class}) and an optional name. * The combination of type and name identifies the value. * Two keys with differing types but identical names are not considered to be equivalent. * <p> * When writing session data, the values are serialized immediately. * That is, all objects are treated as immutable value objects from the perspective of this object. * Any changes made to an object after it has been written to this object will <b>NOT</b> be persisted. * If such changes are to be persisted, the object must be written again. * <p> * If a {@link SessionSerializer} is not provided for a given get/set, the {@link #getDefaultSerializer()} will be used. * The {@link SessionModule} provides a default implementation based on Java serialization. * An alternative implementation can be used by overriding the Guice binding for {@link SessionSerializer}. * <p> * The session data is held in memory for a given request until the {@link Session#save()} method is called on the corresponding session. * However, this object internally holds the data in serialized form. * Therefore, every read and write incurs the cost of serialization and deserialization. */ public interface SessionData { /** * The keys of all objects currently in the session. * * @return the keys of all objects currently in the session */ Set<SessionKey<?>> getKeys(); /** * Fetch the object with the given key, using the {@link #getDefaultSerializer() default serializer}. * * @param key the key * @param <T> the type of object * @return the value for the given key * @see #require(SessionKey) */ default <T> Optional<T> get(SessionKey<T> key) throws Exception { return get(key, getDefaultSerializer()); } /** * Read the object with the given key. * * @param key the key * @param serializer the serializer * @param <T> the type of object * @return the value for the given key * @see #require(SessionKey, SessionSerializer) */ <T> Optional<T> get(SessionKey<T> key, SessionSerializer serializer) throws Exception; /** * Read the object with the given name, using the {@link #getDefaultSerializer() default serializer}. * <p> * This method will throw an {@link IllegalArgumentException} if there is more than one object who's key has the given name. * * @param name the object name * @return the value for the given key * @see #require(String) */ default Optional<?> get(String name) throws Exception { return get(SessionKey.of(name)); } /** * Read the object with the given name. * <p> * This method will throw an {@link IllegalArgumentException} if there is more than one object who's key has the given name. * * @param name the object name * @param serializer the serializer * @return the value for the given key * @see #require(String, SessionSerializer) */ default Optional<?> get(String name, SessionSerializer serializer) throws Exception { return get(SessionKey.of(name), serializer); } /** * Read the object with the given type, and no name, using the {@link #getDefaultSerializer() default serializer}. * * @param type the type * @param <T> the type * @return the value for the given key * @see #require(Class) */ default <T> Optional<T> get(Class<T> type) throws Exception { return get(SessionKey.of(type)); } /** * Read the object with the given type, and no name. * * @param type the type * @param serializer the serializer * @param <T> the type * @return the value for the given key * @see #require(Class, SessionSerializer) */ default <T> Optional<T> get(Class<T> type, SessionSerializer serializer) throws Exception { return get(SessionKey.of(type), serializer); } /** * Like {@link #get(SessionKey)}, but throws {@link NoSuchElementException} on the absence of a value. * * @param key the object key * @param <T> the type * @return the value for the given key */ default <T> T require(SessionKey<T> key) throws Exception { return require(key, getDefaultSerializer()); } /** * Like {@link #get(SessionKey, SessionSerializer)}, but throws {@link NoSuchElementException} on the absence of a value. * * @param key the object key * @param serializer the serializer * @param <T> the type * @return the value for the given key */ default <T> T require(SessionKey<T> key, SessionSerializer serializer) throws Exception { return get(key, serializer).orElseThrow(() -> new NoSuchElementException("No object for " + key + " in session")); } /** * Like {@link #get(Class)}, but throws {@link NoSuchElementException} on the absence of a value. * * @param type the type * @param <T> the type * @return the value for the given key */ default <T> T require(Class<T> type) throws Exception { return require(SessionKey.of(type)); } /** * Like {@link #get(Class, SessionSerializer)}, but throws {@link NoSuchElementException} on the absence of a value. * * @param type the type * @param serializer the serializer * @param <T> the type * @return the value for the given key */ default <T> T require(Class<T> type, SessionSerializer serializer) throws Exception { return require(SessionKey.of(type), serializer); } /** * Like {@link #get(String)}, but throws {@link NoSuchElementException} on the absence of a value. * <p> * This method will throw an {@link IllegalArgumentException} if there is more than one object who's key has the given name. * * @param name the object name * @return the value for the given key */ default Object require(String name) throws Exception { return require(SessionKey.of(name)); } /** * Like {@link #get(String, SessionSerializer)}, but throws {@link NoSuchElementException} on the absence of a value. * <p> * This method will throw an {@link IllegalArgumentException} if there is more than one object who's key has the given name. * * @param name the object name * @param serializer the serializer * @return the value for the given key */ default Object require(String name, SessionSerializer serializer) throws Exception { return require(SessionKey.of(name), serializer); } /** * Sets the value for the given key, using the {@link #getDefaultSerializer() default serializer}. * * @param key the key * @param value the value * @param <T> the type */ default <T> void set(SessionKey<T> key, T value) throws Exception { set(key, value, getDefaultSerializer()); } /** * Sets the value for the given key. * * @param key the key * @param value the value * @param serializer the serializer * @param <T> the type */ <T> void set(SessionKey<T> key, T value, SessionSerializer serializer) throws Exception; /** * Sets the value for the given type, using the {@link #getDefaultSerializer() default serializer}. * * @param type the type * @param value the value * @param <T> the type */ default <T> void set(Class<T> type, T value) throws Exception { set(SessionKey.of(type), value); } /** * Sets the value for the given type. * * @param type the type * @param value the value * @param serializer the serializer * @param <T> the type */ default <T> void set(Class<T> type, T value, SessionSerializer serializer) throws Exception { set(SessionKey.of(type), value, serializer); } /** * Sets the value for the given name and type, using the runtime type of the value and the {@link #getDefaultSerializer() default serializer}. * * @param name the name * @param value the value * @param <T> the type */ default <T> void set(String name, T value) throws Exception { set(SessionKey.ofType(name, value), value, getDefaultSerializer()); } /** * Sets the value for the given name and type, using the runtime type of the value. * * @param name the name * @param value the value * @param serializer the serializer * @param <T> the type */ default <T> void set(String name, T value, SessionSerializer serializer) throws Exception { set(SessionKey.ofType(name, value), value, serializer); } /** * Sets the value for the type, using the runtime type of the value and the {@link #getDefaultSerializer() default serializer}. * * @param value the value * @param <T> the type */ default <T> void set(T value) throws Exception { set(SessionKey.ofType(value), value, getDefaultSerializer()); } /** * Sets the value for the type, using the runtime type of the value. * * @param value the value * @param serializer the serializer * @param <T> the type */ default <T> void set(T value, SessionSerializer serializer) throws Exception { set(SessionKey.ofType(value), value, serializer); } /** * Removes the object with the given key, if it exists. * * @param key the key */ void remove(SessionKey<?> key); /** * Removes the object with the given type and no name, if it exists. * * @param type the type */ default void remove(Class<?> type) { remove(SessionKey.of(type)); } /** * Removes the object with the name, if it exists. * <p> * This method will throw a {@link NoSuchElementException} if there are more than one entries with the given name. * * @param name the name */ default void remove(String name) { remove(SessionKey.of(name)); } /** * Remove all entries from the session data. */ void clear(); /** * The corresponding {@link Session} object. * * @return the session object */ Session getSession(); /** * See {@link Session#isDirty()}. * * @return whether or not any changes have been made to the session data since it was accessed */ default boolean isDirty() { return getSession().isDirty(); } /** * See {@link Session#save()}. * * @return the save operation */ default Operation save() { return getSession().save(); } /** * See {@link Session#terminate()}. * * @return the terminate operation */ default Operation terminate() { return getSession().terminate(); } /** * See {@link Session#getDefaultSerializer()}. * * @return the serializer to use by default */ default SessionSerializer getDefaultSerializer() { return getSession().getDefaultSerializer(); } /** * See {@link Session#getJavaSerializer()}. * * @return a serializer for {@link Serializable} objects */ default JavaSessionSerializer getJavaSerializer() { return getSession().getJavaSerializer(); } }