keycloak-memoizeit

Merge pull request #1981 from stianst/master KEYCLOAK-2247

1/6/2016 4:19:35 PM

Changes

.travis.yml 10(+9 -1)

pom.xml 8(+4 -4)

Details

.travis.yml 10(+9 -1)

diff --git a/.travis.yml b/.travis.yml
index b2b3627..3da0679 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,10 +1,18 @@
 language: java
 
+env:
+  global:
+    - MAVEN_SKIP_RC=true
+    - MAVEN_OPTS="-Xms512m -Xmx2048m"
+
 jdk:
   - oraclejdk8
 
+before_script:
+  - export MAVEN_SKIP_RC=true
+
 install: 
-  - travis_wait mvn install -Pdistribution -DskipTests=true -B -V -q
+  - mvn install -Pdistribution -DskipTests=true -B -V -q
 
 script:
   - mvn test -B
diff --git a/distribution/feature-packs/server-feature-pack/feature-pack-build.xml b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml
index f920885..6ef7e7b 100644
--- a/distribution/feature-packs/server-feature-pack/feature-pack-build.xml
+++ b/distribution/feature-packs/server-feature-pack/feature-pack-build.xml
@@ -1,4 +1,26 @@
-<build xmlns="urn:wildfly:feature-pack-build:1.0">
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2014, Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags. See the copyright.txt file in the
+  ~ distribution for a full listing of individual contributors.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<build xmlns="urn:wildfly:feature-pack-build:1.1">
     <dependencies>
         <artifact name="org.wildfly:wildfly-feature-pack" />
     </dependencies>
@@ -8,20 +30,31 @@
             <property name="jgroups.supplement" value="" />
         </standalone>
         <domain template="configuration/domain/template.xml" subsystems="configuration/domain/subsystems.xml" output-file="domain/configuration/domain.xml" />
+        <host template="configuration/host/host.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host.xml" />
+        <host template="configuration/host/host-master.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host-master.xml" />
+        <host template="configuration/host/host-slave.xml" subsystems="configuration/host/subsystems.xml" output-file="domain/configuration/host-slave.xml" />
     </config>
 
     <mkdirs>
+        <dir name="domain/data/content"/>
+        <dir name="standalone/lib/ext"/>
+        <dir name="domain/tmp/auth"/>
+        <dir name="standalone/tmp/auth"/>
+        <dir name=".installation"/>
     </mkdirs>
     <file-permissions>
         <permission value="755">
             <filter pattern="*.sh" include="true"/>
+            <filter pattern="*" include="false"/>
         </permission>
         <permission value="700">
             <filter pattern="*/tmp/auth" include="true"/>
+            <filter pattern="*" include="false"/>
         </permission>
         <permission value="600">
             <filter pattern="*-users.properties" include="true" />
             <filter pattern="*/.installation" include="true"/>
+            <filter pattern="*" include="false"/>
         </permission>
     </file-permissions>
     <line-endings>
@@ -33,4 +66,4 @@
             <filter pattern="*.conf" include="true"/>
         </unix>
     </line-endings>
-</build>
\ No newline at end of file
+</build>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
index 29c6e63..bea2e10 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/subsystems.xml
@@ -53,63 +53,4 @@
       <subsystem supplement="ha">undertow.xml</subsystem>
       <subsystem>keycloak-server.xml</subsystem>
    </subsystems>
-   <subsystems name="full">
-      <!-- Each subsystem to be included relative to the src/main/resources directory -->
-      <subsystem>logging.xml</subsystem>
-      <subsystem>bean-validation.xml</subsystem>
-      <subsystem>keycloak-datasources.xml</subsystem>
-      <subsystem supplement="full">ee.xml</subsystem>
-      <subsystem supplement="full">ejb3.xml</subsystem>
-      <subsystem>io.xml</subsystem>
-      <subsystem>keycloak-infinispan.xml</subsystem>
-      <subsystem>iiop-openjdk.xml</subsystem>
-      <subsystem>jaxrs.xml</subsystem>
-      <subsystem>jca.xml</subsystem>
-      <subsystem>jdr.xml</subsystem>
-      <subsystem supplement="domain">jmx.xml</subsystem>
-      <subsystem>jpa.xml</subsystem>
-      <subsystem>jsf.xml</subsystem>
-      <subsystem>jsr77.xml</subsystem>
-      <subsystem>mail.xml</subsystem>
-      <subsystem>messaging.xml</subsystem>
-      <subsystem>naming.xml</subsystem>
-      <subsystem>remoting.xml</subsystem>
-      <subsystem>request-controller.xml</subsystem>
-      <subsystem>security.xml</subsystem>
-      <subsystem>security-manager.xml</subsystem>
-      <subsystem>transactions.xml</subsystem>
-      <subsystem>undertow.xml</subsystem>
-      <subsystem>keycloak-server.xml</subsystem>
-   </subsystems>
-   <subsystems name="full-ha">
-      <!-- Each subsystem to be included relative to the src/main/resources directory -->
-      <subsystem>logging.xml</subsystem>
-      <subsystem>bean-validation.xml</subsystem>
-      <subsystem>keycloak-datasources.xml</subsystem>
-      <subsystem supplement="full">ee.xml</subsystem>
-      <subsystem supplement="full-ha">ejb3.xml</subsystem>
-      <subsystem>io.xml</subsystem>
-      <subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
-      <subsystem>iiop-openjdk.xml</subsystem>
-      <subsystem>jaxrs.xml</subsystem>
-      <subsystem>jca.xml</subsystem>
-      <subsystem>jdr.xml</subsystem>
-      <subsystem>jgroups.xml</subsystem>
-      <subsystem supplement="domain">jmx.xml</subsystem>
-      <subsystem>jpa.xml</subsystem>
-      <subsystem>jsf.xml</subsystem>
-      <subsystem>jsr77.xml</subsystem>
-      <subsystem>mail.xml</subsystem>
-      <subsystem supplement="ha">messaging.xml</subsystem>
-      <subsystem>mod_cluster.xml</subsystem>
-      <subsystem>naming.xml</subsystem>
-      <subsystem>remoting.xml</subsystem>
-      <subsystem>resource-adapters.xml</subsystem>
-      <subsystem>request-controller.xml</subsystem>
-      <subsystem>security.xml</subsystem>
-      <subsystem>security-manager.xml</subsystem>
-      <subsystem>transactions.xml</subsystem>
-      <subsystem supplement="ha">undertow.xml</subsystem>
-      <subsystem>keycloak-server.xml</subsystem>
-   </subsystems>
 </config>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml
index 8c4464c..770d261 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/domain/template.xml
@@ -24,18 +24,12 @@
     </management>
 
     <profiles>
-        <profile name="default">
-            <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
-        </profile>
-        <profile name="ha">
-            <?SUBSYSTEMS socket-binding-group="ha-sockets"?>
-        </profile>
-        <profile name="full">
-            <?SUBSYSTEMS socket-binding-group="full-sockets"?>
-        </profile>
-        <profile name="full-ha">
-            <?SUBSYSTEMS socket-binding-group="full-ha-sockets"?>
-        </profile>
+       <profile name="default">
+           <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+       </profile>
+       <profile name="ha">
+           <?SUBSYSTEMS socket-binding-group="ha-sockets"?>
+       </profile>
     </profiles>
 
     <!--
@@ -60,28 +54,20 @@
             <!-- Needed for server groups using the 'ha' profile  -->
             <?SOCKET-BINDINGS?>
         </socket-binding-group>
-        <socket-binding-group name="full-sockets" default-interface="public">
-            <!-- Needed for server groups using the 'full' profile  -->
-            <?SOCKET-BINDINGS?>
-        </socket-binding-group>
-        <socket-binding-group name="full-ha-sockets" default-interface="public">
-            <!-- Needed for server groups using the 'full-ha' profile  -->
-            <?SOCKET-BINDINGS?>
-        </socket-binding-group>
     </socket-binding-groups>
 
     <server-groups>
-        <server-group name="main-server-group" profile="full">
+        <server-group name="main-server-group" profile="default">
             <jvm name="default">
                 <heap size="64m" max-size="512m"/>
             </jvm>
-            <socket-binding-group ref="full-sockets"/>
+            <socket-binding-group ref="standard-sockets"/>
         </server-group>
-        <server-group name="other-server-group" profile="full-ha">
+        <server-group name="other-server-group" profile="ha">
             <jvm name="default">
                 <heap size="64m" max-size="512m"/>
             </jvm>
-            <socket-binding-group ref="full-ha-sockets"/>
+            <socket-binding-group ref="ha-sockets"/>
         </server-group>
     </server-groups>
 
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml
new file mode 100644
index 0000000..501fae8
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host.xml
@@ -0,0 +1,110 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<host name="master" xmlns="urn:jboss:domain:4.0">
+    <extensions>
+        <?EXTENSIONS?>
+    </extensions>
+
+    <management>
+        <security-realms>
+            <security-realm name="ManagementRealm">
+                <authentication>
+                    <local default-user="$local" skip-group-loading="true"/>
+                    <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization map-groups-to-roles="false">
+                    <properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+            <security-realm name="ApplicationRealm">
+                <authentication>
+                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
+                    <properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization>
+                    <properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+        </security-realms>
+        <audit-log>
+            <formatters>
+                <json-formatter name="json-formatter"/>
+            </formatters>
+            <handlers>
+                <file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
+                <file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+            </handlers>
+            <logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="host-file"/>
+                </handlers>
+            </logger>
+            <server-logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="server-file"/>
+                </handlers>
+            </server-logger>
+        </audit-log>
+        <management-interfaces>
+            <native-interface security-realm="ManagementRealm">
+                <socket interface="management" port="${jboss.management.native.port:9999}"/>
+            </native-interface>
+            <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
+                <socket interface="management" port="${jboss.management.http.port:9990}"/>
+            </http-interface>
+        </management-interfaces>
+    </management>
+
+    <domain-controller>
+        <local/>
+        <!-- Alternative remote domain controller configuration with a host and port -->
+        <!-- <remote protocol="remote" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9999}" security-realm="ManagementRealm"/> -->
+    </domain-controller>
+
+    <interfaces>
+        <interface name="management">
+            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+        </interface>
+        <interface name="public">
+            <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+        </interface>
+
+        <?INTERFACES?>
+
+    </interfaces>
+
+    <jvms>
+        <jvm name="default">
+            <heap size="64m" max-size="256m"/>
+            <jvm-options>
+                <option value="-server"/>
+            </jvm-options>
+        </jvm>
+    </jvms>
+
+    <servers>
+        <server name="server-one" group="main-server-group">
+            <!-- Remote JPDA debugging for a specific server
+            <jvm name="default">
+              <jvm-options>
+                <option value="-agentlib:jdwp=transport=dt_socket,address=8787,server=y,suspend=n"/>
+              </jvm-options>
+           </jvm>
+           -->
+        </server>
+        <server name="server-two" group="main-server-group" auto-start="true">
+            <!-- server-two avoids port conflicts by incrementing the ports in
+                 the default socket-group declared in the server-group -->
+            <socket-bindings port-offset="150"/>
+        </server>
+        <server name="server-three" group="other-server-group" auto-start="false">
+            <!-- server-three avoids port conflicts by incrementing the ports in
+                 the default socket-group declared in the server-group -->
+            <socket-bindings port-offset="250"/>
+        </server>
+    </servers>
+
+    <profile>
+        <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+    </profile>
+</host>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml
new file mode 100644
index 0000000..5d959bd
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-master.xml
@@ -0,0 +1,85 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+   A simple configuration for a Host Controller that only acts as the master domain controller
+   and does not itself directly control any servers.
+-->
+<host name="master" xmlns="urn:jboss:domain:4.0">
+    <extensions>
+        <?EXTENSIONS?>
+    </extensions>
+
+    <management>
+        <security-realms>
+            <security-realm name="ManagementRealm">
+                <authentication>
+                    <local default-user="$local" skip-group-loading="true"/>
+                    <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization map-groups-to-roles="false">
+                    <properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+            <security-realm name="ApplicationRealm">
+                <authentication>
+                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
+                    <properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization>
+                    <properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+        </security-realms>
+        <audit-log>
+            <formatters>
+                <json-formatter name="json-formatter"/>
+            </formatters>
+            <handlers>
+                <file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
+                <file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+            </handlers>
+            <logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="host-file"/>
+                </handlers>
+            </logger>
+            <server-logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="server-file"/>
+                </handlers>
+            </server-logger>
+        </audit-log>
+        <management-interfaces>
+            <native-interface security-realm="ManagementRealm">
+                <socket interface="management" port="${jboss.management.native.port:9999}"/>
+            </native-interface>
+            <http-interface security-realm="ManagementRealm" http-upgrade-enabled="true">
+                <socket interface="management" port="${jboss.management.http.port:9990}"/>
+            </http-interface>
+        </management-interfaces>
+    </management>
+
+    <domain-controller>
+        <local/>
+    </domain-controller>
+
+    <interfaces>
+        <interface name="management">
+            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+        </interface>
+    </interfaces>
+
+    <jvms>
+        <jvm name="default">
+            <heap size="64m" max-size="256m"/>
+            <jvm-options>
+                <option value="-server"/>
+            </jvm-options>
+        </jvm>
+    </jvms>
+
+    <profile>
+        <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+    </profile>
+
+</host>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml
new file mode 100644
index 0000000..4b79b0a
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/host-slave.xml
@@ -0,0 +1,101 @@
+<?xml version='1.0' encoding='UTF-8'?>
+
+<host xmlns="urn:jboss:domain:4.0">
+    <extensions>
+        <?EXTENSIONS?>
+    </extensions>
+
+    <management>
+        <security-realms>
+            <security-realm name="ManagementRealm">
+                <server-identities>
+                    <!-- Replace this with either a base64 password of your own, or use a vault with a vault expression -->
+                    <secret value="c2xhdmVfdXNlcl9wYXNzd29yZA=="/>
+                </server-identities>
+
+                <authentication>
+                    <local default-user="$local" skip-group-loading="true"/>
+                    <properties path="mgmt-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization map-groups-to-roles="false">
+                    <properties path="mgmt-groups.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+            <security-realm name="ApplicationRealm">
+                <authentication>
+                    <local default-user="$local" allowed-users="*" skip-group-loading="true"/>
+                    <properties path="application-users.properties" relative-to="jboss.domain.config.dir"/>
+                </authentication>
+                <authorization>
+                    <properties path="application-roles.properties" relative-to="jboss.domain.config.dir"/>
+                </authorization>
+            </security-realm>
+        </security-realms>
+        <audit-log>
+            <formatters>
+                <json-formatter name="json-formatter"/>
+            </formatters>
+            <handlers>
+                <file-handler name="host-file" formatter="json-formatter" relative-to="jboss.domain.data.dir" path="audit-log.log"/>
+                <file-handler name="server-file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+            </handlers>
+            <logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="host-file"/>
+                </handlers>
+            </logger>
+            <server-logger log-boot="true" log-read-only="false" enabled="false">
+                <handlers>
+                    <handler name="server-file"/>
+                </handlers>
+            </server-logger>
+        </audit-log>
+        <management-interfaces>
+            <native-interface security-realm="ManagementRealm">
+                <socket interface="management" port="${jboss.management.native.port:9999}"/>
+            </native-interface>
+        </management-interfaces>
+    </management>
+
+    <domain-controller>
+        <remote security-realm="ManagementRealm">
+            <discovery-options>
+                <static-discovery name="primary" protocol="${jboss.domain.master.protocol:remote}" host="${jboss.domain.master.address}" port="${jboss.domain.master.port:9999}"/>
+            </discovery-options>
+        </remote>
+    </domain-controller>
+
+    <interfaces>
+        <interface name="management">
+            <inet-address value="${jboss.bind.address.management:127.0.0.1}"/>
+        </interface>
+        <interface name="public">
+            <inet-address value="${jboss.bind.address:127.0.0.1}"/>
+        </interface>
+
+        <?INTERFACES?>
+
+    </interfaces>
+
+    <jvms>
+        <jvm name="default">
+            <heap size="64m" max-size="256m"/>
+            <jvm-options>
+                <option value="-server"/>
+            </jvm-options>
+        </jvm>
+    </jvms>
+
+    <servers>
+        <server name="server-one" group="main-server-group"/>
+        <server name="server-two" group="other-server-group">
+            <!-- server-two avoids port conflicts by incrementing the ports in
+                 the default socket-group declared in the server-group -->
+            <socket-bindings port-offset="150"/>
+        </server>
+    </servers>
+
+    <profile>
+        <?SUBSYSTEMS socket-binding-group="standard-sockets"?>
+    </profile>
+</host>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml
new file mode 100644
index 0000000..3df2a95
--- /dev/null
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/host/subsystems.xml
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+  ~ JBoss, Home of Professional Open Source.
+  ~ Copyright 2015, Red Hat, Inc., and individual contributors
+  ~ as indicated by the @author tags. See the copyright.txt file in the
+  ~ distribution for a full listing of individual contributors.
+  ~
+  ~ This is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU Lesser General Public License as
+  ~ published by the Free Software Foundation; either version 2.1 of
+  ~ the License, or (at your option) any later version.
+  ~
+  ~ This software is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+  ~ Lesser General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Lesser General Public
+  ~ License along with this software; if not, write to the Free
+  ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+  ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+  -->
+
+<!--  See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
+<config>
+    <subsystems>
+        <subsystem>jmx.xml</subsystem>
+    </subsystems>
+</config>
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
index 151ab71..bf84e79 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/subsystems-ha.xml
@@ -1,30 +1,30 @@
 <?xml version='1.0' encoding='UTF-8'?>
 <!--  See src/resources/configuration/ReadMe.txt for how the configuration assembly works -->
 <config>
-   <subsystems>
-      <subsystem>logging.xml</subsystem>
-      <subsystem>bean-validation.xml</subsystem>
-      <subsystem>keycloak-datasources.xml</subsystem>
-      <subsystem>ee.xml</subsystem>
-      <subsystem supplement="ha">ejb3.xml</subsystem>
-      <subsystem>io.xml</subsystem>
-      <subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
-      <subsystem>jaxrs.xml</subsystem>
-      <subsystem>jca.xml</subsystem>
-      <subsystem>jdr.xml</subsystem>
-      <subsystem>jgroups.xml</subsystem>
-      <subsystem>jmx.xml</subsystem>
-      <subsystem>jpa.xml</subsystem>
-      <subsystem>jsf.xml</subsystem>
-      <subsystem>mail.xml</subsystem>
-      <subsystem>mod_cluster.xml</subsystem>
-      <subsystem>naming.xml</subsystem>
-      <subsystem>remoting.xml</subsystem>
-      <subsystem>request-controller.xml</subsystem>
-      <subsystem>security-manager.xml</subsystem>
-      <subsystem>security.xml</subsystem>
-      <subsystem>transactions.xml</subsystem>
-      <subsystem supplement="ha">undertow.xml</subsystem>
-      <subsystem>keycloak-server.xml</subsystem>
-   </subsystems>
+    <subsystems>
+        <subsystem>logging.xml</subsystem>
+        <subsystem>bean-validation.xml</subsystem>
+        <subsystem>keycloak-datasources.xml</subsystem>
+        <subsystem>ee.xml</subsystem>
+        <subsystem supplement="ha">ejb3.xml</subsystem>
+        <subsystem>io.xml</subsystem>
+        <subsystem supplement="ha">keycloak-infinispan.xml</subsystem>
+        <subsystem>jaxrs.xml</subsystem>
+        <subsystem>jca.xml</subsystem>
+        <subsystem>jdr.xml</subsystem>
+        <subsystem>jgroups.xml</subsystem>
+        <subsystem>jmx.xml</subsystem>
+        <subsystem>jpa.xml</subsystem>
+        <subsystem>jsf.xml</subsystem>
+        <subsystem>mail.xml</subsystem>
+        <subsystem>mod_cluster.xml</subsystem>
+        <subsystem>naming.xml</subsystem>
+        <subsystem>remoting.xml</subsystem>
+        <subsystem>request-controller.xml</subsystem>
+        <subsystem>security-manager.xml</subsystem>
+        <subsystem>security.xml</subsystem>
+        <subsystem>transactions.xml</subsystem>
+        <subsystem supplement="ha">undertow.xml</subsystem>
+        <subsystem>keycloak-server.xml</subsystem>
+    </subsystems>
 </config>
\ No newline at end of file
diff --git a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml
index 76fbe9e..4df055c 100644
--- a/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml
+++ b/distribution/feature-packs/server-feature-pack/src/main/resources/configuration/standalone/template.xml
@@ -29,15 +29,15 @@
         </security-realms>
         <audit-log>
             <formatters>
-                <json-formatter name="json-formatter"/>
-            </formatters>
+               <json-formatter name="json-formatter"/>
+            </formatters>        
             <handlers>
-                <file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
+               <file-handler name="file" formatter="json-formatter" relative-to="jboss.server.data.dir" path="audit-log.log"/>
             </handlers>
             <logger log-boot="true" log-read-only="false" enabled="false">
-                <handlers>
-                    <handler name="file"/>
-                </handlers>
+               <handlers>
+                  <handler name="file"/>
+               </handlers>
             </logger>
         </audit-log>
         <management-interfaces>
@@ -69,8 +69,9 @@
         <interface name="public">
             <inet-address value="${jboss.bind.address:127.0.0.1}"/>
         </interface>
-        <!-- TODO - only show this if the jacorb subsystem is added  -->
+
         <?INTERFACES?>
+
     </interfaces>
 
     <socket-binding-group name="standard-sockets" default-interface="public" port-offset="${jboss.socket.binding.port-offset:0}">
@@ -80,4 +81,4 @@
         <?SOCKET-BINDINGS?>
 
     </socket-binding-group>
-</server>
\ No newline at end of file
+</server>
diff --git a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
index 0c1df9c..f2acf49 100755
--- a/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
+++ b/model/api/src/main/java/org/keycloak/models/UserSessionProvider.java
@@ -23,14 +23,12 @@ public interface UserSessionProvider extends Provider {
     List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId);
     UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId);
 
-    List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue);
-
-    int getActiveUserSessions(RealmModel realm, ClientModel client);
+    long getActiveUserSessions(RealmModel realm, ClientModel client);
     void removeUserSession(RealmModel realm, UserSessionModel session);
     void removeUserSessions(RealmModel realm, UserModel user);
 
     // Implementation should propagate removal of expired userSessions to userSessionPersister too
-    void removeExpiredUserSessions(RealmModel realm);
+    void removeExpired(RealmModel realm);
     void removeUserSessions(RealmModel realm);
     void removeClientSession(RealmModel realm, ClientSessionModel clientSession);
 
@@ -56,7 +54,7 @@ public interface UserSessionProvider extends Provider {
     // Don't remove userSession even if it's last userSession
     void removeOfflineClientSession(RealmModel realm, String clientSessionId);
 
-    int getOfflineSessionsCount(RealmModel realm, ClientModel client);
+    long getOfflineSessionsCount(RealmModel realm, ClientModel client);
     List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max);
 
     // Triggered by persister during pre-load
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java
index db20ef8..693db67 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/compat/MemUserSessionProvider.java
@@ -177,17 +177,6 @@ public class MemUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) {
-        List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
-        for (UserSessionEntity s : this.userSessions.values()) {
-            if (s.getRealm().equals(realm.getId()) && noteValue.equals(s.getNotes().get(noteName))) {
-                userSessions.add(new UserSessionAdapter(session, this, realm, s));
-            }
-        }
-        return userSessions;
-    }
-
-    @Override
     public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
         return getUserSessions(realm, client, false);
     }
@@ -230,7 +219,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+    public long getActiveUserSessions(RealmModel realm, ClientModel client) {
         return getUserSessions(realm, client, false).size();
     }
 
@@ -287,7 +276,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public void removeExpiredUserSessions(RealmModel realm) {
+    public void removeExpired(RealmModel realm) {
         UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
 
         Iterator<UserSessionEntity> itr = userSessions.values().iterator();
@@ -565,7 +554,7 @@ public class MemUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public int getOfflineSessionsCount(RealmModel realm, ClientModel client) {
+    public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
         return getUserSessions(realm, client, true).size();
     }
 
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java
new file mode 100644
index 0000000..bcd72e7
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/CompatInfinispanUserSessionProvider.java
@@ -0,0 +1,387 @@
+package org.keycloak.models.sessions.infinispan;
+
+import org.infinispan.Cache;
+import org.infinispan.distexec.mapreduce.MapReduceTask;
+import org.jboss.logging.Logger;
+import org.keycloak.common.util.Time;
+import org.keycloak.models.*;
+import org.keycloak.models.session.UserSessionPersisterProvider;
+import org.keycloak.models.sessions.infinispan.entities.*;
+import org.keycloak.models.sessions.infinispan.mapreduce.*;
+import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RealmInfoUtil;
+
+import java.util.*;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class CompatInfinispanUserSessionProvider extends InfinispanUserSessionProvider {
+
+    private static final Logger log = Logger.getLogger(CompatInfinispanUserSessionProvider.class);
+
+    public CompatInfinispanUserSessionProvider(KeycloakSession session, Cache<String, SessionEntity> sessionCache, Cache<String, SessionEntity> offlineSessionCache,
+                                         Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache) {
+        super(session, sessionCache, offlineSessionCache, loginFailureCache);
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user) {
+        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        return wrapUserSessions(realm, sessions.values(), false);
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
+        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).brokerUserId(brokerUserId))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        return wrapUserSessions(realm, sessions.values(), false);
+    }
+
+    @Override
+    public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
+        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        List<UserSessionModel> userSessionModels = wrapUserSessions(realm, sessions.values(), false);
+        if (userSessionModels.isEmpty()) return null;
+        return userSessionModels.get(0);
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client) {
+        return getUserSessions(realm, client, -1, -1);
+    }
+
+    @Override
+    public List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults) {
+        return getUserSessions(realm, client, firstResult, maxResults, false);
+    }
+
+    protected List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        Map<String, Integer> map = new MapReduceTask(cache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
+                .reducedWith(new LargestResultReducer())
+                .execute();
+
+        List<Map.Entry<String, Integer>> sessionTimestamps = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
+
+        Collections.sort(sessionTimestamps, new Comparator<Map.Entry<String, Integer>>() {
+            @Override
+            public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
+                return e1.getValue().compareTo(e2.getValue());
+            }
+        });
+
+        if (firstResult != -1 || maxResults == -1) {
+            if (firstResult == -1) {
+                firstResult = 0;
+            }
+
+            if (maxResults == -1) {
+                maxResults = Integer.MAX_VALUE;
+            }
+
+            if (firstResult > sessionTimestamps.size()) {
+                return Collections.emptyList();
+            }
+
+            int toIndex = (firstResult + maxResults) < sessionTimestamps.size() ? firstResult + maxResults : sessionTimestamps.size();
+            sessionTimestamps = sessionTimestamps.subList(firstResult, toIndex);
+        }
+
+        List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
+        for (Map.Entry<String, Integer> e : sessionTimestamps) {
+            UserSessionEntity userSessionEntity = (UserSessionEntity) cache.get(e.getKey());
+            if (userSessionEntity != null) {
+                userSessions.add(wrap(realm, userSessionEntity, offline));
+            }
+        }
+
+        return userSessions;
+    }
+
+    @Override
+    public long getActiveUserSessions(RealmModel realm, ClientModel client) {
+        return getUserSessionsCount(realm, client, false);
+    }
+
+    protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        Map map = new MapReduceTask(cache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
+                .reducedWith(new LargestResultReducer()).execute();
+
+        return map.size();
+    }
+
+    @Override
+    public void removeUserSession(RealmModel realm, UserSessionModel session) {
+        removeUserSession(realm, session.getId());
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm, UserModel user) {
+        removeUserSessions(realm, user, false);
+    }
+
+    protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        Map<String, String> sessions = new MapReduceTask(cache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : sessions.keySet()) {
+            removeUserSession(realm, id, offline);
+        }
+    }
+
+    @Override
+    public void removeExpired(RealmModel realm) {
+        UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
+
+        int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
+        int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
+        int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
+        int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
+
+        Map<String, String> map = new MapReduceTask(sessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).expired(expired, expiredRefresh).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : map.keySet()) {
+            removeUserSession(realm, id);
+        }
+
+        map = new MapReduceTask(sessionCache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession(true).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : map.keySet()) {
+            tx.remove(sessionCache, id);
+        }
+
+        // Remove expired offline user sessions
+        Map<String, SessionEntity> map2 = new MapReduceTask(offlineSessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (Map.Entry<String, SessionEntity> entry : map2.entrySet()) {
+            String userSessionId = entry.getKey();
+            tx.remove(offlineSessionCache, userSessionId);
+            // Propagate to persister
+            persister.removeUserSession(userSessionId, true);
+
+            UserSessionEntity entity = (UserSessionEntity) entry.getValue();
+            for (String clientSessionId : entity.getClientSessions()) {
+                tx.remove(offlineSessionCache, clientSessionId);
+            }
+        }
+
+        // Remove expired offline client sessions
+        map = new MapReduceTask(offlineSessionCache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredOffline).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String clientSessionId : map.keySet()) {
+            tx.remove(offlineSessionCache, clientSessionId);
+            persister.removeClientSession(clientSessionId, true);
+        }
+
+        // Remove expired client initial access
+        map = new MapReduceTask(sessionCache)
+                .mappedWith(ClientInitialAccessMapper.create(realm.getId()).expired(Time.currentTime()).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : map.keySet()) {
+            tx.remove(sessionCache, id);
+        }
+    }
+
+    @Override
+    public void removeUserSessions(RealmModel realm) {
+        removeUserSessions(realm, false);
+    }
+
+    protected void removeUserSessions(RealmModel realm, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        Map<String, String> ids = new MapReduceTask(cache)
+                .mappedWith(SessionMapper.create(realm.getId()).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : ids.keySet()) {
+            cache.remove(id);
+        }
+    }
+
+    @Override
+    public void removeUserLoginFailure(RealmModel realm, String username) {
+        LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
+        tx.remove(loginFailureCache, key);
+    }
+
+    @Override
+    public void removeAllUserLoginFailures(RealmModel realm) {
+        Map<LoginFailureKey, Object> sessions = new MapReduceTask(loginFailureCache)
+                .mappedWith(UserLoginFailureMapper.create(realm.getId()).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (LoginFailureKey id : sessions.keySet()) {
+            tx.remove(loginFailureCache, id);
+        }
+    }
+
+    @Override
+    public void onRealmRemoved(RealmModel realm) {
+        removeUserSessions(realm, true);
+        removeUserSessions(realm, false);
+        removeAllUserLoginFailures(realm);
+    }
+
+    @Override
+    public void onClientRemoved(RealmModel realm, ClientModel client) {
+        onClientRemoved(realm, client, true);
+        onClientRemoved(realm, client, false);
+    }
+
+    private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        Map<String, ClientSessionEntity> map = new MapReduceTask(cache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (Map.Entry<String, ClientSessionEntity> entry : map.entrySet()) {
+
+            // detach from userSession
+            ClientSessionAdapter adapter = wrap(realm, entry.getValue(), offline);
+            adapter.setUserSession(null);
+
+            tx.remove(cache, entry.getKey());
+        }
+    }
+
+    @Override
+    public void onUserRemoved(RealmModel realm, UserModel user) {
+        removeUserSessions(realm, user, true);
+        removeUserSessions(realm, user, false);
+
+        loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getUsername()));
+        loginFailureCache.remove(new LoginFailureKey(realm.getId(), user.getEmail()));
+    }
+
+    @Override
+    public void removeClientSession(RealmModel realm, ClientSessionModel clientSession) {
+        removeClientSession(realm, clientSession, false);
+    }
+
+    protected void removeClientSession(RealmModel realm, ClientSessionModel clientSession, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        UserSessionModel userSession = clientSession.getUserSession();
+        if (userSession != null)  {
+            UserSessionEntity entity = ((UserSessionAdapter) userSession).getEntity();
+            if (entity.getClientSessions() != null) {
+                entity.getClientSessions().remove(clientSession.getId());
+
+            }
+            tx.replace(cache, entity.getId(), entity);
+        }
+        tx.remove(cache, clientSession.getId());
+    }
+
+    protected void removeUserSession(RealmModel realm, String userSessionId) {
+        removeUserSession(realm, userSessionId, false);
+    }
+
+    protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
+        Cache<String, SessionEntity> cache = getCache(offline);
+
+        tx.remove(cache, userSessionId);
+
+        // TODO: Isn't more effective to retrieve from userSessionEntity directly?
+        Map<String, String> map = new MapReduceTask(cache)
+                .mappedWith(ClientSessionMapper.create(realm.getId()).userSession(userSessionId).emitKey())
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        for (String id : map.keySet()) {
+            tx.remove(cache, id);
+        }
+    }
+
+    @Override
+    public void removeOfflineUserSession(RealmModel realm, String userSessionId) {
+        removeUserSession(realm, userSessionId, true);
+    }
+
+    @Override
+    public List<ClientSessionModel> getOfflineClientSessions(RealmModel realm, UserModel user) {
+        Map<String, UserSessionEntity> sessions = new MapReduceTask(offlineSessionCache)
+                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+
+        List<ClientSessionEntity> clientSessions = new LinkedList<>();
+        for (UserSessionEntity userSession : sessions.values()) {
+            Set<String> currClientSessions = userSession.getClientSessions();
+            for (String clientSessionId : currClientSessions) {
+                ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
+                if (cls != null) {
+                    clientSessions.add(cls);
+                }
+            }
+        }
+
+        return wrapClientSessions(realm, clientSessions, true);
+    }
+
+    @Override
+    public void removeOfflineClientSession(RealmModel realm, String clientSessionId) {
+        ClientSessionModel clientSession = getOfflineClientSession(realm, clientSessionId);
+        removeClientSession(realm, clientSession, true);
+    }
+
+    @Override
+    public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
+        return getUserSessionsCount(realm, client, true);
+    }
+
+    @Override
+    public List<UserSessionModel> getOfflineUserSessions(RealmModel realm, ClientModel client, int first, int max) {
+        return getUserSessions(realm, client, first, max, true);
+    }
+
+    @Override
+    public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
+        Map<String, ClientInitialAccessEntity> entities = new MapReduceTask(sessionCache)
+                .mappedWith(ClientInitialAccessMapper.create(realm.getId()))
+                .reducedWith(new FirstResultReducer())
+                .execute();
+        return wrapClientInitialAccess(realm, entities.values());
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java
new file mode 100644
index 0000000..0eed330
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/Consumers.java
@@ -0,0 +1,66 @@
+package org.keycloak.models.sessions.infinispan;
+
+import org.keycloak.models.RealmModel;
+import org.keycloak.models.UserSessionModel;
+import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Consumers {
+
+    private Consumers() {
+    }
+
+    public static UserSessionModelsConsumer userSessionModels(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
+        return new UserSessionModelsConsumer(provider, realm, offline);
+    }
+
+    public static class UserSessionIdAndTimestampConsumer implements Consumer<Map.Entry<String, SessionEntity>> {
+
+        private Map<String, Integer> sessions = new HashMap<>();
+
+        @Override
+        public void accept(Map.Entry<String, SessionEntity> entry) {
+            SessionEntity e = entry.getValue();
+            if (e instanceof ClientSessionEntity) {
+                ClientSessionEntity ce = (ClientSessionEntity) e;
+                sessions.put(ce.getUserSession(), ce.getTimestamp());
+            }
+        }
+
+    }
+
+    public static class UserSessionModelsConsumer implements Consumer<Map.Entry<String, SessionEntity>> {
+
+        private InfinispanUserSessionProvider provider;
+        private RealmModel realm;
+        private boolean offline;
+        private List<UserSessionModel> sessions = new LinkedList<>();
+
+        private UserSessionModelsConsumer(InfinispanUserSessionProvider provider, RealmModel realm, boolean offline) {
+            this.provider = provider;
+            this.realm = realm;
+            this.offline = offline;
+        }
+
+        @Override
+        public void accept(Map.Entry<String, SessionEntity> entry) {
+            SessionEntity e = entry.getValue();
+            sessions.add(provider.wrap(realm, (UserSessionEntity) e, offline));
+        }
+
+        public List<UserSessionModel> getSessions() {
+            return sessions;
+        }
+
+    }
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
index d89f47b..7e66b12 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider.java
@@ -1,25 +1,21 @@
 package org.keycloak.models.sessions.infinispan;
 
 import org.infinispan.Cache;
-import org.infinispan.distexec.mapreduce.MapReduceTask;
+import org.infinispan.CacheStream;
 import org.jboss.logging.Logger;
+import org.keycloak.common.util.Time;
 import org.keycloak.models.*;
 import org.keycloak.models.session.UserSessionPersisterProvider;
 import org.keycloak.models.sessions.infinispan.entities.*;
-import org.keycloak.models.sessions.infinispan.mapreduce.*;
+import org.keycloak.models.sessions.infinispan.stream.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.RealmInfoUtil;
-import org.keycloak.common.util.Time;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -28,11 +24,11 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
 
     private static final Logger log = Logger.getLogger(InfinispanUserSessionProvider.class);
 
-    private final KeycloakSession session;
-    private final Cache<String, SessionEntity> sessionCache;
-    private final Cache<String, SessionEntity> offlineSessionCache;
-    private final Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache;
-    private final InfinispanKeycloakTransaction tx;
+    protected final KeycloakSession session;
+    protected final Cache<String, SessionEntity> sessionCache;
+    protected final Cache<String, SessionEntity> offlineSessionCache;
+    protected final Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache;
+    protected final InfinispanKeycloakTransaction tx;
 
     public InfinispanUserSessionProvider(KeycloakSession session, Cache<String, SessionEntity> sessionCache, Cache<String, SessionEntity> offlineSessionCache,
                                          Cache<LoginFailureKey, LoginFailureEntity> loginFailureCache) {
@@ -139,36 +135,31 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         return wrap(realm, entity, offline);
     }
 
-    @Override
-    public List<UserSessionModel> getUserSessions(RealmModel realm, UserModel user) {
-        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
-                .reducedWith(new FirstResultReducer())
-                .execute();
+    protected List<UserSessionModel> getUserSessions(RealmModel realm, Predicate<Map.Entry<String, SessionEntity>> predicate, boolean offline) {
+        CacheStream<Map.Entry<String, SessionEntity>> cacheStream = getCache(offline).entrySet().stream();
+        Iterator<Map.Entry<String, SessionEntity>> itr = cacheStream.filter(predicate).iterator();
+        List<UserSessionModel> sessions = new LinkedList<>();
+        while (itr.hasNext()) {
+            UserSessionEntity e = (UserSessionEntity) itr.next().getValue();
+            sessions.add(wrap(realm, e, offline));
+        }
+        return sessions;
+    }
 
-        return wrapUserSessions(realm, sessions.values(), false);
+    @Override
+    public List<UserSessionModel> getUserSessions(final RealmModel realm, UserModel user) {
+        return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).user(user.getId()), false);
     }
 
     @Override
     public List<UserSessionModel> getUserSessionByBrokerUserId(RealmModel realm, String brokerUserId) {
-        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).brokerUserId(brokerUserId))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        return wrapUserSessions(realm, sessions.values(), false);
+        return getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerUserId(brokerUserId), false);
     }
 
     @Override
     public UserSessionModel getUserSessionByBrokerSessionId(RealmModel realm, String brokerSessionId) {
-        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).brokerSessionId(brokerSessionId))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        List<UserSessionModel> userSessionModels = wrapUserSessions(realm, sessions.values(), false);
-        if (userSessionModels.isEmpty()) return null;
-        return userSessionModels.get(0);
+        List<UserSessionModel> userSessions = getUserSessions(realm, UserSessionPredicate.create(realm.getId()).brokerSessionId(brokerSessionId), false);
+        return userSessions.isEmpty() ? null : userSessions.get(0);
     }
 
     @Override
@@ -181,86 +172,58 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         return getUserSessions(realm, client, firstResult, maxResults, false);
     }
 
-    protected List<UserSessionModel> getUserSessions(RealmModel realm, ClientModel client, int firstResult, int maxResults, boolean offline) {
-        Cache<String, SessionEntity> cache = getCache(offline);
+    protected List<UserSessionModel> getUserSessions(final RealmModel realm, ClientModel client, int firstResult, int maxResults, final boolean offline) {
+        final Cache<String, SessionEntity> cache = getCache(offline);
 
-        Map<String, Integer> map = new MapReduceTask(cache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
-                .reducedWith(new LargestResultReducer())
-                .execute();
+        Iterator<UserSessionTimestamp> itr = cache.entrySet().stream()
+                .filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession())
+                .map(Mappers.clientSessionToUserSessionTimestamp())
+                .iterator();
 
-        List<Map.Entry<String, Integer>> sessionTimestamps = new LinkedList<Map.Entry<String, Integer>>(map.entrySet());
-
-        Collections.sort(sessionTimestamps, new Comparator<Map.Entry<String, Integer>>() {
-            @Override
-            public int compare(Map.Entry<String, Integer> e1, Map.Entry<String, Integer> e2) {
-                return e1.getValue().compareTo(e2.getValue());
-            }
-        });
-
-        if (firstResult != -1 || maxResults == -1) {
-            if (firstResult == -1) {
-                firstResult = 0;
+        Map<String, UserSessionTimestamp> m = new HashMap<>();
+        while(itr.hasNext()) {
+            UserSessionTimestamp next = itr.next();
+            if (!m.containsKey(next.getUserSessionId()) || m.get(next.getUserSessionId()).getClientSessionTimestamp() < next.getClientSessionTimestamp()) {
+                m.put(next.getUserSessionId(), next);
             }
+        }
 
-            if (maxResults == -1) {
-                maxResults = Integer.MAX_VALUE;
-            }
+        Stream<UserSessionTimestamp> stream = new LinkedList<>(m.values()).stream().sorted(Comparators.userSessionTimestamp());
 
-            if (firstResult > sessionTimestamps.size()) {
-                return Collections.emptyList();
-            }
-
-            int toIndex = (firstResult + maxResults) < sessionTimestamps.size() ? firstResult + maxResults : sessionTimestamps.size();
-            sessionTimestamps = sessionTimestamps.subList(firstResult, toIndex);
+        if (firstResult > 0) {
+            stream = stream.skip(firstResult);
         }
 
-        List<UserSessionModel> userSessions = new LinkedList<UserSessionModel>();
-        for (Map.Entry<String, Integer> e : sessionTimestamps) {
-            UserSessionEntity userSessionEntity = (UserSessionEntity) cache.get(e.getKey());
-            if (userSessionEntity != null) {
-                userSessions.add(wrap(realm, userSessionEntity, offline));
-            }
+        if (maxResults > 0) {
+            stream = stream.limit(maxResults);
         }
 
-        return userSessions;
-    }
-
-    @Override
-    public List<UserSessionModel> getUserSessionsByNote(RealmModel realm, String noteName, String noteValue) {
-        HashMap<String, String> notes = new HashMap<>();
-        notes.put(noteName, noteValue);
-        return getUserSessionsByNotes(realm, notes);
-    }
-
-    public List<UserSessionModel> getUserSessionsByNotes(RealmModel realm, Map<String, String> notes) {
-        Map<String, UserSessionEntity> sessions = new MapReduceTask(sessionCache)
-                .mappedWith(UserSessionNoteMapper.create(realm.getId()).notes(notes))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        return wrapUserSessions(realm, sessions.values(), false);
+        final List<UserSessionModel> sessions = new LinkedList<>();
+        stream.forEach(new Consumer<UserSessionTimestamp>() {
+            @Override
+            public void accept(UserSessionTimestamp userSessionTimestamp) {
+                SessionEntity entity = cache.get(userSessionTimestamp.getUserSessionId());
+                if (entity != null) {
+                    sessions.add(wrap(realm, (UserSessionEntity) entity, offline));
+                }
+            }
+        });
 
+        return sessions;
     }
 
     @Override
-    public int getActiveUserSessions(RealmModel realm, ClientModel client) {
+    public long getActiveUserSessions(RealmModel realm, ClientModel client) {
         return getUserSessionsCount(realm, client, false);
     }
 
-    protected int getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
-        Cache<String, SessionEntity> cache = getCache(offline);
-
-        Map map = new MapReduceTask(cache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()).emitUserSessionAndTimestamp())
-                .reducedWith(new LargestResultReducer()).execute();
-
-        return map.size();
+    protected long getUserSessionsCount(RealmModel realm, ClientModel client, boolean offline) {
+        return getCache(offline).entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId()).requireUserSession()).map(Mappers.clientSessionToUserSessionId()).distinct().count();
     }
 
     @Override
     public void removeUserSession(RealmModel realm, UserSessionModel session) {
-        removeUserSession(realm, session.getId());
+        removeUserSession(realm, session.getId(), false);
     }
 
     @Override
@@ -271,80 +234,81 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     protected void removeUserSessions(RealmModel realm, UserModel user, boolean offline) {
         Cache<String, SessionEntity> cache = getCache(offline);
 
-        Map<String, String> sessions = new MapReduceTask(cache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (String id : sessions.keySet()) {
-            removeUserSession(realm, id, offline);
+        Iterator<String> itr = cache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).map(Mappers.sessionId()).iterator();
+        while (itr.hasNext()) {
+            removeUserSession(realm, itr.next(), offline);
         }
     }
 
     @Override
-    public void removeExpiredUserSessions(RealmModel realm) {
-        UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
+    public void removeExpired(RealmModel realm) {
+        removeExpiredUserSessions(realm);
+        removeExpiredClientSessions(realm);
+        removeExpiredOfflineUserSessions(realm);
+        removeExpiredOfflineClientSessions(realm);
+        removeExpiredClientInitialAccess(realm);
+    }
 
+    private void removeExpiredUserSessions(RealmModel realm) {
         int expired = Time.currentTime() - realm.getSsoSessionMaxLifespan();
         int expiredRefresh = Time.currentTime() - realm.getSsoSessionIdleTimeout();
-        int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
-        int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
 
-        Map<String, String> map = new MapReduceTask(sessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).expired(expired, expiredRefresh).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
+        Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).expired(expired, expiredRefresh)).iterator();
+
+        while (itr.hasNext()) {
+            UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
+            tx.remove(sessionCache, entity.getId());
 
-        for (String id : map.keySet()) {
-            removeUserSession(realm, id);
+            if (entity.getClientSessions() != null) {
+                for (String clientSessionId : entity.getClientSessions()) {
+                    tx.remove(sessionCache, clientSessionId);
+                }
+            }
         }
+    }
 
-        map = new MapReduceTask(sessionCache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession(true).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
+    private void removeExpiredClientSessions(RealmModel realm) {
+        int expiredDettachedClientSession = Time.currentTime() - RealmInfoUtil.getDettachedClientSessionLifespan(realm);
 
-        for (String id : map.keySet()) {
-            tx.remove(sessionCache, id);
+        Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredDettachedClientSession).requireNullUserSession()).iterator();
+        while (itr.hasNext()) {
+            tx.remove(sessionCache, itr.next().getKey());
         }
+    }
+
+    private void removeExpiredOfflineUserSessions(RealmModel realm) {
+        UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
+        int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
 
-        // Remove expired offline user sessions
-        Map<String, SessionEntity> map2 = new MapReduceTask(offlineSessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).expired(null, expiredOffline))
-                .reducedWith(new FirstResultReducer())
-                .execute();
+        Iterator<Map.Entry<String, SessionEntity>> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).expired(null, expiredOffline)).iterator();
+        while (itr.hasNext()) {
+            UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
+            tx.remove(offlineSessionCache, entity.getId());
 
-        for (Map.Entry<String, SessionEntity> entry : map2.entrySet()) {
-            String userSessionId = entry.getKey();
-            tx.remove(offlineSessionCache, userSessionId);
-            // Propagate to persister
-            persister.removeUserSession(userSessionId, true);
+            persister.removeUserSession(entity.getId(), true);
 
-            UserSessionEntity entity = (UserSessionEntity) entry.getValue();
             for (String clientSessionId : entity.getClientSessions()) {
                 tx.remove(offlineSessionCache, clientSessionId);
             }
         }
+    }
 
-        // Remove expired offline client sessions
-        map = new MapReduceTask(offlineSessionCache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).expiredRefresh(expiredOffline).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
+    private void removeExpiredOfflineClientSessions(RealmModel realm) {
+        UserSessionPersisterProvider persister = session.getProvider(UserSessionPersisterProvider.class);
+        int expiredOffline = Time.currentTime() - realm.getOfflineSessionIdleTimeout();
 
-        for (String clientSessionId : map.keySet()) {
-            tx.remove(offlineSessionCache, clientSessionId);
-            persister.removeClientSession(clientSessionId, true);
+        Iterator<String> itr = offlineSessionCache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).expiredRefresh(expiredOffline)).map(Mappers.sessionId()).iterator();
+        while (itr.hasNext()) {
+            String sessionId = itr.next();
+            tx.remove(offlineSessionCache, sessionId);
+            persister.removeClientSession(sessionId, true);
         }
+    }
 
-        // Remove expired client initial access
-        map = new MapReduceTask(sessionCache)
-                .mappedWith(ClientInitialAccessMapper.create(realm.getId()).expired(Time.currentTime()).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (String id : map.keySet()) {
-            tx.remove(sessionCache, id);
+    private void removeExpiredClientInitialAccess(RealmModel realm) {
+        Iterator<String> itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId()).expired(Time.currentTime())).map(Mappers.sessionId()).iterator();
+        while (itr.hasNext()) {
+            tx.remove(sessionCache, itr.next());
         }
     }
 
@@ -356,13 +320,9 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     protected void removeUserSessions(RealmModel realm, boolean offline) {
         Cache<String, SessionEntity> cache = getCache(offline);
 
-        Map<String, String> ids = new MapReduceTask(cache)
-                .mappedWith(SessionMapper.create(realm.getId()).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (String id : ids.keySet()) {
-            cache.remove(id);
+        Iterator<String> itr = cache.entrySet().stream().filter(SessionPredicate.create(realm.getId())).map(Mappers.sessionId()).iterator();
+        while (itr.hasNext()) {
+            cache.remove(itr.next());
         }
     }
 
@@ -384,24 +344,18 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
 
     @Override
     public void removeUserLoginFailure(RealmModel realm, String username) {
-        LoginFailureKey key = new LoginFailureKey(realm.getId(), username);
-        tx.remove(loginFailureCache, key);
+        tx.remove(loginFailureCache, new LoginFailureKey(realm.getId(), username));
     }
 
     @Override
     public void removeAllUserLoginFailures(RealmModel realm) {
-        Map<LoginFailureKey, Object> sessions = new MapReduceTask(loginFailureCache)
-                .mappedWith(UserLoginFailureMapper.create(realm.getId()).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (LoginFailureKey id : sessions.keySet()) {
-            tx.remove(loginFailureCache, id);
+        Iterator<LoginFailureKey> itr = loginFailureCache.entrySet().stream().filter(UserLoginFailurePredicate.create(realm.getId())).map(Mappers.loginFailureId()).iterator();
+        while (itr.hasNext()) {
+            LoginFailureKey key = itr.next();
+            tx.remove(loginFailureCache, key);
         }
     }
 
-
-
     @Override
     public void onRealmRemoved(RealmModel realm) {
         removeUserSessions(realm, true);
@@ -418,18 +372,13 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     private void onClientRemoved(RealmModel realm, ClientModel client, boolean offline) {
         Cache<String, SessionEntity> cache = getCache(offline);
 
-        Map<String, ClientSessionEntity> map = new MapReduceTask(cache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).client(client.getId()))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (Map.Entry<String, ClientSessionEntity> entry : map.entrySet()) {
-
-            // detach from userSession
-            ClientSessionAdapter adapter = wrap(realm, entry.getValue(), offline);
+        Iterator<Map.Entry<String, SessionEntity>> itr = cache.entrySet().stream().filter(ClientSessionPredicate.create(realm.getId()).client(client.getId())).iterator();
+        while (itr.hasNext()) {
+            ClientSessionEntity entity = (ClientSessionEntity) itr.next().getValue();
+            ClientSessionAdapter adapter = wrap(realm, entity, offline);
             adapter.setUserSession(null);
 
-            tx.remove(cache, entry.getKey());
+            tx.remove(cache, entity.getId());
         }
     }
 
@@ -491,27 +440,19 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
         }
     }
 
-    protected void removeUserSession(RealmModel realm, String userSessionId) {
-        removeUserSession(realm, userSessionId, false);
-    }
-
     protected void removeUserSession(RealmModel realm, String userSessionId, boolean offline) {
         Cache<String, SessionEntity> cache = getCache(offline);
 
         tx.remove(cache, userSessionId);
 
-        // TODO: Isn't more effective to retrieve from userSessionEntity directly?
-        Map<String, String> map = new MapReduceTask(cache)
-                .mappedWith(ClientSessionMapper.create(realm.getId()).userSession(userSessionId).emitKey())
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        for (String id : map.keySet()) {
-            tx.remove(cache, id);
+        UserSessionEntity sessionEntity = (UserSessionEntity) cache.get(userSessionId);
+        if (sessionEntity.getClientSessions() != null) {
+            for (String clientSessionId : sessionEntity.getClientSessions()) {
+                tx.remove(cache, clientSessionId);
+            }
         }
     }
 
-
     InfinispanKeycloakTransaction getTx() {
         return tx;
     }
@@ -522,7 +463,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     }
 
     List<UserSessionModel> wrapUserSessions(RealmModel realm, Collection<UserSessionEntity> entities, boolean offline) {
-        List<UserSessionModel> models = new LinkedList<UserSessionModel>();
+        List<UserSessionModel> models = new LinkedList<>();
         for (UserSessionEntity e : entities) {
             models.add(wrap(realm, e, offline));
         }
@@ -553,7 +494,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     }
 
     List<ClientSessionModel> wrapClientSessions(RealmModel realm, Collection<ClientSessionEntity> entities, boolean offline) {
-        List<ClientSessionModel> models = new LinkedList<ClientSessionModel>();
+        List<ClientSessionModel> models = new LinkedList<>();
         for (ClientSessionEntity e : entities) {
             models.add(wrap(realm, e, offline));
         }
@@ -600,23 +541,21 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
 
     @Override
     public List<ClientSessionModel> getOfflineClientSessions(RealmModel realm, UserModel user) {
-        Map<String, UserSessionEntity> sessions = new MapReduceTask(offlineSessionCache)
-                .mappedWith(UserSessionMapper.create(realm.getId()).user(user.getId()))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-
-        List<ClientSessionEntity> clientSessions = new LinkedList<>();
-        for (UserSessionEntity userSession : sessions.values()) {
-            Set<String> currClientSessions = userSession.getClientSessions();
+        Iterator<Map.Entry<String, SessionEntity>> itr = offlineSessionCache.entrySet().stream().filter(UserSessionPredicate.create(realm.getId()).user(user.getId())).iterator();
+        List<ClientSessionModel> clientSessions = new LinkedList<>();
+
+        while(itr.hasNext()) {
+            UserSessionEntity entity = (UserSessionEntity) itr.next().getValue();
+            Set<String> currClientSessions = entity.getClientSessions();
             for (String clientSessionId : currClientSessions) {
                 ClientSessionEntity cls = (ClientSessionEntity) offlineSessionCache.get(clientSessionId);
                 if (cls != null) {
-                    clientSessions.add(cls);
+                    clientSessions.add(wrap(realm, cls, true));
                 }
             }
         }
 
-        return wrapClientSessions(realm, clientSessions, true);
+        return clientSessions;
     }
 
     @Override
@@ -626,7 +565,7 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
     }
 
     @Override
-    public int getOfflineSessionsCount(RealmModel realm, ClientModel client) {
+    public long getOfflineSessionsCount(RealmModel realm, ClientModel client) {
         return getUserSessionsCount(realm, client, true);
     }
 
@@ -721,18 +660,19 @@ public class InfinispanUserSessionProvider implements UserSessionProvider {
 
     @Override
     public List<ClientInitialAccessModel> listClientInitialAccess(RealmModel realm) {
-        Map<String, ClientInitialAccessEntity> entities = new MapReduceTask(sessionCache)
-                .mappedWith(ClientInitialAccessMapper.create(realm.getId()))
-                .reducedWith(new FirstResultReducer())
-                .execute();
-        return wrapClientInitialAccess(realm, entities.values());
+        Iterator<Map.Entry<String, SessionEntity>> itr = sessionCache.entrySet().stream().filter(ClientInitialAccessPredicate.create(realm.getId())).iterator();
+        List<ClientInitialAccessModel> list = new LinkedList<>();
+        while (itr.hasNext()) {
+            list.add(wrap(realm, (ClientInitialAccessEntity) itr.next().getValue()));
+        }
+        return list;
     }
 
     class InfinispanKeycloakTransaction implements KeycloakTransaction {
 
         private boolean active;
         private boolean rollback;
-        private Map<Object, CacheTask> tasks = new HashMap<Object, CacheTask>();
+        private Map<Object, CacheTask> tasks = new HashMap<>();
 
         @Override
         public void begin() {
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
index 382d01f..e18aa84 100755
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProviderFactory.java
@@ -47,7 +47,8 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
             Cache<String, SessionEntity> cache = connections.getCache(InfinispanConnectionProvider.SESSION_CACHE_NAME);
             Cache<String, SessionEntity> offlineSessionsCache = connections.getCache(InfinispanConnectionProvider.OFFLINE_SESSION_CACHE_NAME);
             Cache<LoginFailureKey, LoginFailureEntity> loginFailures = connections.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
-            return new InfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures);
+
+            return isStreamMode() ? new InfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures) : new CompatInfinispanUserSessionProvider(session, cache, offlineSessionsCache, loginFailures);
         } else {
             return compatProviderFactory.create(session);
         }
@@ -147,5 +148,9 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
         return false;
     }
 
+    private boolean isStreamMode() {
+        return Version.getVersionShort() >= Version.getVersionShort("8.1.0.Final");
+    }
+
 }
 
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java
index b368fd3..2a9058d 100644
--- a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/initializer/InfinispanUserSessionInitializer.java
@@ -151,13 +151,14 @@ public class InfinispanUserSessionInitializer {
         int processors = Runtime.getRuntime().availableProcessors();
 
         ExecutorService localExecutor = Executors.newCachedThreadPool();
-        DistributedExecutorService distributedExecutorService = new DefaultExecutorService(cache, localExecutor);
+        Transport transport = cache.getCacheManager().getTransport();
+        boolean distributed = transport != null;
+        ExecutorService executorService = distributed ? new DefaultExecutorService(cache, localExecutor) : localExecutor;
 
         int errors = 0;
 
         try {
             while (!state.isFinished()) {
-                Transport transport = cache.getCacheManager().getTransport();
                 int nodesCount = transport==null ? 1 : transport.getMembers().size();
                 int distributedWorkersCount = processors * nodesCount;
 
@@ -173,8 +174,11 @@ public class InfinispanUserSessionInitializer {
                 for (Integer segment : segments) {
                     SessionInitializerWorker worker = new SessionInitializerWorker();
                     worker.setWorkerEnvironment(segment, sessionsPerSegment, sessionLoader);
+                    if (!distributed) {
+                        worker.setEnvironment(cache, null);
+                    }
 
-                    Future<WorkerResult> future = distributedExecutorService.submit(worker);
+                    Future<WorkerResult> future = executorService.submit(worker);
                     futures.add(future);
                 }
 
@@ -210,7 +214,9 @@ public class InfinispanUserSessionInitializer {
                 }
             }
         } finally {
-            distributedExecutorService.shutdown();
+            if (distributed) {
+                executorService.shutdown();
+            }
             localExecutor.shutdown();
         }
     }
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java
new file mode 100644
index 0000000..22518ef
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientInitialAccessPredicate.java
@@ -0,0 +1,59 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.entities.ClientInitialAccessEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ClientInitialAccessPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
+
+    public ClientInitialAccessPredicate(String realm) {
+        this.realm = realm;
+    }
+
+    private String realm;
+
+    private Integer expired;
+
+    public static ClientInitialAccessPredicate create(String realm) {
+        return new ClientInitialAccessPredicate(realm);
+    }
+
+    public ClientInitialAccessPredicate expired(int time) {
+        this.expired = time;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, SessionEntity> entry) {
+        SessionEntity e = entry.getValue();
+
+        if (!realm.equals(e.getRealm())) {
+            return false;
+        }
+
+        if (!(e instanceof ClientInitialAccessEntity)) {
+            return false;
+        }
+
+        ClientInitialAccessEntity entity = (ClientInitialAccessEntity) e;
+
+        if (expired != null) {
+            if (entity.getRemainingCount() <= 0) {
+                return true;
+            } else if (entity.getExpiration() > 0 && (entity.getTimestamp() + entity.getExpiration()) < expired) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java
new file mode 100644
index 0000000..490b8f4
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/ClientSessionPredicate.java
@@ -0,0 +1,97 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class ClientSessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
+
+    private String realm;
+
+    private String client;
+
+    private String userSession;
+
+    private Long expiredRefresh;
+
+    private Boolean requireUserSession = false;
+
+    private Boolean requireNullUserSession = false;
+
+    private ClientSessionPredicate(String realm) {
+        this.realm = realm;
+    }
+
+    public static ClientSessionPredicate create(String realm) {
+        return new ClientSessionPredicate(realm);
+    }
+
+    public ClientSessionPredicate client(String client) {
+        this.client = client;
+        return this;
+    }
+
+    public ClientSessionPredicate userSession(String userSession) {
+        this.userSession = userSession;
+        return this;
+    }
+
+    public ClientSessionPredicate expiredRefresh(long expiredRefresh) {
+        this.expiredRefresh = expiredRefresh;
+        return this;
+    }
+
+    public ClientSessionPredicate requireUserSession() {
+        requireUserSession = true;
+        return this;
+    }
+
+    public ClientSessionPredicate requireNullUserSession() {
+        requireNullUserSession = true;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, SessionEntity> entry) {
+        SessionEntity e = entry.getValue();
+
+        if (!realm.equals(e.getRealm())) {
+            return false;
+        }
+
+        if (!(e instanceof ClientSessionEntity)) {
+            return false;
+        }
+
+        ClientSessionEntity entity = (ClientSessionEntity) e;
+
+        if (client != null && !entity.getClient().equals(client)) {
+            return false;
+        }
+
+        if (userSession != null && !userSession.equals(entity.getUserSession())) {
+            return false;
+        }
+
+        if (requireUserSession && entity.getUserSession() == null) {
+            return false;
+        }
+
+        if (requireNullUserSession && entity.getUserSession() != null) {
+            return false;
+        }
+
+        if (expiredRefresh != null && entity.getTimestamp() > expiredRefresh) {
+            return false;
+        }
+
+        return true;
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java
new file mode 100644
index 0000000..ba7fd02
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Comparators.java
@@ -0,0 +1,24 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.UserSessionTimestamp;
+
+import java.io.Serializable;
+import java.util.Comparator;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Comparators {
+
+    public static Comparator<UserSessionTimestamp> userSessionTimestamp() {
+        return new UserSessionTimestampComparator();
+    }
+
+    private static class UserSessionTimestampComparator implements Comparator<UserSessionTimestamp>, Serializable {
+        @Override
+        public int compare(UserSessionTimestamp u1, UserSessionTimestamp u2) {
+            return u1.getClientSessionTimestamp() - u2.getClientSessionTimestamp();
+        }
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java
new file mode 100644
index 0000000..3164f6d
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/Mappers.java
@@ -0,0 +1,77 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.UserSessionTimestamp;
+import org.keycloak.models.sessions.infinispan.entities.ClientSessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
+import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.Function;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class Mappers {
+
+    public static Function<Map.Entry<String, SessionEntity>, UserSessionTimestamp> clientSessionToUserSessionTimestamp() {
+        return new ClientSessionToUserSessionTimestampMapper();
+    }
+
+    public static Function<Map.Entry<String, Optional<UserSessionTimestamp>>, UserSessionTimestamp> userSessionTimestamp() {
+        return new UserSessionTimestampMapper();
+    }
+
+    public static Function<Map.Entry<String, SessionEntity>, String> sessionId() {
+        return new SessionIdMapper();
+    }
+
+    public static Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey> loginFailureId() {
+        return new LoginFailureIdMapper();
+    }
+
+    public static Function<Map.Entry<String, SessionEntity>, String> clientSessionToUserSessionId() {
+        return new ClientSessionToUserSessionIdMapper();
+    }
+
+    private static class ClientSessionToUserSessionTimestampMapper implements Function<Map.Entry<String, SessionEntity>, UserSessionTimestamp>, Serializable {
+        @Override
+        public UserSessionTimestamp apply(Map.Entry<String, SessionEntity> entry) {
+            SessionEntity e = entry.getValue();
+            ClientSessionEntity entity = (ClientSessionEntity) e;
+            return new UserSessionTimestamp(entity.getUserSession(), entity.getTimestamp());
+        }
+    }
+
+    private static class UserSessionTimestampMapper implements Function<Map.Entry<String, Optional<org.keycloak.models.sessions.infinispan.UserSessionTimestamp>>, org.keycloak.models.sessions.infinispan.UserSessionTimestamp>, Serializable {
+        @Override
+        public org.keycloak.models.sessions.infinispan.UserSessionTimestamp apply(Map.Entry<String, Optional<org.keycloak.models.sessions.infinispan.UserSessionTimestamp>> e) {
+            return e.getValue().get();
+        }
+    }
+
+    private static class SessionIdMapper implements Function<Map.Entry<String, SessionEntity>, String>, Serializable {
+        @Override
+        public String apply(Map.Entry<String, SessionEntity> entry) {
+            return entry.getKey();
+        }
+    }
+
+    private static class LoginFailureIdMapper implements Function<Map.Entry<LoginFailureKey, LoginFailureEntity>, LoginFailureKey>, Serializable {
+        @Override
+        public LoginFailureKey apply(Map.Entry<LoginFailureKey, LoginFailureEntity> entry) {
+            return entry.getKey();
+        }
+    }
+
+    private static class ClientSessionToUserSessionIdMapper implements Function<Map.Entry<String, SessionEntity>, String>, Serializable {
+        @Override
+        public String apply(Map.Entry<String, SessionEntity> entry) {
+            SessionEntity e = entry.getValue();
+            ClientSessionEntity entity = (ClientSessionEntity) e;
+            return entity.getUserSession();
+        }
+    }
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java
new file mode 100755
index 0000000..6dd5540
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/SessionPredicate.java
@@ -0,0 +1,29 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class SessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
+
+    private String realm;
+
+    private SessionPredicate(String realm) {
+        this.realm = realm;
+    }
+
+    public static SessionPredicate create(String realm) {
+        return new SessionPredicate(realm);
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, SessionEntity> entry) {
+        return realm.equals(entry.getValue().getRealm());
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java
new file mode 100755
index 0000000..fb0fb7e
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserLoginFailurePredicate.java
@@ -0,0 +1,31 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.entities.LoginFailureEntity;
+import org.keycloak.models.sessions.infinispan.entities.LoginFailureKey;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserLoginFailurePredicate implements Predicate<Map.Entry<LoginFailureKey, LoginFailureEntity>>, Serializable {
+
+    private String realm;
+
+    private UserLoginFailurePredicate(String realm) {
+        this.realm = realm;
+    }
+
+    public static UserLoginFailurePredicate create(String realm) {
+        return new UserLoginFailurePredicate(realm);
+    }
+
+    @Override
+    public boolean test(Map.Entry<LoginFailureKey, LoginFailureEntity> entry) {
+        LoginFailureEntity e = entry.getValue();
+        return realm.equals(e.getRealm());
+    }
+
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java
new file mode 100644
index 0000000..2add049
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/stream/UserSessionPredicate.java
@@ -0,0 +1,91 @@
+package org.keycloak.models.sessions.infinispan.stream;
+
+import org.keycloak.models.sessions.infinispan.entities.SessionEntity;
+import org.keycloak.models.sessions.infinispan.entities.UserSessionEntity;
+
+import java.io.Serializable;
+import java.util.Map;
+import java.util.function.Predicate;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserSessionPredicate implements Predicate<Map.Entry<String, SessionEntity>>, Serializable {
+
+    private String realm;
+
+    private String user;
+
+    private Integer expired;
+
+    private Integer expiredRefresh;
+
+    private String brokerSessionId;
+    private String brokerUserId;
+
+    private UserSessionPredicate(String realm) {
+        this.realm = realm;
+    }
+
+    public static UserSessionPredicate create(String realm) {
+        return new UserSessionPredicate(realm);
+    }
+
+    public UserSessionPredicate user(String user) {
+        this.user = user;
+        return this;
+    }
+
+    public UserSessionPredicate expired(Integer expired, Integer expiredRefresh) {
+        this.expired = expired;
+        this.expiredRefresh = expiredRefresh;
+        return this;
+    }
+
+    public UserSessionPredicate brokerSessionId(String id) {
+        this.brokerSessionId = id;
+        return this;
+    }
+
+    public UserSessionPredicate brokerUserId(String id) {
+        this.brokerUserId = id;
+        return this;
+    }
+
+    @Override
+    public boolean test(Map.Entry<String, SessionEntity> entry) {
+        SessionEntity e = entry.getValue();
+
+        if (!(e instanceof UserSessionEntity)) {
+            return false;
+        }
+
+        UserSessionEntity entity = (UserSessionEntity) e;
+
+        if (!realm.equals(entity.getRealm())) {
+            return false;
+        }
+
+        if (user != null && !entity.getUser().equals(user)) {
+            return false;
+        }
+
+        if (brokerSessionId != null && !brokerSessionId.equals(entity.getBrokerSessionId())) {
+            return false;
+        }
+
+        if (brokerUserId != null && !brokerUserId.equals(entity.getBrokerUserId())) {
+            return false;
+        }
+
+        if (expired != null && expiredRefresh != null && entity.getStarted() > expired && entity.getLastSessionRefresh() > expiredRefresh) {
+            return false;
+        }
+
+        if (expired == null && expiredRefresh != null && entity.getLastSessionRefresh() > expiredRefresh) {
+            return false;
+        }
+
+        return true;
+    }
+}
diff --git a/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java
new file mode 100644
index 0000000..3284e43
--- /dev/null
+++ b/model/sessions-infinispan/src/main/java/org/keycloak/models/sessions/infinispan/UserSessionTimestamp.java
@@ -0,0 +1,24 @@
+package org.keycloak.models.sessions.infinispan;
+
+import java.io.Serializable;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UserSessionTimestamp implements Serializable {
+    private String userSessionId;
+    private int clientSessionTimestamp;
+
+    public UserSessionTimestamp(String userSessionId, int clientSessionTimestamp) {
+        this.userSessionId = userSessionId;
+        this.clientSessionTimestamp = clientSessionTimestamp;
+    }
+
+    public String getUserSessionId() {
+        return userSessionId;
+    }
+
+    public int getClientSessionTimestamp() {
+        return clientSessionTimestamp;
+    }
+}

pom.xml 8(+4 -4)

diff --git a/pom.xml b/pom.xml
index b2aa2f4..03e1416 100755
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <groupId>org.jboss</groupId>
         <artifactId>jboss-parent</artifactId>
-        <version>16</version>
+        <version>19</version>
     </parent>
 
     <name>Keycloak</name>
@@ -49,8 +49,8 @@
         <dom4j.version>1.6.1</dom4j.version>
         <xml-apis.version>1.4.01</xml-apis.version>
         <slf4j.version>1.7.7</slf4j.version>
-        <wildfly.version>10.0.0.CR4</wildfly.version>
-        <wildfly.core.version>2.0.1.Final</wildfly.core.version>
+        <wildfly.version>10.0.0.CR5</wildfly.version>
+        <wildfly.core.version>2.0.5.Final</wildfly.core.version>
         <wildfly.build-tools.version>1.1.0.Final</wildfly.build-tools.version>
 
         <!-- this is EAP 6.4 alpha, publicly available -->
@@ -66,7 +66,7 @@
         <sun.jaxb.version>2.2.11</sun.jaxb.version>
         <sun.xsom.version>20140925</sun.xsom.version>
         <javax.mail.version>1.4.5</javax.mail.version>
-        <infinispan.version>6.0.2.Final</infinispan.version>
+        <infinispan.version>8.1.0.Final</infinispan.version>
         <liquibase.version>3.4.1</liquibase.version>
         <jetty9.version>9.1.0.v20131115</jetty9.version>
         <osgi.version>4.2.0</osgi.version>
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
index 03b0636..73ebe44 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/ClientResource.java
@@ -383,9 +383,9 @@ public class ClientResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, Integer> getApplicationSessionCount() {
+    public Map<String, Long> getApplicationSessionCount() {
         auth.requireView();
-        Map<String, Integer> map = new HashMap<String, Integer>();
+        Map<String, Long> map = new HashMap<>();
         map.put("count", session.sessions().getActiveUserSessions(client.getRealm(), client));
         return map;
     }
@@ -430,9 +430,9 @@ public class ClientResource {
     @GET
     @NoCache
     @Produces(MediaType.APPLICATION_JSON)
-    public Map<String, Integer> getOfflineSessionCount() {
+    public Map<String, Long> getOfflineSessionCount() {
         auth.requireView();
-        Map<String, Integer> map = new HashMap<String, Integer>();
+        Map<String, Long> map = new HashMap<>();
         map.put("count", session.sessions().getOfflineSessionsCount(client.getRealm(), client));
         return map;
     }
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
index 9d144e4..cb97855 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/RealmAdminResource.java
@@ -369,9 +369,9 @@ public class RealmAdminResource {
         auth.requireView();
         List<Map<String, String>> data = new LinkedList<Map<String, String>>();
         for (ClientModel client : realm.getClients()) {
-            int size = session.sessions().getActiveUserSessions(client.getRealm(), client);
+            long size = session.sessions().getActiveUserSessions(client.getRealm(), client);
             if (size == 0) continue;
-            Map<String, String> map = new HashMap<String, String>();
+            Map<String, String> map = new HashMap<>();
             map.put("id", client.getId());
             map.put("clientId", client.getClientId());
             map.put("active", size + "");
diff --git a/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java b/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java
index 96c8bad..8f6b91c 100755
--- a/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java
+++ b/services/src/main/java/org/keycloak/services/scheduled/ClearExpiredUserSessions.java
@@ -13,7 +13,7 @@ public class ClearExpiredUserSessions implements ScheduledTask {
     public void run(KeycloakSession session) {
         UserSessionProvider sessions = session.sessions();
         for (RealmModel realm : session.realms().getRealms()) {
-            sessions.removeExpiredUserSessions(realm);
+            sessions.removeExpired(realm);
         }
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
index 5d02107..08529ca 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTest.java
@@ -100,6 +100,8 @@ public class AdapterTest {
 
     @Test
     public void testLoginSSOAndLogout() throws Exception {
+        testStrategy.testLoginSSOMax();
+
         testStrategy.testLoginSSOAndLogout();
     }
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
index 1e60096..f93c4eb 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/adapter/AdapterTestStrategy.java
@@ -310,7 +310,7 @@ public class AdapterTestStrategy extends ExternalResource {
 
         session = keycloakRule.startSession();
         realm = session.realms().getRealmByName("demo");
-        session.sessions().removeExpiredUserSessions(realm);
+        session.sessions().removeExpired(realm);
         session.getTransaction().commit();
         session.close();
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
index 4d43897..19beaf6 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/BruteForceTest.java
@@ -286,9 +286,6 @@ public class BruteForceTest {
 
     }
 
-
-
-
     @Test
     public void testBrowserInvalidPassword() throws Exception {
         loginSuccess();
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
index 30d94fa..c12e6fe 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/forms/LoginTest.java
@@ -524,7 +524,7 @@ public class LoginTest {
             keycloakRule.update(new KeycloakRule.KeycloakSetup() {
                 @Override
                 public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                   manager.getSession().sessions().removeExpiredUserSessions(appRealm);
+                   manager.getSession().sessions().removeExpired(appRealm);
                 }
             });
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
index ab93b1c..147ee86 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderOfflineTest.java
@@ -347,7 +347,7 @@ public class UserSessionProviderOfflineTest {
 
         resetSession();
 
-        session.sessions().removeExpiredUserSessions(realm);
+        session.sessions().removeExpired(realm);
 
         resetSession();
 
@@ -372,7 +372,7 @@ public class UserSessionProviderOfflineTest {
         // Expire everything and assert nothing found
         Time.setOffset(3000000);
         try {
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
 
             resetSession();
 
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
index 88e7597..8106458 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/model/UserSessionProviderTest.java
@@ -17,11 +17,7 @@ import org.keycloak.services.managers.UserManager;
 import org.keycloak.testsuite.rule.KeycloakRule;
 import org.keycloak.common.util.Time;
 
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 
 import static org.junit.Assert.*;
 
@@ -276,7 +272,7 @@ public class UserSessionProviderTest {
 
             resetSession();
 
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             for (String e : expired) {
@@ -309,13 +305,13 @@ public class UserSessionProviderTest {
             resetSession();
 
             Time.setOffset(25);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNotNull(session.sessions().getClientSession(clientSessionId));
 
             Time.setOffset(35);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNull(session.sessions().getClientSession(clientSessionId));
@@ -328,13 +324,13 @@ public class UserSessionProviderTest {
             resetSession();
 
             Time.setOffset(35);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNotNull(session.sessions().getClientSession(clientSessionId));
 
             Time.setOffset(45);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNull(session.sessions().getClientSession(clientSessionId));
@@ -347,13 +343,13 @@ public class UserSessionProviderTest {
             resetSession();
 
             Time.setOffset(45);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNotNull(session.sessions().getClientSession(clientSessionId));
 
             Time.setOffset(55);
-            session.sessions().removeExpiredUserSessions(realm);
+            session.sessions().removeExpired(realm);
             resetSession();
 
             assertNull(session.sessions().getClientSession(clientSessionId));
@@ -463,6 +459,18 @@ public class UserSessionProviderTest {
 
         failure1 = session.sessions().getUserLoginFailure(realm, "user1");
         assertEquals(0, failure1.getNumFailures());
+
+        session.sessions().removeUserLoginFailure(realm, "user1");
+
+        resetSession();
+
+        assertNull(session.sessions().getUserLoginFailure(realm, "user1"));
+
+        session.sessions().removeAllUserLoginFailures(realm);
+
+        resetSession();
+
+        assertNull(session.sessions().getUserLoginFailure(realm, "user2"));
     }
 
     @Test
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
index caa61ed..1af7515 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/oauth/OfflineTokenTest.java
@@ -263,7 +263,7 @@ public class OfflineTokenTest {
 
             @Override
             public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
-                manager.getSession().sessions().removeExpiredUserSessions(appRealm);
+                manager.getSession().sessions().removeExpired(appRealm);
             }
 
         });