I have a kata
application, which allows me to be hands-on with various things. This is a web application and sometime back it had the use case of Persisting sessions. The application is a simple webapp running on Jetty, which is configured via the jetty-maven-plugin
. Jetty has good support of session persistance. If you look into the docs, it allows you to perssist session in files, db, mongodb, hazelcast etc. So I went ahead and configured File Persistance.
Jetty has its own DI sytax which is not intutive enough. so to get FilePersistance
working I had take hints to arrive at the following configuration :
<Configure id="webapp" class="org.eclipse.jetty.webapp.WebAppContext">
<Get id="sh" name="sessionHandler">
<Set name="sessionCache">
<New class="org.eclipse.jetty.server.session.DefaultSessionCache">
<Arg><Ref id="sh"/></Arg>
<Set name="sessionDataStore">
<New class="org.eclipse.jetty.server.session.FileSessionDataStore">
<Set name="storeDir">
<New class="java.io.File">
<Arg>/tmp/jetty-sessions</Arg>
</New>
</Set>
</New>
</Set>
</New>
</Set>
</Get>
</Configure
The above configuration can be added to jetty-web.xml
in classpath or the jetty-maven-plugin
can be configured to pick the specific configuration file in the following manner.
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.14.v20181114</version>
<configuration>
<contextXml>${project.build.directory}/classes/jetty.xml</contextXml>
</configuration>
</plugin>
This was fine untill I need to change the store to my Database as I was running 2 nodes and needed to make sure that session information is available. I spent a good amount of time looking at the dtd to get it working. I had to accomplish the follwoing two steps :
- Configure a JNDI datasource for my database
- Configure JDBCSessionDataStore to write using the created JNDI Resource
The major task was to understand how do I need to configure JNDI first. I had to spend some time to understand the difference between Call
and Set
. Also it wasn’t very clear that the xml can have ONLY one Configure
element. Anyways after spending a substantial amout of time I got the following working configuration it place.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
<Set name="contextPath">/</Set>
<!--Set name="war">/home/home/Projects/assessmatic/admin/target/admin.war</Set-->
<Call name="addBean">
<Arg>
<New id="postgres" class="org.eclipse.jetty.plus.jndi.Resource">
<Arg></Arg>
<Arg>/jdbc/sessions</Arg>
<Arg>
<New class="org.postgresql.ds.PGSimpleDataSource">
<Set name="User">postgres</Set>
<Set name="Password">password</Set>
<Set name="DatabaseName">postgres</Set>
<Set name="ServerName">172.17.0.2</Set>
<Set name="PortNumber">5432</Set>
</New>
</Arg>
</New>
</Arg>
</Call>
<Call id="sh" name="getSessionHandler">
<Set name="sessionCache">
<New class="org.eclipse.jetty.server.session.DefaultSessionCache">
<Arg>
<Ref id="sh"/>
</Arg>
<Set name="sessionDataStore">
<New class="org.eclipse.jetty.server.session.JDBCSessionDataStore">
<Set name="gracePeriodSec">
<Property name="jetty.session.gracePeriod.seconds" default="3600"/>
</Set>
<Set name="savePeriodSec">
<Property name="jetty.session.savePeriod.seconds" default="0"/>
</Set>
<Set name="databaseAdaptor">
<New class="org.eclipse.jetty.server.session.DatabaseAdaptor">
<Set name="DatasourceName">
<Property name="jetty.session.jdbc.datasourceName" default="/jdbc/sessions"/>
</Set>
<Set name="blobType">
<Property name="jetty.session.jdbc.blobType"/>
</Set>
<Set name="longType">
<Property name="jetty.session.jdbc.longType"/>
</Set>
<Set name="stringType">
<Property name="jetty.session.jdbc.stringType"/>
</Set>
</New>
</Set>
<Set name="sessionTableSchema">
<New
class="org.eclipse.jetty.server.session.JDBCSessionDataStore$SessionTableSchema">
<Set name="accessTimeColumn">
<Property name="jetty.session.jdbc.schema.accessTimeColumn" default="accessTime"/>
</Set>
<Set name="contextPathColumn">
<Property name="jetty.session.jdbc.schema.contextPathColumn" default="contextPath"/>
</Set>
<Set name="cookieTimeColumn">
<Property name="jetty.session.jdbc.schema.cookieTimeColumn" default="cookieTime"/>
</Set>
<Set name="createTimeColumn">
<Property name="jetty.session.jdbc.schema.createTimeColumn" default="createTime"/>
</Set>
<Set name="expiryTimeColumn">
<Property name="jetty.session.jdbc.schema.expiryTimeColumn" default="expiryTime"/>
</Set>
<Set name="lastAccessTimeColumn">
<Property name="jetty.session.jdbc.schema.lastAccessTimeColumn"
default="lastAccessTime"/>
</Set>
<Set name="lastSavedTimeColumn">
<Property name="jetty.session.jdbc.schema.lastSavedTimeColumn"
default="lastSavedTime"/>
</Set>
<Set name="idColumn">
<Property name="jetty.session.jdbc.schema.idColumn" default="sessionId"/>
</Set>
<Set name="lastNodeColumn">
<Property name="jetty.session.jdbc.schema.lastNodeColumn" default="lastNode"/>
</Set>
<Set name="virtualHostColumn">
<Property name="jetty.session.jdbc.schema.virtualHostColumn" default="virtualHost"/>
</Set>
<Set name="maxIntervalColumn">
<Property name="jetty.session.jdbc.schema.maxIntervalColumn" default="maxInterval"/>
</Set>
<Set name="mapColumn">
<Property name="jetty.session.jdbc.schema.mapColumn" default="map"/>
</Set>
<Set name="tableName">
<Property name="jetty.session.jdbc.schema.table" default="JettySessions"/>
</Set>
</New>
</Set>
</New>
</Set>
</New>
</Set>
</Call>
</Configure>
Now this had a few classpath issues as the plugin is now first creating JNDI resource before loading the application. So I had to add postgres
dependencies to its dependency configuration. Once configured the session persistance works very well.