diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc
index 11eaf71790e5..ba8bfd985e5f 100644
--- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc
+++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-hazelcast.adoc
@@ -84,6 +84,7 @@ Opening the `start.d/session-store-hazelcast-remote.ini` will show a list of all
#jetty.session.hazelcast.mapName=jetty_sessions
#jetty.session.hazelcast.onlyClient=true
#jetty.session.hazelcast.configurationLocation=
+jetty.session.hazelcast.scavengeZombies=false
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
----
@@ -94,6 +95,8 @@ jetty.session.hazelcast.onlyClient::
Hazelcast instance will be configured in client mode
jetty.session.hazelcast.configurationLocation::
Path to an an Hazelcast xml configuration file
+jetty.session.hazelcast.scavengeZombies::
+True/False. `False` by default. If `true`, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your session stores attributes that reference classes from inside your webapp, or jetty classes, you will need to ensure that these classes are available on each of your hazelcast instances.
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
@@ -106,6 +109,8 @@ Configuring `savePeriod` is useful if your persistence technology is very slow/c
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
+
+Be aware using the `scavengeZombies` option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances.
____
==== Configuring Embedded Hazelcast Clustering
@@ -165,15 +170,18 @@ Opening the `start.d/start.d/session-store-hazelcast-embedded.ini` will show a l
#jetty.session.hazelcast.mapName=jetty_sessions
#jetty.session.hazelcast.configurationLocation=
+jetty.session.hazelcast.scavengeZombies=false
#jetty.session.gracePeriod.seconds=3600
#jetty.session.savePeriod.seconds=0
----
jetty.session.hazelcast.mapName::
Name of the Map in Hazelcast where sessions will be stored.
-jetty.session.gracePeriod.seconds::
-Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.hazelcast.configurationLocation::
Path to an an Hazelcast xml configuration file
+jetty.session.hazelcast.scavengeZombies::
+True/False. `False` by default. If `true`, jetty will use hazelcast queries to find sessions that are no longer being used on any jetty node and whose expiry time has passed. If you enable this option, and your sessions contain attributes that reference classes from inside your webapp (or jetty classes) you will need to ensure that these classes are available on each of your hazelcast instances.
+jetty.session.gracePeriod.seconds::
+Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
@@ -184,4 +192,6 @@ Configuring `savePeriod` is useful if your persistence technology is very slow/c
In a clustered environment, there is a risk of the last access time of the session being out-of-date in the shared store for up to `savePeriod` seconds.
This allows the possibility that a node may prematurely expire the session, even though it is in use by another node.
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
+
+Be aware using the `scavengeZombies` option that if your session attributes contain classes from inside your webapp (or jetty classes) then you will need to put these classes onto the classpath of all of your hazelcast instances. In the cast of embedded hazelcast, as it is started before your webapp, it will NOT have access to your webapp's classes - you will need to extract these classes and put them onto the jetty server's classpath.
____
diff --git a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc
index 8647aa9ce1c8..e8274075591a 100644
--- a/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc
+++ b/jetty-documentation/src/main/asciidoc/administration/sessions/session-configuration-infinispan.adoc
@@ -24,10 +24,6 @@
When using the Jetty distribution, you will first need to enable the `session-store-infinispan-remote` link:#startup-modules[module] for your link:#startup-base-and-home[Jetty base] using the `--add-to-start` argument on the command line.
-____
-[IMPORTANT]
-If you are running Jetty with JDK 9 or greater, enable `session-store-infinispan-remote-910.mod` instead.
-____
[source, screen, subs="{sub-order}"]
----
@@ -52,7 +48,7 @@ INFO : server transitively enabled, ini template available with --add-
INFO : sessions transitively enabled, ini template available with --add-to-start=sessions
INFO : session-store-infinispan-remote initialized in ${jetty.base}/start.d/session-store-infinispan-remote.ini
MKDIR : ${jetty.base}/lib/infinispan
-DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote/7.1.1.Final/infinispan-remote-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-7.1.1.Final.jar
+DOWNLD: https://repo1.maven.org/maven2/org/infinispan/infinispan-remote-it/9.4.8.Final/infinispan-remote-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-remote-it-9.4.8.Final.jar
MKDIR : ${jetty.base}/resources
COPY : ${jetty.home}/modules/session-store-infinispan-remote/resources/hotrod-client.properties to ${jetty.base}/resources/hotrod-client.properties
INFO : Base directory was modified
@@ -93,13 +89,17 @@ Opening the `start.d/session-store-infinispan-remote.ini` will show a list of al
jetty.session.infinispan.remoteCacheName::
Name of the cache in Infinispan where sessions will be stored.
jetty.session.infinispan.idleTimeout.seconds::
-Amount of time, in seconds, that the system allows the connector to remain idle before closing the connection.
+Amount of time, in seconds, that a session entry in infinispan can be idle (ie not read or written) before infinispan will delete its entry.
+Usually, you do *not* want to set a value for this, as you want jetty to handle all session expiration (and call any SessionListeners).
+However, if there is the possibility that sessions can be left in infinispan but no longer referenced by any jetty node (so called "zombie" or "orphan" sessions), then you might want to use this feature.
+You should make sure that the number of seconds you specify is sufficiently large to avoid the situation where a session is still being referenced by jetty, but is rarely accessed and thus deleted by infinispan.
+Alternatively, you can enable the `infinispan-remote-query` module, which will allow jetty to search the infinispan session cache to proactively find and properly (ie calling any SessionListeners) scavenge defunct sessions.
jetty.session.gracePeriod.seconds::
Amount of time, in seconds, to wait for other nodes to be checked to verify an expired session is in fact expired throughout the cluster before closing it.
jetty.session.savePeriod.seconds=0::
By default whenever the last concurrent request leaves a session, that session is always persisted via the `SessionDataStore`, even if the only thing that changed on the session is its updated last access time.
A non-zero value means that the `SessionDataStore` will skip persisting the session if only the access time changed, and it has been less than `savePeriod` seconds since the last time the session was written.
-+
+
____
[NOTE]
Configuring `savePeriod` is useful if your persistence technology is very slow/costly for writes.
@@ -108,6 +108,19 @@ This allows the possibility that a node may prematurely expire the session, even
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
+==== Configuring the Remote Infinispan Query Module
+
+Enabling this module allows jetty to search infinispan for expired sessions that are no longer being referenced by any jetty node.
+Note that this is an *additional* module, to be used in conjuction with the `session-store-infinispan-remote` module.
+
+[source, screen, subs="{sub-order}"]
+----
+java -jar ../start.jar --add-to-start=infinispan-remote-query
+----
+
+There are no configuration properties associated with this module.
+
+
==== Configuring Embedded Inifinspan Clustering
During testing, it can be helpful to run an in-process instance of Infinispan.
@@ -137,7 +150,7 @@ Proceed (y/N)? y
INFO : server initialised (transitively) in ${jetty.base}/start.d/server.ini
INFO : sessions initialised (transitively) in ${jetty.base}/start.d/sessions.ini
INFO : session-store-infinispan-embedded initialised in ${jetty.base}/start.d/session-store-infinispan-embedded.ini
-DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded/7.1.1.Final/infinispan-embedded-7.1.1.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-7.1.1.Final.jar
+DOWNLOAD: https://repo1.maven.org/maven2/org/infinispan/infinispan-embedded-it/9.4.8.Final/infinispan-embedded-it-9.4.8.Final.jar to ${jetty.base}/lib/infinispan/infinispan-embedded-it-9.4.8.Final.jar
INFO : Base directory was modified
----
@@ -180,6 +193,19 @@ This allows the possibility that a node may prematurely expire the session, even
Thorough consideration of the `maxIdleTime` of the session when setting the `savePeriod` is imperative - there is no point in setting a `savePeriod` that is larger than the `maxIdleTime`.
____
+
+==== Configuring Inifinspan Embedded Query
+
+Similarly to the `session-store-infinispan-remote` module, the `session-store-infinispan-embedded` module has an adjunct module `infinispan-embedded-query`, which when enabled, will allow jetty to detect and properly scavenge defunct sessions stranded in infinispan.
+
+[source, screen, subs="{sub-order}"]
+----
+java -jar ../start.jar --add-to-start=infinispan-embedded-query
+----
+
+There are no configuration properties associated with this module.
+
+
==== Converting session format for jetty-9.4.13
From jetty-9.4.13 onwards, we have changed the format of the serialized session when using a remote cache (ie using hotrod).
diff --git a/jetty-hazelcast/pom.xml b/jetty-hazelcast/pom.xml
index 48e211e3d04d..dfad9a45152f 100644
--- a/jetty-hazelcast/pom.xml
+++ b/jetty-hazelcast/pom.xml
@@ -12,7 +12,7 @@
Jetty :: Hazelcast Session Manager
- 3.9.3
+ 3.9.4${project.groupId}.hazelcast
diff --git a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml
index 680e6f07d3f4..9df3c69c5e3e 100644
--- a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml
+++ b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/default.xml
@@ -13,6 +13,7 @@
+
diff --git a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml
index ca32fcff21d6..355d73707e7f 100644
--- a/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml
+++ b/jetty-hazelcast/src/main/config/etc/sessions/hazelcast/remote.xml
@@ -12,6 +12,7 @@
+
diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod
index 405b5209aafa..374493bc509b 100644
--- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod
+++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-embedded.mod
@@ -13,7 +13,7 @@ session-store
sessions
[files]
-maven://com.hazelcast/hazelcast/3.9.3|lib/hazelcast/hazelcast-3.9.3.jar
+maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar
[xml]
etc/sessions/hazelcast/default.xml
@@ -32,5 +32,6 @@ http://www.apache.org/licenses/LICENSE-2.0.html
jetty.session.hazelcast.mapName=jetty-distributed-session-map
jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE
#jetty.session.hazelcast.configurationLocation=
+jetty.session.hazelcast.scavengeZombies=false
jetty.session.gracePeriod.seconds=3600
jetty.session.savePeriod.seconds=0
diff --git a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod
index 29e3a2531718..3796bef5924d 100644
--- a/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod
+++ b/jetty-hazelcast/src/main/config/modules/session-store-hazelcast-remote.mod
@@ -13,8 +13,8 @@ session-store
sessions
[files]
-maven://com.hazelcast/hazelcast/3.9.3|lib/hazelcast/hazelcast-3.9.3.jar
-maven://com.hazelcast/hazelcast-client/3.9.3|lib/hazelcast/hazelcast-client-3.9.3.jar
+maven://com.hazelcast/hazelcast/3.9.4|lib/hazelcast/hazelcast-3.9.4.jar
+maven://com.hazelcast/hazelcast-client/3.9.4|lib/hazelcast/hazelcast-client-3.9.4.jar
[xml]
etc/sessions/hazelcast/remote.xml
@@ -33,6 +33,7 @@ http://www.apache.org/licenses/LICENSE-2.0.html
jetty.session.hazelcast.mapName=jetty-distributed-session-map
jetty.session.hazelcast.hazelcastInstanceName=JETTY_DISTRIBUTED_SESSION_INSTANCE
jetty.session.hazelcast.onlyClient=true
+jetty.session.hazelcast.scavengeZombies=false
#jetty.session.hazelcast.configurationLocation=
jetty.session.gracePeriod.seconds=3600
jetty.session.savePeriod.seconds=0
diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java
index dfed4934cb47..a728ccd658fc 100644
--- a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java
+++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStore.java
@@ -18,7 +18,8 @@
package org.eclipse.jetty.hazelcast.session;
-import java.util.Collections;
+import java.util.Collection;
+import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@@ -33,6 +34,9 @@
import org.eclipse.jetty.util.log.Logger;
import com.hazelcast.core.IMap;
+import com.hazelcast.query.EntryObject;
+import com.hazelcast.query.Predicate;
+import com.hazelcast.query.PredicateBuilder;
/**
* Session data stored in Hazelcast
@@ -47,9 +51,35 @@ public class HazelcastSessionDataStore
private IMap sessionDataMap;
+ private boolean _scavengeZombies;
+
public HazelcastSessionDataStore()
{
- // no op
+ }
+
+ /** Control whether or not to execute queries to find
+ * "zombie" sessions - ie sessions that are no longer
+ * actively referenced by any jetty instance and should
+ * be expired.
+ *
+ * If you use this feature, be aware that if your session
+ * stores any attributes that use classes from within your
+ * webapp, or from within jetty, you will need to make sure
+ * those classes are available to all of your hazelcast
+ * instances, whether embedded or remote.
+ *
+ * @param scavengeZombies true means unreferenced sessions
+ * will be actively sought and expired. False means that they
+ * will remain in hazelcast until some other mechanism removes them.
+ */
+ public void setScavengeZombieSessions (boolean scavengeZombies)
+ {
+ _scavengeZombies = scavengeZombies;
+ }
+
+ public boolean isScavengeZombies()
+ {
+ return _scavengeZombies;
}
@Override
@@ -97,7 +127,9 @@ public void setSessionDataMap( IMap sessionDataMap )
public void initialize( SessionContext context )
throws Exception
{
- _context = context;
+ super.initialize(context);
+ if (isScavengeZombies())
+ sessionDataMap.addIndex("expiry", true);
}
@Override
@@ -113,16 +145,13 @@ public boolean isPassivating()
return true;
}
+
@Override
public Set doGetExpired( Set candidates )
{
- if (candidates == null || candidates.isEmpty())
- {
- return Collections.emptySet();
- }
-
long now = System.currentTimeMillis();
- return candidates.stream().filter( candidate -> {
+
+ Set expiredSessionIds = candidates.stream().filter( candidate -> {
if (LOG.isDebugEnabled())
LOG.debug( "Checking expiry for candidate {}", candidate );
@@ -184,7 +213,49 @@ public Set doGetExpired( Set candidates )
}
return false;
} ).collect( Collectors.toSet() );
+
+ if (isScavengeZombies())
+ {
+ //Now find other sessions in hazelcast that have expired
+ final AtomicReference> reference = new AtomicReference<>();
+ final AtomicReference exception = new AtomicReference<>();
+
+ _context.run(()->
+ {
+ try
+ {
+ Set ids = new HashSet<>();
+ EntryObject eo = new PredicateBuilder().getEntryObject();
+ Predicate, ?> predicate = eo.get("expiry").greaterThan(0).and(eo.get("expiry").lessEqual(now));
+ Collection results = sessionDataMap.values(predicate);
+ if (results != null)
+ {
+ for (SessionData sd: results)
+ ids.add(sd.getId());
+ }
+ reference.set(ids);
+ }
+ catch (Exception e)
+ {
+ exception.set(e);
+ }
+ });
+
+ if (exception.get() != null)
+ {
+ LOG.warn("Error querying for expired sessions {}", exception.get());
+ return expiredSessionIds;
+ }
+
+ if (reference.get() != null)
+ {
+ expiredSessionIds.addAll(reference.get());
+ }
+ }
+
+ return expiredSessionIds;
}
+
@Override
public boolean exists( String id )
diff --git a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java
index f1524102cef4..08a941bd8bac 100644
--- a/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java
+++ b/jetty-hazelcast/src/main/java/org/eclipse/jetty/hazelcast/session/HazelcastSessionDataStoreFactory.java
@@ -54,8 +54,20 @@ public class HazelcastSessionDataStoreFactory
private HazelcastInstance hazelcastInstance;
private MapConfig mapConfig;
+
+ private boolean scavengeZombies = false;
+ public boolean isScavengeZombies()
+ {
+ return scavengeZombies;
+ }
+
+ public void setScavengeZombies(boolean scavengeZombies)
+ {
+ this.scavengeZombies = scavengeZombies;
+ }
+
@Override
public SessionDataStore getSessionDataStore( SessionHandler handler )
throws Exception
@@ -122,9 +134,10 @@ public SessionDataStore getSessionDataStore( SessionHandler handler )
}
}
// initialize the map
- hazelcastSessionDataStore.setSessionDataMap(hazelcastInstance.getMap( mapName ) );
- hazelcastSessionDataStore.setGracePeriodSec( getGracePeriodSec() );
- hazelcastSessionDataStore.setSavePeriodSec( getSavePeriodSec() );
+ hazelcastSessionDataStore.setSessionDataMap(hazelcastInstance.getMap( mapName ));
+ hazelcastSessionDataStore.setGracePeriodSec(getGracePeriodSec());
+ hazelcastSessionDataStore.setSavePeriodSec(getSavePeriodSec());
+ hazelcastSessionDataStore.setScavengeZombieSessions(scavengeZombies);
return hazelcastSessionDataStore;
}
diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml b/jetty-home/etc/infinispan-embedded.xml
similarity index 90%
rename from jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml
rename to jetty-home/etc/infinispan-embedded.xml
index 5adc356b1f60..07d8ca214cbb 100644
--- a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded/infinispan-embedded.xml
+++ b/jetty-home/etc/infinispan-embedded.xml
@@ -2,4 +2,4 @@
-
+
\ No newline at end of file
diff --git a/jetty-home/pom.xml b/jetty-home/pom.xml
index 70e3d3deea92..5b981b9ec975 100644
--- a/jetty-home/pom.xml
+++ b/jetty-home/pom.xml
@@ -440,12 +440,41 @@
org.eclipse.jetty,org.eclipse.jetty.websocket
+ infinispan-embedded,infinispan-remoteconfigfalseMETA-INF/**${assembly-directory}
+
+ unpack-infinispan-config
+ generate-resources
+
+ unpack
+
+
+
+
+ org.eclipse.jetty
+ infinispan-embedded
+ ${project.version}
+ config
+ jar
+
+
+ org.eclipse.jetty
+ infinispan-remote
+ ${project.version}
+ config
+ jar
+
+
+ true
+ META-INF/**
+ ${assembly-directory}
+
+
@@ -699,7 +728,24 @@
org.eclipse.jetty
- jetty-infinispan
+ infinispan-embedded
+ ${project.version}
+ pom
+
+
+ org.eclipse.jetty
+ infinispan-embedded-query
+ ${project.version}
+
+
+ org.eclipse.jetty
+ infinispan-remote
+ ${project.version}
+ pom
+
+
+ org.eclipse.jetty
+ infinispan-remote-query${project.version}
diff --git a/jetty-home/start.ini b/jetty-home/start.ini
new file mode 100644
index 000000000000..215582944fea
--- /dev/null
+++ b/jetty-home/start.ini
@@ -0,0 +1,9 @@
+# ---------------------------------------
+# Module: session-store-infinispan-embedded
+# Enables session data store in a local Infinispan cache
+# ---------------------------------------
+--module=session-store-infinispan-embedded
+
+#jetty.session.gracePeriod.seconds=3600
+#jetty.session.savePeriod.seconds=0
+
diff --git a/jetty-infinispan/infinispan-common/pom.xml b/jetty-infinispan/infinispan-common/pom.xml
new file mode 100644
index 000000000000..5b4a89e04d9e
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/pom.xml
@@ -0,0 +1,74 @@
+
+
+ org.eclipse.jetty
+ infinispan-parent
+ 9.4.16-SNAPSHOT
+
+ 4.0.0
+ infinispan-common
+ Jetty :: Infinispan Session Manager Common
+ http://www.eclipse.org/jetty
+
+ ${project.groupId}.infinispan.common
+
+
+
+
+ install
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+ config
+
+
+
+
+
+
+
+
+
+ org.infinispan
+ infinispan-core
+ ${infinispan.version}
+ true
+
+
+ org.infinispan.protostream
+ protostream
+ 4.2.2.Final
+ true
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${project.version}
+
+
+ org.infinispan
+ infinispan-client-hotrod
+ ${infinispan.version}
+ provided
+
+
+ org.infinispan
+ infinispan-remote-query-client
+ ${infinispan.version}
+ provided
+
+
+ junit
+ junit
+ test
+
+
+
diff --git a/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml b/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml
new file mode 100644
index 000000000000..cd994df21ddd
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/src/main/config/etc/sessions/infinispan/infinispan-common.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jetty-infinispan/infinispan-common/src/main/config/modules/infinispan-common.mod b/jetty-infinispan/infinispan-common/src/main/config/modules/infinispan-common.mod
new file mode 100644
index 000000000000..babac9c900cf
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/src/main/config/modules/infinispan-common.mod
@@ -0,0 +1,20 @@
+[description]
+Common to all infinispan modules
+
+[tags]
+session
+
+[depend]
+sessions
+
+[lib]
+lib/infinispan-common-${jetty.version}.jar
+lib/infinispan/*.jar
+
+[ini]
+infinispan.version?=9.1.0.Final
+
+[license]
+Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+http://infinispan.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java
similarity index 100%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionData.java
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java
similarity index 68%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java
index fa21de58ade6..0761bd15bdf7 100644
--- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java
+++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStore.java
@@ -1,6 +1,6 @@
//
// ========================================================================
-// Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
@@ -34,6 +34,7 @@
import org.eclipse.jetty.util.log.Logger;
import org.infinispan.commons.api.BasicCache;
+
/**
* InfinispanSessionDataStore
*
@@ -48,10 +49,14 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
/**
* Clustered cache of sessions
*/
- private BasicCache _cache;
+ private BasicCache _cache;
private int _infinispanIdleTimeoutSec;
+
+
+
+ private QueryManager _queryManager;
private boolean _passivating;
@@ -61,7 +66,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
*
* @return the cache
*/
- public BasicCache getCache()
+ public BasicCache getCache()
{
return _cache;
}
@@ -73,13 +78,26 @@ public BasicCache getCache()
*
* @param cache the cache
*/
- public void setCache (BasicCache cache)
+ public void setCache (BasicCache cache)
{
this._cache = cache;
}
+ public QueryManager getQueryManager()
+ {
+ return _queryManager;
+ }
+
+ public void setQueryManager (QueryManager queryManager)
+ {
+ _queryManager = queryManager;
+ }
+
+ /**
+ * @see org.eclipse.jetty.server.session.SessionDataStore#load(String)
+ */
@Override
protected void doStart() throws Exception
{
@@ -139,67 +157,92 @@ public boolean delete(String id) throws Exception
@Override
public Set doGetExpired(Set candidates)
{
- if (candidates == null || candidates.isEmpty())
- return candidates;
-
+
long now = System.currentTimeMillis();
Set expired = new HashSet<>();
- //TODO if there is NOT an idle timeout set on entries in infinispan, need to check other sessions
- //that are not currently in the SessionDataStore (eg they've been passivated)
- for (String candidate:candidates)
+ /*
+ * 1. Select sessions managed by this node for our context that have expired
+ */
+ if(candidates != null)
{
- if (LOG.isDebugEnabled())
- LOG.debug("Checking expiry for candidate {}", candidate);
- try
+ for (String candidate:candidates)
{
- SessionData sd = load(candidate);
-
- //if the session no longer exists
- if (sd == null)
- {
- expired.add(candidate);
- if (LOG.isDebugEnabled())
- LOG.debug("Session {} does not exist in infinispan", candidate);
- }
- else
+ if (LOG.isDebugEnabled())
+ LOG.debug("Checking expiry for candidate {}", candidate);
+ try
{
- if (_context.getWorkerName().equals(sd.getLastNode()))
+ SessionData sd = load(candidate);
+
+ //if the session no longer exists
+ if (sd == null)
{
- //we are its manager, add it to the expired set if it is expired now
- if ((sd.getExpiry() > 0 ) && sd.getExpiry() <= now)
- {
- expired.add(candidate);
- if (LOG.isDebugEnabled())
- LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName());
- }
+ expired.add(candidate);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Session {} does not exist in infinispan", candidate);
}
else
{
- //if we are not the session's manager, only expire it iff:
- // this is our first expiryCheck and the session expired a long time ago
- //or
- //the session expired at least one graceperiod ago
- if (_lastExpiryCheckTime <=0)
+ if (_context.getWorkerName().equals(sd.getLastNode()))
{
- if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
+ //we are its manager, add it to the expired set if it is expired now
+ if ((sd.getExpiry() > 0 ) && sd.getExpiry() <= now)
+ {
expired.add(candidate);
+ if (LOG.isDebugEnabled())
+ LOG.debug("Session {} managed by {} is expired", candidate, _context.getWorkerName());
+ }
}
else
{
- if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * _gracePeriodSec)))
- expired.add(candidate);
+ //if we are not the session's manager, only expire it iff:
+ // this is our first expiryCheck and the session expired a long time ago
+ //or
+ //the session expired at least one graceperiod ago
+ if (_lastExpiryCheckTime <=0)
+ {
+ if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * (3 * _gracePeriodSec))))
+ expired.add(candidate);
+ }
+ else
+ {
+ if ((sd.getExpiry() > 0 ) && sd.getExpiry() < (now - (1000L * _gracePeriodSec)))
+ expired.add(candidate);
+ }
}
}
}
+ catch (Exception e)
+ {
+ LOG.warn("Error checking if candidate {} is expired", candidate, e);
+ }
}
- catch (Exception e)
+ }
+
+
+ /*
+ * 2. Select sessions for any node or context that have expired
+ * at least 1 graceperiod since the last expiry check. If we haven't done previous expiry checks, then check
+ * those that have expired at least 3 graceperiod ago.
+ */
+ if(_queryManager != null)
+ {
+ long upperBound = now;
+ if (_lastExpiryCheckTime <= 0)
+ upperBound = (now - (3*(1000L * _gracePeriodSec)));
+ else
+ upperBound = _lastExpiryCheckTime - (1000L * _gracePeriodSec);
+
+ if (LOG.isDebugEnabled()) LOG.debug("{}- Pass 2: Searching for sessions expired before {}", _context.getWorkerName(), upperBound);
+
+ for (String sessionId : _queryManager.queryExpiredSessions(upperBound))
{
- LOG.warn("Error checking if candidate {} is expired", candidate, e);
+ expired.add(sessionId);
+ if (LOG.isDebugEnabled()) LOG.debug ("{}- Found expired sessionId=",_context.getWorkerName(), sessionId);
}
}
-
+
return expired;
}
@@ -233,8 +276,8 @@ public boolean isPassivating()
{
return _passivating;
}
-
-
+
+
@Override
public boolean exists(String id) throws Exception
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java
similarity index 83%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java
index 291b80a6dc9a..71129ea911e0 100644
--- a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java
+++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionDataStoreFactory.java
@@ -20,6 +20,7 @@
package org.eclipse.jetty.session.infinispan;
import org.eclipse.jetty.server.session.AbstractSessionDataStoreFactory;
+import org.eclipse.jetty.server.session.SessionData;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.server.session.SessionDataStore;
import org.infinispan.commons.api.BasicCache;
@@ -32,8 +33,8 @@
public class InfinispanSessionDataStoreFactory extends AbstractSessionDataStoreFactory
{
int _infinispanIdleTimeoutSec;
- BasicCache _cache;
-
+ BasicCache _cache;
+ protected QueryManager _queryManager;
/**
* @return the infinispanIdleTimeoutSec
@@ -62,6 +63,7 @@ public SessionDataStore getSessionDataStore (SessionHandler handler) throws Exce
store.setInfinispanIdleTimeoutSec(getInfinispanIdleTimeoutSec());
store.setCache(getCache());
store.setSavePeriodSec(getSavePeriodSec());
+ store.setQueryManager(getQueryManager());
return store;
}
@@ -70,7 +72,7 @@ public SessionDataStore getSessionDataStore (SessionHandler handler) throws Exce
*
* @return the cache
*/
- public BasicCache getCache()
+ public BasicCache getCache()
{
return _cache;
}
@@ -82,10 +84,20 @@ public BasicCache getCache()
*
* @param cache the cache
*/
- public void setCache (BasicCache cache)
+ public void setCache (BasicCache cache)
{
this._cache = cache;
}
+ public QueryManager getQueryManager()
+ {
+ return _queryManager;
+ }
+
+ public void setQueryManager(QueryManager queryManager)
+ {
+ _queryManager = queryManager;
+ }
+
}
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java
similarity index 100%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/InfinispanSessionLegacyConverter.java
diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java
new file mode 100644
index 000000000000..764ac2405bf5
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/NullQueryManagerFactory.java
@@ -0,0 +1,36 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.session.infinispan;
+
+import org.eclipse.jetty.server.session.SessionData;
+import org.infinispan.commons.api.BasicCache;
+
+/**
+ * NullQueryManagerFactory
+ *
+ * Trivial impl of the QueryManagerFactory that does not support doing queries.
+ */
+public class NullQueryManagerFactory implements QueryManagerFactory
+{
+ @Override
+ public QueryManager getQueryManager(BasicCache cache)
+ {
+ return null;
+ }
+}
diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java
new file mode 100644
index 000000000000..33711c3a506c
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManager.java
@@ -0,0 +1,27 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.session.infinispan;
+
+import java.util.Set;
+
+public interface QueryManager
+{
+ Set queryExpiredSessions();
+ Set queryExpiredSessions(long currentTime);
+}
diff --git a/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java
new file mode 100644
index 000000000000..6475614a290c
--- /dev/null
+++ b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/QueryManagerFactory.java
@@ -0,0 +1,27 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.session.infinispan;
+
+import org.eclipse.jetty.server.session.SessionData;
+import org.infinispan.commons.api.BasicCache;
+
+public interface QueryManagerFactory
+{
+ public QueryManager getQueryManager(BasicCache cache);
+}
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java
similarity index 100%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/SessionDataMarshaller.java
diff --git a/jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java b/jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java
similarity index 100%
rename from jetty-infinispan/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java
rename to jetty-infinispan/infinispan-common/src/main/java/org/eclipse/jetty/session/infinispan/WebAppMarshaller.java
diff --git a/jetty-infinispan/src/main/resources/session.proto b/jetty-infinispan/infinispan-common/src/main/resources/session.proto
similarity index 100%
rename from jetty-infinispan/src/main/resources/session.proto
rename to jetty-infinispan/infinispan-common/src/main/resources/session.proto
diff --git a/jetty-infinispan/infinispan-embedded-query/pom.xml b/jetty-infinispan/infinispan-embedded-query/pom.xml
new file mode 100644
index 000000000000..d1f4bb36479a
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/pom.xml
@@ -0,0 +1,125 @@
+
+
+ org.eclipse.jetty
+ infinispan-parent
+ 9.4.16-SNAPSHOT
+
+ 4.0.0
+ infinispan-embedded-query
+ Jetty :: Infinispan Session Manager Embedded with Querying
+ http://www.eclipse.org/jetty
+
+ ${project.groupId}.infinispan.embedded.query
+
+
+ install
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ build-deps-file
+ generate-resources
+
+ list
+
+
+ false
+ ${project.build.directory}/deps.txt
+ true
+ org.eclipse.jetty,javax.servlet,org.slf4j
+ true
+ runtime
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ process-deps
+ process-resources
+
+ run
+
+
+
+
+
+
+
+
+
+ process-mod
+ process-resources
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+ src/main/assembly/config.xml
+
+
+
+
+
+
+
+
+
+ org.eclipse.jetty
+ infinispan-common
+ ${project.version}
+
+
+ org.infinispan
+ infinispan-core
+
+
+ org.infinispan
+ infinispan-commons
+
+
+
+
+ org.infinispan
+ infinispan-query
+ ${infinispan.version}
+
+
+ org.eclipse.jetty.toolchain
+ jetty-test-helper
+ test
+
+
+
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml b/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml
new file mode 100644
index 000000000000..7234f9b9e4ea
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/assembly/config.xml
@@ -0,0 +1,27 @@
+
+
+ config
+ false
+
+ jar
+
+
+
+ src/main/config-template
+
+
+ **
+
+
+ **/infinispan-query-libs.mod
+
+
+
+ target
+ modules
+
+ infinispan-query-libs.mod
+
+
+
+
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml
new file mode 100644
index 000000000000..9fe9caefbf5a
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/etc/sessions/infinispan/infinispan-embedded-query.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ expiry
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /etc/infinispan.xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jetty-query-sessions
+
+
+
+
+
+
+
+
+
+
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod
new file mode 100644
index 000000000000..73706051703f
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-embedded-query.mod
@@ -0,0 +1,20 @@
+[description]
+Enables querying with the Infinispan cache
+
+[tags]
+session
+
+[provides]
+infinispan-embedded
+
+[depends]
+infinispan-query-libs
+
+[lib]
+lib/infinispan/*.jar
+lib/infinispan-embedded-query-${jetty.version}.jar
+
+[xml]
+etc/sessions/infinispan/infinispan-embedded-query.xml
+etc/sessions/infinispan/infinispan-common.xml
+
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query-libs.mod b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query-libs.mod
new file mode 100644
index 000000000000..54b8a22e5c77
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query-libs.mod
@@ -0,0 +1,11 @@
+[description]
+The Infinispan query libraries
+
+[tags]
+3rdparty
+infinispan
+
+[depends]
+infinispan-query
+
+
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query.mod b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query.mod
new file mode 100644
index 000000000000..5a262b322ac1
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/config-template/modules/infinispan-query.mod
@@ -0,0 +1,16 @@
+[description]
+Enables querying with the Infinispan cache
+
+[tags]
+session
+3rdparty
+infinispan
+
+[license]
+Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+http://infinispan.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini]
+## Hide the infinispan libraries from deployed webapps
+jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/
diff --git a/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java
new file mode 100644
index 000000000000..e1810fb2c982
--- /dev/null
+++ b/jetty-infinispan/infinispan-embedded-query/src/main/java/org/eclipse/jetty/session/infinispan/EmbeddedQueryManager.java
@@ -0,0 +1,41 @@
+package org.eclipse.jetty.session.infinispan;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.jetty.server.session.SessionData;
+import org.infinispan.Cache;
+import org.infinispan.query.Search;
+import org.infinispan.query.dsl.Query;
+import org.infinispan.query.dsl.QueryFactory;
+
+public class EmbeddedQueryManager implements QueryManager
+{
+ private Cache _cache;
+
+ public EmbeddedQueryManager(Cache cache)
+ {
+ _cache = cache;
+ }
+
+ @Override
+ public Set queryExpiredSessions(long time)
+ {
+ QueryFactory qf = Search.getQueryFactory(_cache);
+ Query q = qf.from(SessionData.class).select("id").having("expiry").lte(time).build();
+
+ List
+
-
+
@@ -60,29 +74,17 @@
-
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-libs.mod b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-libs.mod
new file mode 100644
index 000000000000..aed7e5a4d41f
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-libs.mod
@@ -0,0 +1,11 @@
+[description]
+The Infinispan remote query libraries
+
+[tags]
+3rdparty
+infinispan
+
+[depends]
+infinispan-remote-query-serverclasses
+
+
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-serverclasses.mod b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-serverclasses.mod
new file mode 100644
index 000000000000..12571f52dfcb
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query-serverclasses.mod
@@ -0,0 +1,16 @@
+[description]
+Enables querying with a remote Infinispan cache
+
+[tags]
+session
+3rdparty
+infinispan
+
+[license]
+Infinispan is an open source project hosted on Github and released under the Apache 2.0 license.
+http://infinispan.org/
+http://www.apache.org/licenses/LICENSE-2.0.html
+
+[ini]
+## Hide the infinispan libraries from deployed webapps
+jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod
new file mode 100644
index 000000000000..a465ae1d0bea
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query.mod
@@ -0,0 +1,24 @@
+[description]
+Enables querying with a remote Infinispan cache
+
+[tags]
+session
+
+[provides]
+infinispan-remote
+
+[depends]
+infinispan-remote-query-libs
+
+[files]
+basehome:modules/infinispan-remote-query/hotrod-client.properties|resources/hotrod-client.properties
+basehome:modules/infinispan-remote-query/other_proto_marshallers.xml|etc/other_proto_marshallers.xml
+
+[lib]
+lib/infinispan/*.jar
+lib/infinispan-remote-query-${jetty.version}.jar
+
+[xml]
+etc/sessions/infinispan/infinispan-remote-query.xml
+etc/other_proto_marshallers.xml
+etc/sessions/infinispan/infinispan-common.xml
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/hotrod-client.properties b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/hotrod-client.properties
new file mode 100644
index 000000000000..bb774cd9c525
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/hotrod-client.properties
@@ -0,0 +1 @@
+#infinispan.client.hotrod.server_list
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/other_proto_marshallers.xml b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/other_proto_marshallers.xml
new file mode 100644
index 000000000000..494755ae7871
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/config-template/modules/infinispan-remote-query/other_proto_marshallers.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java
new file mode 100644
index 000000000000..c30e089e423b
--- /dev/null
+++ b/jetty-infinispan/infinispan-remote-query/src/main/java/org/eclipse/jetty/session/infinispan/RemoteQueryManager.java
@@ -0,0 +1,67 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2019 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.session.infinispan;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.eclipse.jetty.server.session.SessionData;
+import org.infinispan.client.hotrod.RemoteCache;
+import org.infinispan.client.hotrod.Search;
+import org.infinispan.query.dsl.Query;
+import org.infinispan.query.dsl.QueryFactory;
+
+/**
+ * RemoteQueryManager
+ *
+ * A QueryManager impl that supports doing queries against remote infinispan server.
+ *
+ */
+public class RemoteQueryManager implements QueryManager
+{
+ private RemoteCache _cache;
+
+ public RemoteQueryManager(RemoteCache cache)
+ {
+ _cache = cache;
+ }
+
+ @Override
+ public Set queryExpiredSessions(long time)
+ {
+ // TODO can the QueryFactory be created only once
+ QueryFactory qf = Search.getQueryFactory(_cache);
+ Query q = qf.from(InfinispanSessionData.class).select("id").having("expiry").lte(time).build();
+
+ List