Interface SessionStore
-
- All Superinterfaces:
Service
public interface SessionStore extends Service
A persistent store of session data.Ratpack's session support cooperates with the implementation of this type found in the context registry. The
SessionModule
provides a default implementation that stores the data in local memory. In order to persist session data in the store of your choice, simply override the binding for this type with your own implementation.The store methods return
Promise
andOperation
in order to support non blocking IO.The store should not make any attempt to interpret the bytes that it is storing/loading.
Example implementation
Here is an example implementation that uses files on the filesystem to store session data.
import com.google.common.io.Files; import com.google.inject.Singleton; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufInputStream; import io.netty.buffer.ByteBufOutputStream; import io.netty.util.AsciiString; import ratpack.core.service.StartEvent; import ratpack.core.service.StopEvent; import ratpack.exec.Operation; import ratpack.exec.Promise; import ratpack.exec.Blocking; import ratpack.guice.ConfigurableModule; import ratpack.guice.Guice; import ratpack.session.Session; import ratpack.session.SessionModule; import ratpack.session.SessionStore; import ratpack.test.embed.EphemeralBaseDir; import ratpack.test.embed.EmbeddedApp; import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertEquals; public class Example { static class FileSessionStore implements SessionStore { private final ByteBufAllocator bufferAllocator; private final File dir; @Inject public FileSessionStore(ByteBufAllocator bufferAllocator, FileSessionModule.Config config) { this.bufferAllocator = bufferAllocator; this.dir = config.dir; } @Override public void onStart(StartEvent event) throws Exception { Blocking.op(() -> { assert dir.mkdirs() || dir.exists(); }).then(); } @Override public void onStop(StopEvent event) throws Exception { Blocking.op(() -> { Arrays.asList(dir.listFiles()).forEach(File::delete); dir.delete(); }).then(); } @Override public Operation store(AsciiString sessionId, ByteBuf sessionData) { return Blocking.op(() -> Files.asByteSink(file(sessionId)).writeFrom(new ByteBufInputStream(sessionData)) ); } @Override public Promise<ByteBuf> load(AsciiString sessionId) { File sessionFile = file(sessionId); return Blocking.get(() -> { if (sessionFile.exists()) { ByteBuf buffer = bufferAllocator.buffer((int) sessionFile.length()); try { Files.asByteSource(sessionFile).copyTo(new ByteBufOutputStream(buffer)); return buffer; } catch (IOException e) { buffer.release(); throw e; } } else { return bufferAllocator.buffer(0, 0); } }); } private File file(AsciiString sessionId) { return new File(dir, sessionId.toString()); } @Override public Operation remove(AsciiString sessionId) { return Blocking.op(() -> file(sessionId).delete()); } @Override public Promise<Long> size() { return Blocking.get(() -> (long) dir.listFiles(File::isFile).length); } } public static class FileSessionModule extends ConfigurableModule<FileSessionModule.Config> { public static class Config { File dir; } @Override protected void configure() { bind(SessionStore.class).to(FileSessionStore.class).in(Singleton.class); } } public static void main(String... args) throws Exception { EphemeralBaseDir.tmpDir().use(baseDir -> { EmbeddedApp.of(s -> s .registry(Guice.registry(b -> b .module(SessionModule.class) .module(FileSessionModule.class, c -> c.dir = baseDir.getRoot().toFile()) )) .handlers(c -> c .get("set/:name/:value", ctx -> ctx.get(Session.class).getData().then(sessionData -> { sessionData.set(ctx.getPathTokens().get("name"), ctx.getPathTokens().get("value")); ctx.render("ok"); }) ) .get("get/:name", ctx -> ctx.render(ctx.get(Session.class).getData().map(sessionData -> sessionData.require(ctx.getPathTokens().get("name")))) ) ) ).test(httpClient -> { assertEquals("ok", httpClient.getText("set/foo/bar")); assertEquals("bar", httpClient.getText("get/foo")); }); }); } }
- See Also:
SessionModule
-
-
Method Summary
All Methods Instance Methods Abstract Methods Modifier and Type Method Description Promise<io.netty.buffer.ByteBuf>
load(io.netty.util.AsciiString sessionId)
Reads the session data for the given id.Operation
remove(io.netty.util.AsciiString sessionId)
Removes the session data for the given id.Promise<Long>
size()
The current number of sessions.Operation
store(io.netty.util.AsciiString sessionId, io.netty.buffer.ByteBuf sessionData)
Writes the session data for the given id.
-
-
-
Method Detail
-
store
Operation store(io.netty.util.AsciiString sessionId, io.netty.buffer.ByteBuf sessionData)
Writes the session data for the given id.The given byte buffer will not be modified by the caller, and will be released by the caller after the returned operation has completed (with error or without).
- Parameters:
sessionId
- the identifier for the sessionsessionData
- the session data- Returns:
- the store operation
-
load
Promise<io.netty.buffer.ByteBuf> load(io.netty.util.AsciiString sessionId)
Reads the session data for the given id.The caller will release the promised byte buffer.
- Parameters:
sessionId
- the identifier for the session- Returns:
- a promise for the session data
-
remove
Operation remove(io.netty.util.AsciiString sessionId)
Removes the session data for the given id.- Parameters:
sessionId
- the session id- Returns:
- the remove operation
-
-