You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by je...@apache.org on 2015/12/29 22:11:02 UTC
[08/24] incubator-geode git commit: GEODE-14: Move GemFire Sessions
module and relocate all packages to 'internal'
GEODE-14: Move GemFire Sessions module and relocate all packages to 'internal'
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/92ee6a79
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/92ee6a79
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/92ee6a79
Branch: refs/heads/feature/GEODE-14
Commit: 92ee6a7917e2fc37586984ec295a7198d4eb088d
Parents: ed3be77
Author: Jens Deppe <jd...@pivotal.io>
Authored: Mon Dec 28 07:46:37 2015 -0800
Committer: Jens Deppe <jd...@pivotal.io>
Committed: Mon Dec 28 07:46:37 2015 -0800
----------------------------------------------------------------------
extensions/gemfire-modules-session/build.gradle | 4 +
extensions/gemfire-modules-session/pom.xml | 46 +
.../release/bin/cacheserver.bat | 33 +
.../release/bin/cacheserver.sh | 33 +
.../release/bin/gemfire.bat | 23 +
.../release/bin/gemfire.sh | 41 +
.../release/bin/setenv.properties | 6 +
.../release/conf/cache-client.xml | 25 +
.../release/conf/cache-peer.xml | 33 +
.../release/conf/cache-server.xml | 59 +
.../internal/common/AbstractSessionCache.java | 92 ++
.../session/internal/common/CacheProperty.java | 56 +
.../common/ClientServerSessionCache.java | 176 ++
.../internal/common/PeerToPeerSessionCache.java | 174 ++
.../session/internal/common/SessionCache.java | 59 +
.../common/SessionExpirationCacheListener.java | 43 +
.../session/internal/filter/Constants.java | 14 +
.../session/internal/filter/ContextManager.java | 95 ++
.../internal/filter/DummySessionManager.java | 127 ++
.../internal/filter/GemfireHttpSession.java | 517 ++++++
.../filter/GemfireSessionException.java | 36 +
.../internal/filter/GemfireSessionManager.java | 502 ++++++
.../internal/filter/ListenerEventType.java | 70 +
.../session/internal/filter/SessionManager.java | 101 ++
.../AbstractDeltaSessionAttributes.java | 97 ++
.../attributes/AbstractSessionAttributes.java | 179 ++
.../internal/filter/attributes/DeltaEvent.java | 109 ++
.../DeltaQueuedSessionAttributes.java | 84 +
.../attributes/DeltaSessionAttributes.java | 65 +
.../attributes/ImmediateSessionAttributes.java | 58 +
.../attributes/QueuedSessionAttributes.java | 55 +
.../filter/attributes/SessionAttributes.java | 111 ++
.../filter/util/NamedThreadFactory.java | 59 +
.../filter/util/ThreadLocalSession.java | 29 +
.../internal/filter/util/TypeAwareMap.java | 45 +
.../session/internal/jmx/SessionStatistics.java | 69 +
.../internal/jmx/SessionStatisticsMXBean.java | 14 +
.../src/test/resources/log4j.properties | 12 +
.../session/filter/SessionCachingFilter.java | 639 -------
.../modules/session/filter/SessionListener.java | 41 -
.../modules/session/installer/Installer.java | 4 +-
.../internal/filter/SessionCachingFilter.java | 639 +++++++
.../internal/filter/SessionListener.java | 41 +
.../session/filter/AbstractListener.java | 52 -
.../modules/session/filter/Callback.java | 17 -
.../modules/session/filter/CallbackServlet.java | 88 -
.../modules/session/filter/CommonTests.java | 583 -------
.../session/filter/GemfireCacheTest.java | 46 -
.../session/filter/GemfireLocalCacheTest.java | 67 -
.../HttpSessionAttributeListenerImpl.java | 37 -
.../filter/HttpSessionBindingListenerImpl.java | 40 -
.../session/filter/HttpSessionListenerImpl.java | 35 -
.../session/filter/RendezvousManager.java | 37 -
.../ServletRequestAttributeListenerImpl.java | 42 -
.../filter/ServletRequestListenerImpl.java | 36 -
.../session/filter/SessionTestSuite1.java | 69 -
.../session/filter/SessionTestSuite2.java | 68 -
.../session/filter/SessionUberSuite.java | 40 -
.../internal/filter/AbstractListener.java | 52 +
.../session/internal/filter/Callback.java | 17 +
.../internal/filter/CallbackServlet.java | 88 +
.../session/internal/filter/CommonTests.java | 582 +++++++
.../internal/filter/GemfireCacheTest.java | 46 +
.../internal/filter/GemfireLocalCacheTest.java | 62 +
.../HttpSessionAttributeListenerImpl.java | 37 +
.../filter/HttpSessionBindingListenerImpl.java | 40 +
.../filter/HttpSessionListenerImpl.java | 33 +
.../internal/filter/RendezvousManager.java | 37 +
.../ServletRequestAttributeListenerImpl.java | 40 +
.../filter/ServletRequestListenerImpl.java | 34 +
.../internal/filter/SessionTestSuite1.java | 69 +
.../internal/filter/SessionTestSuite2.java | 68 +
.../internal/filter/SessionUberSuite.java | 30 +
.../session/filter/AbstractListener.java | 50 -
.../modules/session/filter/BasicServlet.java | 46 -
.../modules/session/filter/Callback.java | 26 -
.../session/filter/HttpSessionListenerImpl.java | 39 -
.../filter/HttpSessionListenerImpl2.java | 39 -
.../modules/session/filter/IntegrationTest.java | 1552 ------------------
.../modules/session/filter/MyServletTester.java | 33 -
.../filter/ServletContextListenerImpl.java | 48 -
.../internal/filter/AbstractListener.java | 50 +
.../session/internal/filter/BasicServlet.java | 46 +
.../session/internal/filter/Callback.java | 26 +
.../filter/HttpSessionListenerImpl.java | 39 +
.../filter/HttpSessionListenerImpl2.java | 39 +
.../internal/filter/IntegrationTest.java | 1552 ++++++++++++++++++
.../internal/filter/MyServletTester.java | 33 +
.../filter/ServletContextListenerImpl.java | 46 +
modules/gemfire-modules-session/build.gradle | 3 -
modules/gemfire-modules-session/pom.xml | 46 -
modules/gemfire-modules-session/profiles.xml | 18 -
.../release/bin/cacheserver.bat | 33 -
.../release/bin/cacheserver.sh | 33 -
.../release/bin/gemfire.bat | 23 -
.../release/bin/gemfire.sh | 41 -
.../release/bin/setenv.properties | 6 -
.../release/conf/cache-client.xml | 25 -
.../release/conf/cache-peer.xml | 33 -
.../release/conf/cache-server.xml | 59 -
.../session/common/AbstractSessionCache.java | 92 --
.../modules/session/common/CacheProperty.java | 56 -
.../common/ClientServerSessionCache.java | 176 --
.../session/common/PeerToPeerSessionCache.java | 174 --
.../modules/session/common/SessionCache.java | 59 -
.../common/SessionExpirationCacheListener.java | 43 -
.../modules/session/filter/Constants.java | 14 -
.../modules/session/filter/ContextManager.java | 95 --
.../session/filter/DummySessionManager.java | 128 --
.../session/filter/GemfireHttpSession.java | 517 ------
.../session/filter/GemfireSessionException.java | 36 -
.../session/filter/GemfireSessionManager.java | 503 ------
.../session/filter/ListenerEventType.java | 70 -
.../modules/session/filter/SessionManager.java | 101 --
.../AbstractDeltaSessionAttributes.java | 97 --
.../attributes/AbstractSessionAttributes.java | 179 --
.../session/filter/attributes/DeltaEvent.java | 109 --
.../DeltaQueuedSessionAttributes.java | 84 -
.../attributes/DeltaSessionAttributes.java | 65 -
.../attributes/ImmediateSessionAttributes.java | 63 -
.../attributes/QueuedSessionAttributes.java | 60 -
.../filter/attributes/SessionAttributes.java | 111 --
.../session/filter/util/NamedThreadFactory.java | 59 -
.../session/filter/util/ThreadLocalSession.java | 29 -
.../session/filter/util/TypeAwareMap.java | 45 -
.../modules/session/jmx/SessionStatistics.java | 69 -
.../session/jmx/SessionStatisticsMXBean.java | 14 -
.../src/test/resources/log4j.properties | 12 -
settings.gradle | 1 +
129 files changed, 7100 insertions(+), 7152 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/build.gradle
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/build.gradle b/extensions/gemfire-modules-session/build.gradle
new file mode 100644
index 0000000..156f204
--- /dev/null
+++ b/extensions/gemfire-modules-session/build.gradle
@@ -0,0 +1,4 @@
+dependencies {
+ compile project(':extensions/gemfire-modules')
+ compile project(':gemfire-core')
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/pom.xml b/extensions/gemfire-modules-session/pom.xml
new file mode 100644
index 0000000..b274ab3
--- /dev/null
+++ b/extensions/gemfire-modules-session/pom.xml
@@ -0,0 +1,46 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.gemstone</groupId>
+ <artifactId>gemfire-modules-session</artifactId>
+ <packaging>jar</packaging>
+ <version>${gemfire.modules.version}</version>
+ <url>http://maven.apache.org</url>
+ <name>gemfire-modules-session</name>
+
+ <parent>
+ <groupId>com.gemstone</groupId>
+ <artifactId>gemfire-modules-parent</artifactId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.gemstone</groupId>
+ <artifactId>gemfire-modules</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.gemstone.gemfire</groupId>
+ <artifactId>gemfire</artifactId>
+ </dependency>
+
+ <!--<dependency>-->
+ <!--<groupId>org.slf4j</groupId>-->
+ <!--<artifactId>slf4j-log4j12</artifactId>-->
+ <!--<scope>compile</scope>-->
+ <!--</dependency>-->
+
+ </dependencies>
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/bin/cacheserver.bat
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/bin/cacheserver.bat b/extensions/gemfire-modules-session/release/bin/cacheserver.bat
new file mode 100755
index 0000000..2632dc7
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/bin/cacheserver.bat
@@ -0,0 +1,33 @@
+@setlocal enableextensions
+@set scriptdir=%~dp0
+@set gf=%scriptdir:\bin\=%
+@if exist "%gf%\lib\gemfire.jar" @goto gfok
+@echo Could not determine GEMFIRE location
+@verify other 2>nul
+@goto done
+:gfok
+
+@REM Initialize classpath
+
+@REM Add GemFire classes
+@set GEMFIRE_JARS=%gf%/lib/gemfire.jar;%gf%/lib/antlr.jar;%gf%/lib/mail.jar
+
+@REM Add Tomcat classes
+@set GEMFIRE_JARS=%GEMFIRE_JARS%;%gf%/lib/servlet-api.jar;%gf%/lib/catalina.jar;%gf%/lib/${artifact.artifactId}-${artifact.version}.jar;%gf%/bin/tomcat-juli.jar
+
+@REM Add conf directory
+@set GEMFIRE_JARS=%GEMFIRE_JARS%;%gf%/conf
+
+@if defined CLASSPATH set GEMFIRE_JARS=%GEMFIRE_JARS%;%CLASSPATH%
+
+@if not defined GF_JAVA (
+@REM %GF_JAVA% is not defined, assume it is on the PATH
+@set GF_JAVA=java
+)
+
+@"%GF_JAVA%" %JAVA_ARGS% -classpath "%GEMFIRE_JARS%" com.gemstone.gemfire.internal.cache.CacheServerLauncher %*
+:done
+@set scriptdir=
+@set gf=
+@set GEMFIRE_JARS=
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/bin/cacheserver.sh
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/bin/cacheserver.sh b/extensions/gemfire-modules-session/release/bin/cacheserver.sh
new file mode 100755
index 0000000..e395001
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/bin/cacheserver.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Set GEMFIRE to the product toplevel directory
+GEMFIRE=`dirname $0`
+OLDPWD=$PWD
+cd $GEMFIRE
+GEMFIRE=`dirname $PWD`
+cd $OLDPWD
+
+if [ "x$WINDIR" != "x" ]; then
+ echo "ERROR: The variable WINDIR is set indicating this script is running in a Windows OS, please use the .bat file version instead."
+ exit 1
+fi
+
+GEMFIRE_JARS=$GEMFIRE/lib/gemfire-[0-9]*.jar
+if [ ! -f ${GEMFIRE_JARS} ]; then
+ echo "ERROR: Could not determine GEMFIRE location."
+ exit 1
+fi
+
+# Initialize classpath
+GEMFIRE_JARS=$GEMFIRE_JARS:$GEMFIRE/lib/gemfire-modules-[0-9]*
+GEMFIRE_JARS=$GEMFIRE_JARS:$GEMFIRE/lib/servlet-api-[0-9]*
+GEMFIRE_JARS=$GEMFIRE_JARS:$GEMFIRE/lib/slf4j-api-[0-9]*
+GEMFIRE_JARS=$GEMFIRE_JARS:$GEMFIRE/lib/slf4j-jdk14-[0-9]*
+
+# Add configuration
+GEMFIRE_JARS=$GEMFIRE_JARS:$GEMFIRE/conf
+
+if [ "x$CLASSPATH" != "x" ]; then
+ GEMFIRE_JARS=$GEMFIRE_JARS:$CLASSPATH
+fi
+
+${GF_JAVA:-java} ${JAVA_ARGS} -classpath ${GEMFIRE_JARS} com.gemstone.gemfire.internal.cache.CacheServerLauncher "$@"
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/bin/gemfire.bat
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/bin/gemfire.bat b/extensions/gemfire-modules-session/release/bin/gemfire.bat
new file mode 100755
index 0000000..96d2564
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/bin/gemfire.bat
@@ -0,0 +1,23 @@
+@setlocal enableextensions
+@set scriptdir=%~dp0
+@set gf=%scriptdir:\bin\=%
+@if exist "%gf%\lib\gemfire.jar" @goto gfok
+@echo Could not determine GEMFIRE location
+@verify other 2>nul
+@goto done
+:gfok
+
+@set GEMFIRE_JARS=%gf%/lib/gemfire.jar;%gf%/lib/antlr.jar;%gf%/lib/mail.jar
+@if defined CLASSPATH set GEMFIRE_JARS=%GEMFIRE_JARS%;%CLASSPATH%
+
+@if not defined GF_JAVA (
+@REM %GF_JAVA% is not defined, assume it is on the PATH
+@set GF_JAVA=java
+)
+
+@"%GF_JAVA%" %JAVA_ARGS% -classpath "%GEMFIRE_JARS%" com.gemstone.gemfire.internal.SystemAdmin %*
+:done
+@set scriptdir=
+@set gf=
+@set GEMFIRE_JARS=
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/bin/gemfire.sh
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/bin/gemfire.sh b/extensions/gemfire-modules-session/release/bin/gemfire.sh
new file mode 100755
index 0000000..fa5f4cd
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/bin/gemfire.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+# Set GEMFIRE to the product toplevel directory
+GEMFIRE=`dirname $0`
+OLDPWD=$PWD
+cd $GEMFIRE
+GEMFIRE=`dirname $PWD`
+cd $OLDPWD
+
+if [ "x$WINDIR" != "x" ]; then
+ echo "ERROR: The variable WINDIR is set indicating this script is running in a Windows OS, please use the .bat file version instead."
+ exit 1
+fi
+
+if [ ! -f $GEMFIRE/lib/gemfire.jar ]; then
+ echo "ERROR: Could not determine GEMFIRE location."
+ exit 1
+fi
+
+GEMFIRE_JARS=$GEMFIRE/lib/gemfire.jar:$GEMFIRE/lib/antlr.jar
+
+if [ "x$CLASSPATH" != "x" ]; then
+ GEMFIRE_JARS=$GEMFIRE_JARS:$CLASSPATH
+fi
+
+# Command line args that start with -J will be passed to the java vm in JARGS.
+# See java --help for a listing of valid vm args.
+# Example: -J-Xmx1g sets the max heap size to 1 gigabyte.
+
+JARGS=
+GEMFIRE_ARGS=
+for i in "$@"
+do
+ if [ "-J" == "${i:0:2}" ]
+ then
+ JARGS="${JARGS} \"${i#-J}\""
+ else
+ GEMFIRE_ARGS="${GEMFIRE_ARGS} \"${i}\""
+ fi
+done
+
+eval ${GF_JAVA:-java} ${JAVA_ARGS} ${JARGS} -classpath ${GEMFIRE_JARS} com.gemstone.gemfire.internal.SystemAdmin ${GEMFIRE_ARGS}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/bin/setenv.properties
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/bin/setenv.properties b/extensions/gemfire-modules-session/release/bin/setenv.properties
new file mode 100644
index 0000000..fc8918b
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/bin/setenv.properties
@@ -0,0 +1,6 @@
+java.opt.1=-Xms${initial.vm.heap.size.mb:512}M
+java.opt.2=-Xmx${maximum.vm.heap.size.mb:512}M
+java.opt.hotspot.1=-XX:+UseParNewGC
+java.opt.hotspot.2=-XX:+UseConcMarkSweepGC
+java.opt.hotspot.3=-XX:CMSInitiatingOccupancyFraction=${cms.initiating.heap.percentage:50}
+java.opt.j9.1=-Xgcpolicy:gencon
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/conf/cache-client.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/conf/cache-client.xml b/extensions/gemfire-modules-session/release/conf/cache-client.xml
new file mode 100755
index 0000000..c8444b2
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/conf/cache-client.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE client-cache PUBLIC
+ "-//GemStone Systems, Inc.//GemFire Declarative Caching 6.5//EN"
+ "http://www.gemstone.com/dtd/cache6_6.dtd">
+
+<client-cache>
+
+ <!-- The default pool connects to a cache server running on localhost at
+ port 40404. To connect to a different server host and port, modify
+ the following pool server host and port. -->
+ <pool name="sessions" subscription-enabled="true">
+ <server host="localhost" port="40404"/>
+ </pool>
+
+ <!-- To configure the client to use a locator instead of a server, replace
+ the server pool above with the locator pool below and modify the locator
+ host and port as necessary. -->
+ <!--
+ <pool name="sessions" subscription-enabled="true">
+ <locator host="localhost" port="10334"/>
+ </pool>
+ -->
+
+</client-cache>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/conf/cache-peer.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/conf/cache-peer.xml b/extensions/gemfire-modules-session/release/conf/cache-peer.xml
new file mode 100755
index 0000000..1a49637
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/conf/cache-peer.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE cache PUBLIC
+ "-//GemStone Systems, Inc.//GemFire Declarative Caching 6.5//EN"
+ "http://www.gemstone.com/dtd/cache6_6.dtd">
+
+<cache>
+
+ <!-- Uncomment the following disk-store element to modify the default disk store directory -->
+ <!--
+ <disk-store name="DEFAULT">
+ <disk-dirs>
+ <disk-dir>/path/to/persistent/data</disk-dir>
+ </disk-dirs>
+ </disk-store>
+ -->
+
+ <!-- This is the definition of the default session region -->
+ <!--
+ <region name="gemfire_modules_sessions">
+ <region-attributes scope="distributed-ack" enable-gateway="false" data-policy="replicate" statistics-enabled="true">
+ <entry-idle-time>
+ <expiration-attributes timeout="0" action="invalidate">
+ <custom-expiry>
+ <class-name>com.gemstone.gemfire.modules.util.SessionCustomExpiry</class-name>
+ </custom-expiry>
+ </expiration-attributes>
+ </entry-idle-time>
+ </region-attributes>
+ </region>
+ -->
+
+</cache>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/release/conf/cache-server.xml
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/release/conf/cache-server.xml b/extensions/gemfire-modules-session/release/conf/cache-server.xml
new file mode 100755
index 0000000..6ee2223
--- /dev/null
+++ b/extensions/gemfire-modules-session/release/conf/cache-server.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE cache PUBLIC
+ "-//GemStone Systems, Inc.//GemFire Declarative Caching 6.5//EN"
+ "http://www.gemstone.com/dtd/cache6_6.dtd">
+
+<cache>
+
+ <!-- Uncomment the following gateway-hub element to create a gateway hub -->
+ <!--
+ <gateway-hub id="NY" port="11110">
+ <gateway id="LN">
+ <gateway-endpoint id="LN-1" host="localhost" port="22220"/>
+ <gateway-queue disk-store-name="NY_GATEWAY"/>
+ </gateway>
+ </gateway-hub>
+ -->
+
+ <!-- Uncomment the following cache-server element to modify the listen port -->
+ <!--
+ <cache-server port="44444"/>
+ -->
+
+ <!-- Uncomment the following disk-store element to modify the default disk store directory -->
+ <!--
+ <disk-store name="DEFAULT">
+ <disk-dirs>
+ <disk-dir>/path/to/persistent/data</disk-dir>
+ </disk-dirs>
+ </disk-store>
+ -->
+
+ <!-- Uncomment the following disk-store element to create the NY_GATEWAY disk store
+ (for the gateway-hub element defined above) -->
+ <!--
+ <disk-store name="NY_GATEWAY">
+ <disk-dirs>
+ <disk-dir>/path/to/persistent/data</disk-dir>
+ </disk-dirs>
+ </disk-store>
+ -->
+
+ <!-- This is the definition of the default session region -->
+ <!--
+ <region name="gemfire_modules_sessions">
+ <region-attributes enable-gateway="false" data-policy="partition" statistics-enabled="true">
+ <entry-idle-time>
+ <expiration-attributes timeout="0" action="invalidate">
+ <custom-expiry>
+ <class-name>com.gemstone.gemfire.modules.util.SessionCustomExpiry</class-name>
+ </custom-expiry>
+ </expiration-attributes>
+ </entry-idle-time>
+ <partition-attributes redundant-copies="1" total-num-buckets="113"/>
+ </region-attributes>
+ </region>
+ -->
+
+</cache>
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java
new file mode 100644
index 0000000..bc06465
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/AbstractSessionCache.java
@@ -0,0 +1,92 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.modules.session.internal.common;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.modules.session.catalina.internal.DeltaSessionStatistics;
+import com.gemstone.gemfire.modules.session.internal.filter.util.TypeAwareMap;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+public abstract class AbstractSessionCache implements SessionCache {
+
+ /**
+ * The sessionRegion is the <code>Region</code> that actually stores and
+ * replicates the <code>Session</code>s.
+ */
+ protected Region<String, HttpSession> sessionRegion;
+
+ /**
+ * The operatingRegion is the <code>Region</code> used to do HTTP operations.
+ * if local cache is enabled, then this will be the local <code>Region</code>;
+ * otherwise, it will be the session <code>Region</code>.
+ */
+ protected Region<String, HttpSession> operatingRegion;
+
+ protected Map<CacheProperty, Object> properties =
+ new TypeAwareMap<CacheProperty, Object>(CacheProperty.class);
+
+ protected DeltaSessionStatistics statistics;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stop() {
+ sessionRegion.close();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Region<String, HttpSession> getOperatingRegion() {
+ return this.operatingRegion;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Region<String, HttpSession> getSessionRegion() {
+ return this.sessionRegion;
+ }
+
+ protected void createStatistics() {
+ this.statistics =
+ new DeltaSessionStatistics(getCache().getDistributedSystem(),
+ (String) properties.get(CacheProperty.STATISTICS_NAME));
+ }
+
+ /**
+ * Build up a {@code RegionConfiguraton} object from parameters originally
+ * passed in as filter initialization parameters.
+ *
+ * @return a {@code RegionConfiguration} object
+ */
+ protected RegionConfiguration createRegionConfiguration() {
+ RegionConfiguration configuration = new RegionConfiguration();
+
+ configuration.setRegionName(
+ (String) properties.get(CacheProperty.REGION_NAME));
+ configuration.setRegionAttributesId(
+ (String) properties.get(CacheProperty.REGION_ATTRIBUTES_ID));
+
+ configuration.setEnableGatewayDeltaReplication(
+ (Boolean) properties.get(
+ CacheProperty.ENABLE_GATEWAY_DELTA_REPLICATION));
+ configuration.setEnableGatewayReplication(
+ (Boolean) properties.get(CacheProperty.ENABLE_GATEWAY_REPLICATION));
+ configuration.setEnableDebugListener(
+ (Boolean) properties.get(CacheProperty.ENABLE_DEBUG_LISTENER));
+
+ return configuration;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java
new file mode 100644
index 0000000..5abd0b6
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/CacheProperty.java
@@ -0,0 +1,56 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.common;
+
+/**
+ * Used to define cache properties
+ */
+public enum CacheProperty {
+
+ ENABLE_DEBUG_LISTENER(Boolean.class),
+
+ ENABLE_GATEWAY_REPLICATION(Boolean.class),
+
+ ENABLE_GATEWAY_DELTA_REPLICATION(Boolean.class),
+
+ ENABLE_LOCAL_CACHE(Boolean.class),
+
+ REGION_NAME(String.class),
+
+ REGION_ATTRIBUTES_ID(String.class),
+
+ STATISTICS_NAME(String.class),
+
+ /**
+ * This parameter can take the following values which match the respective
+ * attribute container classes
+ * <p/>
+ * delta_queued : QueuedDeltaSessionAttributes delta_immediate :
+ * DeltaSessionAttributes immediate : ImmediateSessionAttributes queued
+ * : QueuedSessionAttributes
+ */
+ SESSION_DELTA_POLICY(String.class),
+
+ /**
+ * This parameter can take the following values:
+ * <p/>
+ * set (default) set_and_get
+ */
+ REPLICATION_TRIGGER(String.class);
+
+ Class clazz;
+
+ CacheProperty(Class clazz) {
+ this.clazz = clazz;
+ }
+
+ public Class getClazz() {
+ return clazz;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
new file mode 100644
index 0000000..a21ea2f
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/ClientServerSessionCache.java
@@ -0,0 +1,176 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.modules.session.internal.common;
+
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.client.ClientCache;
+import com.gemstone.gemfire.cache.client.ClientRegionFactory;
+import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
+import com.gemstone.gemfire.cache.execute.Execution;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.modules.util.BootstrappingFunction;
+import com.gemstone.gemfire.modules.util.CreateRegionFunction;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+import com.gemstone.gemfire.modules.util.RegionStatus;
+
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which defines a client/server cache.
+ */
+public class ClientServerSessionCache extends AbstractSessionCache {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(PeerToPeerSessionCache.class.getName());
+
+ private ClientCache cache;
+
+ protected static final String DEFAULT_REGION_ATTRIBUTES_ID =
+ RegionShortcut.PARTITION_REDUNDANT.toString();
+
+ protected static final Boolean DEFAULT_ENABLE_LOCAL_CACHE = true;
+
+ /**
+ * Constructor
+ *
+ * @param cache
+ * @param properties
+ */
+ public ClientServerSessionCache(ClientCache cache,
+ Map<CacheProperty, Object> properties) {
+ super();
+ this.cache = cache;
+
+ /**
+ * Set some default properties for this cache if they haven't already
+ * been set
+ */
+ this.properties.put(CacheProperty.REGION_ATTRIBUTES_ID,
+ DEFAULT_REGION_ATTRIBUTES_ID);
+ this.properties.put(CacheProperty.ENABLE_LOCAL_CACHE,
+ DEFAULT_ENABLE_LOCAL_CACHE);
+ this.properties.putAll(properties);
+ }
+
+ @Override
+ public void initialize() {
+ // Bootstrap the servers
+ bootstrapServers();
+
+ // Create or retrieve the region
+ createOrRetrieveRegion();
+
+ // Set the session region directly as the operating region since there is no difference
+ // between the local cache region and the session region.
+ operatingRegion = sessionRegion;
+
+ // Create or retrieve the statistics
+ createStatistics();
+ }
+
+ @Override
+ public GemFireCache getCache() {
+ return cache;
+ }
+
+ @Override
+ public boolean isClientServer() {
+ return true;
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Private methods
+
+ private void bootstrapServers() {
+ Execution execution = FunctionService.onServers(this.cache);
+ ResultCollector collector = execution.execute(new BootstrappingFunction());
+ // Get the result. Nothing is being done with it.
+ try {
+ collector.getResult();
+ } catch (Exception e) {
+ // If an exception occurs in the function, log it.
+ LOG.warn("Caught unexpected exception:", e);
+ }
+ }
+
+ private void createOrRetrieveRegion() {
+ // Retrieve the local session region
+ this.sessionRegion =
+ this.cache.getRegion(
+ (String) properties.get(CacheProperty.REGION_NAME));
+
+ // If necessary, create the regions on the server and client
+ if (this.sessionRegion == null) {
+ // Create the PR on the servers
+ createSessionRegionOnServers();
+
+ // Create the region on the client
+ this.sessionRegion = createLocalSessionRegion();
+ LOG.debug("Created session region: " + this.sessionRegion);
+ } else {
+ LOG.debug("Retrieved session region: " + this.sessionRegion);
+ }
+ }
+
+ private void createSessionRegionOnServers() {
+ // Create the RegionConfiguration
+ RegionConfiguration configuration = createRegionConfiguration();
+
+ // Send it to the server tier
+ Execution execution = FunctionService.onServer(this.cache).withArgs(
+ configuration);
+ ResultCollector collector = execution.execute(CreateRegionFunction.ID);
+
+ // Verify the region was successfully created on the servers
+ List<RegionStatus> results = (List<RegionStatus>) collector.getResult();
+ for (RegionStatus status : results) {
+ if (status == RegionStatus.INVALID) {
+ StringBuilder builder = new StringBuilder();
+ builder.append(
+ "An exception occurred on the server while attempting to create or validate region named ");
+ builder.append(properties.get(CacheProperty.REGION_NAME));
+ builder.append(". See the server log for additional details.");
+ throw new IllegalStateException(builder.toString());
+ }
+ }
+ }
+
+ private Region<String, HttpSession> createLocalSessionRegion() {
+ ClientRegionFactory<String, HttpSession> factory = null;
+ boolean enableLocalCache =
+ (Boolean) properties.get(CacheProperty.ENABLE_LOCAL_CACHE);
+
+ String regionName = (String) properties.get(CacheProperty.REGION_NAME);
+ if (enableLocalCache) {
+ // Create the region factory with caching and heap LRU enabled
+ factory = ((ClientCache) this.cache).
+ createClientRegionFactory(
+ ClientRegionShortcut.CACHING_PROXY_HEAP_LRU);
+ LOG.info("Created new local client session region: {}", regionName);
+ } else {
+ // Create the region factory without caching enabled
+ factory = ((ClientCache) this.cache).createClientRegionFactory(
+ ClientRegionShortcut.PROXY);
+ LOG.info(
+ "Created new local client (uncached) session region: {} without any session expiry",
+ regionName);
+ }
+
+ // Create the region
+ return factory.create(regionName);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
new file mode 100644
index 0000000..7ba5e76
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/PeerToPeerSessionCache.java
@@ -0,0 +1,174 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.modules.session.internal.common;
+
+import com.gemstone.gemfire.cache.Cache;
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.RegionFactory;
+import com.gemstone.gemfire.cache.RegionShortcut;
+import com.gemstone.gemfire.cache.execute.FunctionService;
+import com.gemstone.gemfire.modules.session.catalina.callback.LocalSessionCacheLoader;
+import com.gemstone.gemfire.modules.session.catalina.callback.LocalSessionCacheWriter;
+import com.gemstone.gemfire.modules.util.RegionConfiguration;
+import com.gemstone.gemfire.modules.util.RegionHelper;
+import com.gemstone.gemfire.modules.util.TouchPartitionedRegionEntriesFunction;
+import com.gemstone.gemfire.modules.util.TouchReplicatedRegionEntriesFunction;
+
+import java.util.Map;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which defines a peer-to-peer cache
+ */
+public class PeerToPeerSessionCache extends AbstractSessionCache {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(PeerToPeerSessionCache.class.getName());
+
+ private Cache cache;
+
+ private static final String DEFAULT_REGION_ATTRIBUTES_ID =
+ RegionShortcut.REPLICATE.toString();
+
+ private static final Boolean DEFAULT_ENABLE_LOCAL_CACHE = false;
+
+ /**
+ * Constructor
+ *
+ * @param cache
+ * @param properties
+ */
+ public PeerToPeerSessionCache(Cache cache,
+ Map<CacheProperty, Object> properties) {
+ super();
+ this.cache = cache;
+
+ /**
+ * Set some default properties for this cache if they haven't already
+ * been set
+ */
+ this.properties.put(CacheProperty.REGION_ATTRIBUTES_ID,
+ DEFAULT_REGION_ATTRIBUTES_ID);
+ this.properties.put(CacheProperty.ENABLE_LOCAL_CACHE,
+ DEFAULT_ENABLE_LOCAL_CACHE);
+ this.properties.putAll(properties);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize() {
+ // Register Functions
+ registerFunctions();
+
+ // Create or retrieve the region
+ createOrRetrieveRegion();
+
+ /**
+ * If local cache is enabled, create the local region fronting the
+ * session region and set it as the operating region; otherwise, use
+ * the session region directly as the operating region.
+ */
+ boolean enableLocalCache =
+ (Boolean) properties.get(CacheProperty.ENABLE_LOCAL_CACHE);
+ operatingRegion = enableLocalCache
+ ? createOrRetrieveLocalRegion()
+ : this.sessionRegion;
+
+ // Create or retrieve the statistics
+ createStatistics();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public GemFireCache getCache() {
+ return cache;
+ }
+
+ @Override
+ public boolean isClientServer() {
+ return false;
+ }
+
+ private void registerFunctions() {
+ // Register the touch partitioned region entries function if it is not already registered
+ if (!FunctionService.isRegistered(
+ TouchPartitionedRegionEntriesFunction.ID)) {
+ FunctionService.registerFunction(
+ new TouchPartitionedRegionEntriesFunction());
+ }
+
+ // Register the touch replicated region entries function if it is not already registered
+ if (!FunctionService.isRegistered(
+ TouchReplicatedRegionEntriesFunction.ID)) {
+ FunctionService.registerFunction(
+ new TouchReplicatedRegionEntriesFunction());
+ }
+ }
+
+ private void createOrRetrieveRegion() {
+ // Create the RegionConfiguration
+ RegionConfiguration configuration = createRegionConfiguration();
+
+ // Attempt to retrieve the region
+ // If it already exists, validate it
+ // If it doesn't already exist, create it
+ Region region = this.cache.getRegion(
+ (String) properties.get(CacheProperty.REGION_NAME));
+ if (region == null) {
+ // Create the region
+ region = RegionHelper.createRegion(cache, configuration);
+ LOG.info("Created new session region: " + region);
+ } else {
+ // Validate the existing region
+ LOG.info("Retrieved existing session region: " + region);
+ RegionHelper.validateRegion(cache, configuration, region);
+ }
+
+ // Set the session region
+ this.sessionRegion = region;
+ }
+
+ /**
+ * Create a local region fronting the main region.
+ *
+ * @return
+ */
+ private Region<String, HttpSession> createOrRetrieveLocalRegion() {
+ // Attempt to retrieve the fronting region
+ String frontingRegionName = this.sessionRegion.getName() + "_local";
+ Region<String, HttpSession> frontingRegion =
+ this.cache.getRegion(frontingRegionName);
+
+ if (frontingRegion == null) {
+ // Create the region factory
+ RegionFactory<String, HttpSession> factory =
+ this.cache.createRegionFactory(RegionShortcut.LOCAL_HEAP_LRU);
+
+ // Add the cache loader and writer
+ factory.setCacheLoader(new LocalSessionCacheLoader(this.sessionRegion));
+ factory.setCacheWriter(new LocalSessionCacheWriter(this.sessionRegion));
+
+ // Create the region
+ frontingRegion = factory.create(frontingRegionName);
+ LOG.info("Created new local session region: {}", frontingRegion);
+ } else {
+ LOG.info("Retrieved existing local session region: {}",
+ frontingRegion);
+ }
+
+ return frontingRegion;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
new file mode 100644
index 0000000..e0aa6bf
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionCache.java
@@ -0,0 +1,59 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.common;
+
+import com.gemstone.gemfire.cache.GemFireCache;
+import com.gemstone.gemfire.cache.Region;
+
+import javax.servlet.http.HttpSession;
+
+/**
+ * Interface to basic cache operations.
+ */
+public interface SessionCache {
+
+ /**
+ * Initialize the cache and create the appropriate region.
+ */
+ public void initialize();
+
+ /**
+ * Stop the cache.
+ */
+ public void stop();
+
+ /**
+ * Retrieve the cache reference.
+ *
+ * @return a {@code GemFireCache} reference
+ */
+ public GemFireCache getCache();
+
+ /**
+ * Get the {@code Region} being used by client code to put attributes.
+ *
+ * @return a {@code Region<String, HttpSession>} reference
+ */
+ public Region<String, HttpSession> getOperatingRegion();
+
+ /**
+ * Get the backing {@code Region} being used. This may not be the same as the
+ * region being used by client code to put attributes.
+ *
+ * @return a {@code Region<String, HttpSession>} reference
+ */
+ public Region<String, HttpSession> getSessionRegion();
+
+ /**
+ * Is this cache client-server? The only other alternative is peer-to-peer.
+ *
+ * @return true if this cache is client-server.
+ */
+ public boolean isClientServer();
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
new file mode 100644
index 0000000..836f4af
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/common/SessionExpirationCacheListener.java
@@ -0,0 +1,43 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+package com.gemstone.gemfire.modules.session.internal.common;
+
+import com.gemstone.gemfire.cache.Declarable;
+import com.gemstone.gemfire.cache.EntryEvent;
+import com.gemstone.gemfire.cache.Operation;
+import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
+
+import java.util.Properties;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SessionExpirationCacheListener extends
+ CacheListenerAdapter<String, HttpSession> implements Declarable {
+
+ private static final Logger LOG =
+ LoggerFactory.getLogger(SessionExpirationCacheListener.class.getName());
+
+ @Override
+ public void afterDestroy(EntryEvent<String, HttpSession> event) {
+ /**
+ * A Session expired. If it was destroyed by GemFire expiration,
+ * process it. If it was destroyed via Session.invalidate, ignore it
+ * since it has already been processed.
+ */
+ if (event.getOperation() == Operation.EXPIRE_DESTROY) {
+ HttpSession session = (HttpSession) event.getOldValue();
+ session.invalidate();
+ }
+ }
+
+ @Override
+ public void init(Properties p) {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java
new file mode 100644
index 0000000..f62f9db
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/Constants.java
@@ -0,0 +1,14 @@
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+/**
+ * Various constant values used through the app
+ */
+public class Constants {
+
+ public static String GEMFIRE_SESSION_REQUEST = "_gemfire_session_request_";
+
+ public static String SESSION_STATISTICS_MBEAN_NAME =
+ "com.gemstone:type=SessionStatistics,name=sessionStatistics";
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ContextManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ContextManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ContextManager.java
new file mode 100644
index 0000000..4954376
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/ContextManager.java
@@ -0,0 +1,95 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import javax.servlet.ServletContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class is a singleton and manages the mapping of context paths to
+ * original ServletContext objects as well as a mapping of paths to Cache
+ * reference handles.
+ */
+public class ContextManager {
+
+ /**
+ * Logger object
+ */
+ private static final Logger LOG =
+ LoggerFactory.getLogger(ContextManager.class.getName());
+
+ /**
+ * Mapping of context path to ServletContext object
+ */
+ private final ConcurrentMap<String, ServletContext> contextMap =
+ new ConcurrentHashMap<String, ServletContext>(16);
+
+ /**
+ * Our singleton reference
+ */
+ private static final ContextManager manager = new ContextManager();
+
+ private ContextManager() {
+ // This is a singleton
+ LOG.info("Initializing ContextManager");
+ }
+
+ /**
+ * Return our singleton instance
+ *
+ * @return
+ */
+ public static ContextManager getInstance() {
+ return manager;
+ }
+
+ /**
+ * Add a context to our collection
+ *
+ * @param context the {@code ServletContext} to add
+ */
+ public void putContext(ServletContext context) {
+ String path = context.getContextPath();
+ contextMap.put(path, context);
+ LOG.info("Adding context '{}' {}", path, context);
+ }
+
+ /**
+ * Remove a context from our collection
+ *
+ * @param context the context to remove
+ */
+ public void removeContext(ServletContext context) {
+ String path = context.getContextPath();
+ contextMap.remove(path);
+ LOG.info("Removing context '{}'", path);
+ }
+
+ /**
+ * Retrieve the context for a given path
+ *
+ * @param path
+ * @return the GemfireServletContext object or null if the path is not found
+ */
+ public ServletContext getContext(String path) {
+ ServletContext ctx = contextMap.get(path);
+ if (ctx == null) {
+ LOG.warn("No context for requested contextPath '{}'", path);
+ }
+ return ctx;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
new file mode 100644
index 0000000..bfa5e57
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/DummySessionManager.java
@@ -0,0 +1,127 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import javax.servlet.http.HttpSession;
+
+/**
+ * Class which fakes an in-memory basic session manager for testing purposes.
+ */
+public class DummySessionManager implements SessionManager {
+
+ /**
+ * Map of sessions
+ */
+ private final Map<String, HttpSession> sessions =
+ new HashMap<String, HttpSession>();
+
+ private class Attributes extends AbstractSessionAttributes {
+
+ @Override
+ public Object putAttribute(String attr, Object value) {
+ return attributes.put(attr, value);
+ }
+
+ @Override
+ public Object removeAttribute(String attr) {
+ return attributes.remove(attr);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void start(Object config, ClassLoader loader) {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stop() {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSession getSession(String id) {
+ return sessions.get(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSession wrapSession(HttpSession nativeSession) {
+ String id = generateId();
+ AbstractSessionAttributes attributes = new Attributes();
+ GemfireHttpSession session = new GemfireHttpSession(id, nativeSession);
+ session.setManager(this);
+ session.setAttributes(attributes);
+ sessions.put(id, session);
+
+ return session;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSession getWrappingSession(String nativeId) {
+ return sessions.get(nativeId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putSession(HttpSession session) {
+ // shouldn't ever get called
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroySession(String id) {
+ sessions.remove(id);
+ }
+
+ @Override
+ public String destroyNativeSession(String id) {
+ return null;
+ }
+
+ public String getSessionCookieName() {
+ return "JSESSIONID";
+ }
+
+ public String getJvmId() {
+ return "jvm-id";
+ }
+
+ /**
+ * Generate an ID string
+ */
+ private String generateId() {
+ return UUID.randomUUID().toString().toUpperCase() + "-GF";
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
new file mode 100644
index 0000000..1f114bc
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireHttpSession.java
@@ -0,0 +1,517 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+import com.gemstone.gemfire.DataSerializable;
+import com.gemstone.gemfire.DataSerializer;
+import com.gemstone.gemfire.Delta;
+import com.gemstone.gemfire.Instantiator;
+import com.gemstone.gemfire.InvalidDeltaException;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.SessionAttributes;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+
+import com.gemstone.gemfire.modules.util.ClassLoaderObjectInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which implements a Gemfire persisted {@code HttpSession}
+ */
+public class GemfireHttpSession implements
+ HttpSession, DataSerializable, Delta {
+
+ private static transient final Logger LOG =
+ LoggerFactory.getLogger(GemfireHttpSession.class.getName());
+
+ /**
+ * Serial id
+ */
+ private static final long serialVersionUID = 238915238964017823L;
+
+ /**
+ * Id for the session
+ */
+ private String id;
+
+ /**
+ * Attributes really hold the essence of persistence.
+ */
+ private SessionAttributes attributes;
+
+ private transient SessionManager manager;
+
+ private HttpSession nativeSession = null;
+
+ /**
+ * A session becomes invalid if it is explicitly invalidated or if it
+ * expires.
+ */
+ private boolean isValid = true;
+
+ private boolean isNew = true;
+
+ private boolean isDirty = false;
+
+ /**
+ * This is set during serialization and then reset by the SessionManager when
+ * it is retrieved from the attributes.
+ */
+ private AtomicBoolean serialized = new AtomicBoolean(false);
+
+ /**
+ * Register ourselves for de-serialization
+ */
+ static {
+ Instantiator.register(new Instantiator(GemfireHttpSession.class, 27315) {
+ @Override
+ public DataSerializable newInstance() {
+ return new GemfireHttpSession();
+ }
+ });
+ }
+
+ /**
+ * Constructor used for de-serialization
+ */
+ private GemfireHttpSession() {
+ }
+
+ /**
+ * Constructor
+ */
+ public GemfireHttpSession(String id, HttpSession nativeSession) {
+ this();
+ this.id = id;
+ this.nativeSession = nativeSession;
+ if (nativeSession != null) {
+ attributes.setMaxInactiveInterval(nativeSession.getMaxInactiveInterval());
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getAttribute(String name) {
+ if (!isValid) {
+ throw new IllegalStateException("Session is already invalidated");
+ }
+ Object obj = attributes.getAttribute(name);
+
+ if (obj != null) {
+ Object tmpObj = null;
+ ClassLoader loader = ((GemfireSessionManager) manager).getReferenceClassLoader();
+
+ if (obj.getClass().getClassLoader() != loader) {
+ LOG.debug(
+ "Attribute '{}' needs to be reconstructed with a new classloader",
+ name);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ ObjectOutputStream oos = new ObjectOutputStream(baos);
+ oos.writeObject(obj);
+ oos.close();
+
+ ObjectInputStream ois = new ClassLoaderObjectInputStream(
+ new ByteArrayInputStream(baos.toByteArray()),
+ loader);
+ tmpObj = ois.readObject();
+ } catch (IOException e) {
+ LOG.error("Exception while recreating attribute '" + name +
+ "'", e);
+ } catch (ClassNotFoundException e) {
+ LOG.error("Exception while recreating attribute '" + name +
+ "'", e);
+ }
+ if (tmpObj != null) {
+ setAttribute(name, tmpObj);
+ obj = tmpObj;
+ }
+ }
+ }
+
+ return obj;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Enumeration getAttributeNames() {
+ if (!isValid) {
+ throw new IllegalStateException("Session is already invalidated");
+ }
+ return Collections.enumeration(attributes.getAttributeNames());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getCreationTime() {
+ if (nativeSession != null) {
+ return nativeSession.getCreationTime();
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getLastAccessedTime() {
+ if (!isValid) {
+ throw new IllegalStateException("Session is already invalidated");
+ }
+ return attributes.getLastAccessedTime();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public ServletContext getServletContext() {
+ if (nativeSession != null) {
+ return nativeSession.getServletContext();
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSessionContext getSessionContext() {
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object getValue(String name) {
+ return getAttribute(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String[] getValueNames() {
+ return attributes.getAttributeNames().toArray(new String[0]);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void invalidate() {
+ nativeSession.invalidate();
+ manager.destroySession(id);
+ isValid = false;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isNew() {
+ if (!isValid) {
+ throw new IllegalStateException("Session is already invalidated");
+ }
+ return isNew;
+ }
+
+ public void setIsNew(boolean isNew) {
+ this.isNew = isNew;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setMaxInactiveInterval(int interval) {
+ if (nativeSession != null) {
+ nativeSession.setMaxInactiveInterval(interval);
+ }
+ attributes.setMaxInactiveInterval(interval);
+ isDirty = true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int getMaxInactiveInterval() {
+ if (nativeSession != null) {
+ return nativeSession.getMaxInactiveInterval();
+ } else {
+ return attributes.getMaxIntactiveInterval();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putValue(String name, Object value) {
+ setAttribute(name, value);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeAttribute(final String name) {
+ LOG.debug("Session {} removing attribute {}", getId(), name);
+ nativeSession.removeAttribute(name);
+ attributes.removeAttribute(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeValue(String name) {
+ removeAttribute(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setAttribute(final String name, final Object value) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Session {} setting attribute {} = '{}'",
+ new Object[]{id, name, value});
+ }
+
+ isDirty = true;
+ nativeSession.setAttribute(name, value);
+ if (value == null) {
+ removeAttribute(name);
+ } else {
+ attributes.putAttribute(name, value);
+ }
+ }
+
+ /**
+ * Gemfire serialization {@inheritDoc}
+ */
+ @Override
+ public void toData(DataOutput out) throws IOException {
+ DataSerializer.writeString(id, out);
+ DataSerializer.writeObject(attributes, out);
+ }
+
+ /**
+ * Gemfire de-serialization {@inheritDoc}
+ */
+ @Override
+ public void fromData(DataInput in) throws IOException,
+ ClassNotFoundException {
+ id = DataSerializer.readString(in);
+ attributes = DataSerializer.readObject(in);
+ if (getNativeSession() != null) {
+ for (String s : attributes.getAttributeNames()) {
+ getNativeSession().setAttribute(s, attributes.getAttribute(s));
+ }
+ }
+
+ // Explicit sets
+ serialized.set(true);
+ attributes.setSession(this);
+ }
+
+ /**
+ * These three methods handle delta propagation and are deferred to the
+ * attribute object.
+ */
+ @Override
+ public boolean hasDelta() {
+ return isDirty;
+ }
+
+ @Override
+ public void toDelta(DataOutput out) throws IOException {
+ if (attributes instanceof Delta) {
+ ((Delta) attributes).toDelta(out);
+ } else {
+ toData(out);
+ }
+ }
+
+ @Override
+ public void fromDelta(DataInput in) throws IOException,
+ InvalidDeltaException {
+ if (attributes instanceof Delta) {
+ ((Delta) attributes).fromDelta(in);
+ } else {
+ try {
+ fromData(in);
+ } catch (ClassNotFoundException cex) {
+ throw new IOException("Unable to forward fromDelta() call "
+ + "to fromData()", cex);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("[id=").append(id)
+ .append(", isNew=").append(isNew)
+ .append(", isValid=").append(isValid)
+ .append(", hasDelta=").append(hasDelta())
+ .append(", lastAccessedTime=").append(attributes.getLastAccessedTime())
+ .append(", jvmOwnerId=").append(attributes.getJvmOwnerId());
+ builder.append("]");
+ return builder.toString();
+ }
+
+ /**
+ * Flush the session object to the region
+ */
+ public void putInRegion() {
+
+ manager.putSession(this);
+ isDirty = false;
+ }
+
+ /**
+ * Determine whether the session is still valid or whether it has expired.
+ *
+ * @return true or false
+ */
+ public boolean isValid() {
+ if (!isValid) {
+ return false;
+ }
+ if (getMaxInactiveInterval() >= 0) {
+ long now = System.currentTimeMillis();
+ if (now - attributes.getLastAccessedTime() >= getMaxInactiveInterval() * 1000) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Is this session dirty and should it be written to cache
+ */
+ public boolean isDirty() {
+ return isDirty;
+ }
+
+ public void setManager(SessionManager manager) {
+ this.manager = manager;
+ }
+
+ /**
+ * For testing allow retrieval of the wrapped, native session.
+ */
+ public HttpSession getNativeSession() {
+ return nativeSession;
+ }
+
+
+ public void setNativeSession(HttpSession session) {
+ this.nativeSession = session;
+ }
+
+ /**
+ * Handle the process of failing over the session to a new native session
+ * object.
+ *
+ * @param session
+ */
+ public void failoverSession(HttpSession session) {
+ LOG.debug("Failing over session {} to {}", getId(), session.getId());
+ setNativeSession(session);
+ for (String name : attributes.getAttributeNames()) {
+ LOG.debug("Copying '{}' => {}", name, attributes.getAttribute(name));
+ session.setAttribute(name, attributes.getAttribute(name));
+ }
+ session.setMaxInactiveInterval(attributes.getMaxIntactiveInterval());
+ manager.putSession(this);
+ }
+
+
+ /**
+ * Update the last accessed time
+ */
+ public void updateAccessTime() {
+ attributes.setLastAccessedTime(System.currentTimeMillis());
+ }
+
+ /**
+ * The {@code SessionManager} injects this when creating a new session.
+ *
+ * @param attributes
+ */
+ public void setAttributes(AbstractSessionAttributes attributes) {
+ this.attributes = attributes;
+ }
+
+ /**
+ * This is called on deserialization. You can only call it once to get a
+ * meaningful value as it resets the serialized state. In other words, this
+ * call is not idempotent.
+ *
+ * @return whether this object has just been serialized
+ */
+ public boolean justSerialized() {
+ return serialized.getAndSet(false);
+ }
+
+ /**
+ * Called when the session is about to go out of scope. If the session has
+ * been defined to use async queued attributes then they will be written out
+ * at this point.
+ */
+ public void commit() {
+ attributes.setJvmOwnerId(manager.getJvmId());
+ attributes.flush();
+ }
+
+ public String getJvmOwnerId() {
+ if (attributes != null) {
+ return attributes.getJvmOwnerId();
+ }
+
+ return null;
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
new file mode 100644
index 0000000..2a34b5e
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionException.java
@@ -0,0 +1,36 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+/**
+ * Exception class for Gemfire Session Cache specific exceptions.
+ */
+public class GemfireSessionException extends Exception {
+
+ public GemfireSessionException() {
+ super();
+ }
+
+ public GemfireSessionException(String message) {
+ super(message);
+ }
+
+ public GemfireSessionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public GemfireSessionException(Throwable cause) {
+ super(cause);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/92ee6a79/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
----------------------------------------------------------------------
diff --git a/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
new file mode 100644
index 0000000..dd148d2
--- /dev/null
+++ b/extensions/gemfire-modules-session/src/main/java/com/gemstone/gemfire/modules/session/internal/filter/GemfireSessionManager.java
@@ -0,0 +1,502 @@
+/*=========================================================================
+ * Copyright (c) 2010-2014 Pivotal Software, Inc. All Rights Reserved.
+ * This product is protected by U.S. and international copyright
+ * and intellectual property laws. Pivotal products are covered by
+ * one or more patents listed at http://www.pivotal.io/patents.
+ *=========================================================================
+ */
+
+package com.gemstone.gemfire.modules.session.internal.filter;
+
+import com.gemstone.gemfire.cache.CacheClosedException;
+import com.gemstone.gemfire.cache.CacheFactory;
+import com.gemstone.gemfire.cache.EntryNotFoundException;
+import com.gemstone.gemfire.cache.control.ResourceManager;
+import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
+import com.gemstone.gemfire.modules.session.bootstrap.AbstractCache;
+import com.gemstone.gemfire.modules.session.bootstrap.ClientServerCache;
+import com.gemstone.gemfire.modules.session.bootstrap.LifecycleTypeAdapter;
+import com.gemstone.gemfire.modules.session.bootstrap.PeerToPeerCache;
+import com.gemstone.gemfire.modules.session.internal.common.CacheProperty;
+import com.gemstone.gemfire.modules.session.internal.common.ClientServerSessionCache;
+import com.gemstone.gemfire.modules.session.internal.common.PeerToPeerSessionCache;
+import com.gemstone.gemfire.modules.session.internal.common.SessionCache;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.AbstractSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.DeltaQueuedSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.DeltaSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.attributes.ImmediateSessionAttributes;
+import com.gemstone.gemfire.modules.session.internal.filter.util.TypeAwareMap;
+import com.gemstone.gemfire.modules.session.internal.jmx.SessionStatistics;
+import com.gemstone.gemfire.modules.util.RegionHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.MBeanServer;
+import javax.management.ObjectName;
+import javax.naming.InitialContext;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpSession;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * This class implements the session management using a Gemfire distributedCache
+ * as a persistent store for the session objects
+ */
+public class GemfireSessionManager implements SessionManager {
+
+ private final Logger LOG;
+
+ /**
+ * Prefix of init param string used to set gemfire properties
+ */
+ private static final String GEMFIRE_PROPERTY = "gemfire.property.";
+
+ /**
+ * Prefix of init param string used to set gemfire distributedCache setting
+ */
+ private static final String GEMFIRE_CACHE = "gemfire.cache.";
+
+ private static final String INIT_PARAM_CACHE_TYPE = "cache-type";
+ private static final String CACHE_TYPE_CLIENT_SERVER = "client-server";
+ private static final String CACHE_TYPE_PEER_TO_PEER = "peer-to-peer";
+ private static final String INIT_PARAM_SESSION_COOKIE_NAME = "session-cookie-name";
+ private static final String INIT_PARAM_JVM_ID = "jvm-id";
+ private static final String DEFAULT_JVM_ID = "default";
+
+ private SessionCache sessionCache = null;
+
+ /**
+ * Reference to the distributed system
+ */
+ private AbstractCache distributedCache = null;
+
+ /**
+ * Boolean indicating whether the manager is shutting down
+ */
+ private boolean isStopping = false;
+
+ /**
+ * Boolean indicating whether this manager is defined in the same context (war
+ * / classloader) as the filter.
+ */
+ private boolean isolated = false;
+
+ /**
+ * Map of wrapping GemFire session id to native session id
+ */
+ private Map<String, String> nativeSessionMap =
+ new HashMap<String, String>();
+
+ /**
+ * MBean for statistics
+ */
+ private SessionStatistics mbean;
+
+ /**
+ * This CL is used to compare against the class loader of attributes getting
+ * pulled out of the cache. This variable should be set to the CL of the
+ * filter running everything.
+ */
+ private ClassLoader referenceClassLoader;
+
+ private String sessionCookieName = "JSESSIONID";
+
+ /**
+ * Give this JVM a unique identifier.
+ */
+ private String jvmId = "default";
+
+ /**
+ * Set up properties with default values
+ */
+ private TypeAwareMap<CacheProperty, Object> properties =
+ new TypeAwareMap<CacheProperty, Object>(CacheProperty.class) {{
+ put(CacheProperty.REGION_NAME, RegionHelper.NAME + "_sessions");
+ put(CacheProperty.ENABLE_GATEWAY_DELTA_REPLICATION, Boolean.FALSE);
+ put(CacheProperty.ENABLE_GATEWAY_REPLICATION, Boolean.FALSE);
+ put(CacheProperty.ENABLE_DEBUG_LISTENER, Boolean.FALSE);
+ put(CacheProperty.STATISTICS_NAME, "gemfire_statistics");
+ put(CacheProperty.SESSION_DELTA_POLICY, "delta_queued");
+ put(CacheProperty.REPLICATION_TRIGGER, "set");
+ /**
+ * For REGION_ATTRIBUTES_ID and ENABLE_LOCAL_CACHE the default
+ * is different for ClientServerCache and PeerToPeerCache
+ * so those values are set in the relevant constructors when
+ * these properties are passed in to them.
+ */
+ }};
+
+ public GemfireSessionManager() {
+ LOG = LoggerFactory.getLogger(GemfireSessionManager.class.getName());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void start(Object conf, ClassLoader loader) {
+ this.referenceClassLoader = loader;
+ FilterConfig config = (FilterConfig) conf;
+
+ startDistributedSystem(config);
+ initializeSessionCache(config);
+
+ // Register MBean
+ registerMBean();
+
+ if (distributedCache.getClass().getClassLoader() == loader) {
+ isolated = true;
+ }
+
+ String sessionCookieName = config.getInitParameter(
+ INIT_PARAM_SESSION_COOKIE_NAME);
+ if (sessionCookieName != null && !sessionCookieName.isEmpty()) {
+ this.sessionCookieName = sessionCookieName;
+ LOG.info("Session cookie name set to: {}", this.sessionCookieName);
+ }
+
+ jvmId = config.getInitParameter(INIT_PARAM_JVM_ID);
+ if (jvmId == null || jvmId.isEmpty()) {
+ jvmId = DEFAULT_JVM_ID;
+ }
+
+ LOG.info("Started GemfireSessionManager (isolated={}, jvmId={})",
+ isolated, jvmId);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void stop() {
+ isStopping = true;
+
+ if (isolated) {
+ if (distributedCache != null) {
+ LOG.info("Closing distributed cache - assuming isolated cache");
+ distributedCache.close();
+ }
+ } else {
+ LOG.info("Not closing distributed cache - assuming common cache");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSession getSession(String id) {
+ GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+ id);
+
+ if (session != null) {
+ if (session.justSerialized()) {
+ session.setManager(this);
+ LOG.debug("Recovered serialized session {} (jvmId={})", id,
+ session.getJvmOwnerId());
+ }
+ LOG.debug("Retrieved session id {}", id);
+ } else {
+ LOG.debug("Session id {} not found", id);
+ }
+ return session;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public HttpSession wrapSession(HttpSession nativeSession) {
+ String id = generateId();
+ GemfireHttpSession session =
+ new GemfireHttpSession(id, nativeSession);
+
+ /**
+ * Set up the attribute container depending on how things are configured
+ */
+ AbstractSessionAttributes attributes;
+ if ("delta_queued".equals(
+ properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+ attributes = new DeltaQueuedSessionAttributes();
+ ((DeltaQueuedSessionAttributes) attributes).setReplicationTrigger(
+ (String) properties.get(CacheProperty.REPLICATION_TRIGGER));
+ } else if ("delta_immediate".equals(
+ properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+ attributes = new DeltaSessionAttributes();
+ } else if ("immediate".equals(
+ properties.get(CacheProperty.SESSION_DELTA_POLICY))) {
+ attributes = new ImmediateSessionAttributes();
+ } else {
+ attributes = new DeltaSessionAttributes();
+ LOG.warn(
+ "No session delta policy specified - using default of 'delta_immediate'");
+ }
+
+ attributes.setSession(session);
+ attributes.setJvmOwnerId(jvmId);
+
+ session.setManager(this);
+ session.setAttributes(attributes);
+
+ LOG.debug("Creating new session {}", id);
+ sessionCache.getOperatingRegion().put(id, session);
+
+ mbean.incActiveSessions();
+
+ return session;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public HttpSession getWrappingSession(String nativeId) {
+ HttpSession session = null;
+ String gemfireId = getGemfireSessionIdFromNativeId(nativeId);
+
+ if (gemfireId != null) {
+ session = getSession(gemfireId);
+ }
+ return session;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroySession(String id) {
+ if (!isStopping) {
+ try {
+ GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+ id);
+ if (session != null && session.getJvmOwnerId().equals(jvmId)) {
+ LOG.debug("Destroying session {}", id);
+ sessionCache.getOperatingRegion().destroy(id);
+ mbean.decActiveSessions();
+ }
+ } catch (EntryNotFoundException nex) {
+ }
+ } else {
+ if (sessionCache.isClientServer()) {
+ LOG.debug("Destroying session {}", id);
+ try {
+ sessionCache.getOperatingRegion().localDestroy(id);
+ } catch (EntryNotFoundException nex) {
+ // Ignored
+ } catch (CacheClosedException ccex) {
+ // Ignored
+ }
+ } else {
+ GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+ id);
+ if (session != null) {
+ session.setNativeSession(null);
+ }
+ }
+ }
+
+ synchronized (nativeSessionMap) {
+ String nativeId = nativeSessionMap.remove(id);
+ LOG.debug("destroySession called for {} wrapping {}", id, nativeId);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void putSession(HttpSession session) {
+ sessionCache.getOperatingRegion().put(session.getId(), session);
+ mbean.incRegionUpdates();
+ nativeSessionMap.put(session.getId(),
+ ((GemfireHttpSession) session).getNativeSession().getId());
+ }
+
+ @Override
+ public String destroyNativeSession(String nativeId) {
+ String gemfireSessionId = getGemfireSessionIdFromNativeId(nativeId);
+ if (gemfireSessionId != null) {
+ destroySession(gemfireSessionId);
+ }
+ return gemfireSessionId;
+ }
+
+ public ClassLoader getReferenceClassLoader() {
+ return referenceClassLoader;
+ }
+
+ /**
+ * This method is called when a native session gets destroyed. It will check
+ * if the GemFire session is actually still valid/not expired and will then
+ * attach a new, native session.
+ *
+ * @param nativeId the id of the native session
+ * @return the id of the newly attached native session or null if the GemFire
+ * session was already invalid
+ */
+ public String refreshSession(String nativeId) {
+ String gemfireId = getGemfireSessionIdFromNativeId(nativeId);
+ if (gemfireId == null) {
+ return null;
+ }
+
+ GemfireHttpSession session = (GemfireHttpSession) sessionCache.getOperatingRegion().get(
+ gemfireId);
+ if (session.isValid()) {
+
+ }
+
+ return null;
+ }
+
+ public String getSessionCookieName() {
+ return sessionCookieName;
+ }
+
+ public String getJvmId() {
+ return jvmId;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////
+ // Private methods
+
+ private String getGemfireSessionIdFromNativeId(String nativeId) {
+ if (nativeId == null) {
+ return null;
+ }
+
+ for (Map.Entry<String, String> e : nativeSessionMap.entrySet()) {
+ if (nativeId.equals(e.getValue())) {
+ return e.getKey();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Start the underlying distributed system
+ *
+ * @param config
+ */
+ private void startDistributedSystem(FilterConfig config) {
+ // Get the distributedCache type
+ final String cacheType = config.getInitParameter(INIT_PARAM_CACHE_TYPE);
+ if (CACHE_TYPE_CLIENT_SERVER.equals(cacheType)) {
+ distributedCache = ClientServerCache.getInstance();
+ } else if (CACHE_TYPE_PEER_TO_PEER.equals(cacheType)) {
+ distributedCache = PeerToPeerCache.getInstance();
+ } else {
+ LOG.error("No 'cache-type' initialization param set. "
+ + "Cache will not be started");
+ return;
+ }
+
+ if (!distributedCache.isStarted()) {
+ /**
+ * Process all the init params and see if any apply to the
+ * distributed system.
+ */
+ for (Enumeration<String> e = config.getInitParameterNames(); e.hasMoreElements(); ) {
+ String param = e.nextElement();
+ if (!param.startsWith(GEMFIRE_PROPERTY)) {
+ continue;
+ }
+
+ String gemfireProperty = param.substring(GEMFIRE_PROPERTY.length());
+ LOG.info("Setting gemfire property: {} = {}",
+ gemfireProperty, config.getInitParameter(param));
+ distributedCache.setProperty(gemfireProperty,
+ config.getInitParameter(param));
+ }
+
+ distributedCache.lifecycleEvent(LifecycleTypeAdapter.START);
+ }
+ }
+
+ /**
+ * Initialize the distributedCache
+ */
+ private void initializeSessionCache(FilterConfig config) {
+ // Retrieve the distributedCache
+ GemFireCacheImpl cache = (GemFireCacheImpl) CacheFactory.getAnyInstance();
+ if (cache == null) {
+ throw new IllegalStateException("No cache exists. Please configure "
+ + "either a PeerToPeerCacheLifecycleListener or "
+ + "ClientServerCacheLifecycleListener in the "
+ + "server.xml file.");
+ }
+
+ /**
+ * Process all the init params and see if any apply to the distributedCache
+ */
+ ResourceManager rm = cache.getResourceManager();
+ for (Enumeration<String> e = config.getInitParameterNames(); e.hasMoreElements(); ) {
+ String param = e.nextElement();
+
+ // Uggh - don't like this non-generic stuff
+ if (param.equalsIgnoreCase("criticalHeapPercentage")) {
+ float val = Float.parseFloat(config.getInitParameter(param));
+ rm.setCriticalHeapPercentage(val);
+ }
+
+ if (param.equalsIgnoreCase("evictionHeapPercentage")) {
+ float val = Float.parseFloat(config.getInitParameter(param));
+ rm.setEvictionHeapPercentage(val);
+ }
+
+
+ if (!param.startsWith(GEMFIRE_CACHE)) {
+ continue;
+ }
+
+ String gemfireWebParam = param.substring(GEMFIRE_CACHE.length());
+ LOG.info("Setting cache parameter: {} = {}",
+ gemfireWebParam, config.getInitParameter(param));
+ properties.put(CacheProperty.valueOf(gemfireWebParam.toUpperCase()),
+ config.getInitParameter(param));
+ }
+
+ // Create the appropriate session distributedCache
+ sessionCache = cache.isClient()
+ ? new ClientServerSessionCache(cache, properties)
+ : new PeerToPeerSessionCache(cache, properties);
+
+ // Initialize the session distributedCache
+ sessionCache.initialize();
+ }
+
+ /**
+ * Register a bean for statistic gathering purposes
+ */
+ private void registerMBean() {
+ mbean = new SessionStatistics();
+
+ try {
+ InitialContext ctx = new InitialContext();
+ MBeanServer mbs = MBeanServer.class.cast(
+ ctx.lookup("java:comp/env/jmx/runtime"));
+ ObjectName oname = new ObjectName(
+ Constants.SESSION_STATISTICS_MBEAN_NAME);
+
+ mbs.registerMBean(mbean, oname);
+ } catch (Exception ex) {
+ LOG.warn("Unable to register statistics MBean. Error: {}",
+ ex.getMessage());
+ }
+ }
+
+
+ /**
+ * Generate an ID string
+ */
+ private String generateId() {
+ return UUID.randomUUID().toString().toUpperCase() + "-GF";
+ }
+
+ AbstractCache getCache() {
+ return distributedCache;
+ }
+}
\ No newline at end of file