diff --git a/build.gradle b/build.gradle
index cb006b7..2c9e254 100644
--- a/build.gradle
+++ b/build.gradle
@@ -18,7 +18,7 @@ plugins {
group = 'org.springframework.session'
-ext.springBootVersion = '1.3.2.RELEASE'
+ext.springBootVersion = '1.4.1.RELEASE'
ext.IDE_GRADLE = "$rootDir/gradle/ide.gradle"
ext.JAVA_GRADLE = "$rootDir/gradle/java.gradle"
ext.SPRING3_GRADLE = "$rootDir/gradle/spring3.gradle"
diff --git a/docs/build.gradle b/docs/build.gradle
index 14c5141..ddf79ad 100644
--- a/docs/build.gradle
+++ b/docs/build.gradle
@@ -38,8 +38,8 @@ dependencies {
"org.springframework.security:spring-security-config:${springSecurityVersion}",
"org.springframework.security:spring-security-web:${springSecurityVersion}",
"org.springframework.security:spring-security-test:${springSecurityVersion}",
- 'junit:junit:4.11',
- 'org.mockito:mockito-core:1.9.5',
+ "junit:junit:$junitVersion",
+ "org.mockito:mockito-core:$mockitoVersion",
"org.springframework:spring-test:$springVersion",
"org.assertj:assertj-core:$assertjVersion",
"com.hazelcast:hazelcast:$hazelcastVersion",
diff --git a/docs/src/docs/asciidoc/guides/httpsession-gemfire-boot.adoc b/docs/src/docs/asciidoc/guides/httpsession-gemfire-boot.adoc
index 87fbdc5..bee1d6f 100644
--- a/docs/src/docs/asciidoc/guides/httpsession-gemfire-boot.adoc
+++ b/docs/src/docs/asciidoc/guides/httpsession-gemfire-boot.adoc
@@ -89,16 +89,17 @@ We start with the _Spring Boot_ application for configuring and bootstrapping a
include::{samples-dir}httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java[tags=class]
----
-<1> The `@EnableGemFireHttpSession` annotation is used on the GemFire Server mainly to define the corresponding
+<1> The `@EnableGemFireHttpSession` annotation is used on the GemFire Server to mainly define the corresponding
Region (e.g. `ClusteredSpringSessions`, the default) in which Session state information will be stored
and managed by GemFire. As well, we have specified an arbitrary expiration attribute (i.e. `maxInactiveIntervalInSeconds`)
for when the Session will timeout, which is triggered by a GemFire Region entry expiration event that also invalidates
the Session object in the Region.
-<2> Next, we define a few `Properties` allowing us to configure certain aspects of the GemFire Server using
+<2> Next, we define a few `Properties` that allow us to configure certain aspects of the GemFire Server using
http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System properties].
-<3> Then, we create an instance of the GemFire Cache using our defined `Properties`.
-<4> Finally, we setup a Cache Server instance running in the GemFire Server to listen for connections from cache clients.
-The Cache Server `Socket` will be used to connect our GemFire client cache, _Spring Boot_ web application to the server.
+<3> Then, we create an instance of the GemFire `Cache` using our defined `Properties`.
+<4> Finally, we configure and start a `CacheServer` running in the GemFire Server to listen for connections
+from cache clients. The `CacheServer's` `Socket` will be used to connect our GemFire cache client,
+_Spring Boot_ web application to the server.
The sample also makes use of a `PropertySourcesPlaceholderConfigurer` bean in order to externalize the sample application
configuration to affect GemFire and application configuration/behavior from the command-line (e.g. such as GemFire's
@@ -106,9 +107,9 @@ configuration to affect GemFire and application configuration/behavior from the
=== Spring Boot-based GemFire cache client Web application
-Now, we create the _Spring Boot_ web application (a GemFire cache client), exposing our Web service
-using Spring MVC along with _Spring Session_ backed by GemFire, connected to our _Spring Boot_-based GemFire Server,
-in order to manage Session state in a cluster/replicated-enabled fashion.
+Now, we create our _Spring Boot_ Web application exposing our Web service with Spring MVC, running as a
+GemFire cache client connected to our _Spring Boot_-based GemFire Server, using Spring Session backed by GemFire
+to manage Session state in a clustered, replicated fashion.
[source,java]
----
@@ -116,28 +117,29 @@ include::{samples-dir}httpsession-gemfire-boot/src/main/java/sample/client/Appli
----
<1> Here, again, we use the `@EnableGemFireHttpSession` annotation to not only configure the GemFire cache client,
-but also to override the (HTTP) Web application container's `HttpSession` and replace it with a Session implementation
-backed by _Spring Session_ in conjunction with GemFire. Also notice, we did not define any Session expiration timeout
-with the `maxInactiveIntervalInSeconds` attribute this time. That is because the Session expiration is managed
-by GemFire, which will appropriately notify the cache client when the Session times out. Again, we have just resorted
-to using the default Region, `ClusteredSpringSessions`. Of course, we can change the Region name, but we must do so
-on both the client and the server. That is a GemFire requirement, not a _Spring Session Data GemFire_ requirement.
-<2> Similary to the server configuration, we set a few basic GemFire System `Properties` on the client.
-<3> Although, this time, an instance of `ClientCache` is created with the `ClientCacheFactoryBean` from _Spring Data GemFire_.
-<4> However, in order to connect to the GemFire Server we must define a GemFire `Pool` bean containing pre-populated
-connections to the server. Whenever a client Region entry operation corresponding to a Session update occurs,
+but to also override the (HTTP) Web application container's `HttpSession` and replace it with a Session implementation
+backed by _Spring Session_ and GemFire. Also notice, we did not define any Session expiration timeout with the
+`maxInactiveIntervalInSeconds` attribute this time. That is because the Session expiration is managed by GemFire,
+on the server, which will appropriately notify the cache client when the Session times out. Again, we have just
+resorted to using the default named Region, `ClusteredSpringSessions`. Of course, we can change the Region name,
+but we must do so on both the client and the server. That is a GemFire requirement, not a
+_Spring Session Data GemFire_ requirement.
+<2> Similarly to the server configuration, we set a few basic GemFire System `Properties` on the client.
+<3> Although, this time, an instance of `ClientCache` is created with the `ClientCacheFactoryBean`
+from _Spring Data GemFire_.
+<4> However, in order to connect to the GemFire Server we must define a GemFire `Pool` bean containing a
+pool of connections to the server. Whenever a client Region entry operation corresponding to a Session update occurs,
the client-side Region will use an existing, pooled connection to route the operation to the server.
<5> The following _Spring_ `BeanPostProcessor` (along with some utility methods) are only needed for testing purposes
-and is not required by any production code. Specifically, the `BeanPostProcessor` along with the code referenced in *6*
+and are not required by any production code. Specifically, the `BeanPostProcessor` along with the code referenced in *6*
is useful in integration test cases where the client and server processes are forked by the test framework. It is pretty
easy to figure out that a race condition is imminent without proper coordination between the client and the server,
therefore, the BPP and `ClientMembershipListener` help sync the interaction between the client and the server
on startup during automated testing.
-<6> See <5> above.
-<7> Navigates the Web application to the home page (`index.html`), which uses **Thymeleaf** templates for server-side
+<6> Navigates the Web application to the home page (`index.html`), which uses **Thymeleaf** templates for server-side
pages.
-<8> Heartbeat web service endpoint (useful for manual testing purposes).
-<9> Web service endpoint for adding a Session attributes defined by the user using the Web application UI. In addition,
+<7> Heartbeat Web service endpoint (useful for manual testing purposes).
+<8> Web service endpoint allowing the user to add a Session attribute using the Web application UI. In addition,
the webapp stores an additional Session attribute (`requestCount`) to keep track of how many HTTP requests the user
has sent during the current "session".
@@ -159,11 +161,13 @@ and GemFire out-of-the-box using the following attributes:
* `clientRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
with a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
(default is `PROXY`). This attribute is only used when configuring client Region.
+* `poolName` - name of the dedicated GemFire Pool used to connect a client to the cluster of servers. The attribute
+is only used when the application is a GemFire cache client. Defaults to `gemfirePool`.
* `serverRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
using a GemFire http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
(default is `PARTITION`). This attribute is only used when configuring server Regions, or when a p2p topology is employed.
-NOTE: It is important to note that the GemFire client Region name must match a server Region by the same name if
+NOTE: It is important to remember that the GemFire client Region name must match a server Region by the same name if
the client Region is a `PROXY` or `CACHING_PROXY`. Client and server Region names are not required to match if
the client Region used to store Spring Sessions is `LOCAL`. However, keep in mind that your session state will not
be propagated to the server and you lose all the benefits of using GemFire to store and manage distributed, replicated
diff --git a/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver-xml.adoc b/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver-xml.adoc
index 08f68ba..6e3c29d 100644
--- a/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver-xml.adoc
+++ b/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver-xml.adoc
@@ -83,23 +83,23 @@ Add the following Spring Configuration:
include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml[tags=beans]
----
-<1> First, a `Properties` bean is created to reference GemFire configuration common to both the client and server,
-stored in the `META-INF/spring/application.properties` file.
-<2> The `application.properties` are used along with the `PropertySourcesPlaceholderConfigurer` bean to replace
-placeholders in the Spring XML configuration meta-data with property values.
-<3> Spring annotation configuration support is enabled with `` element so that any
+<1> Spring annotation configuration support is enabled with `` element so that any
Spring beans declared in the XML config that are annotated with either Spring or Standard Java annotations supported
by Spring will be configured appropriately.
-<4> `GemFireHttpSessionConfiguration` is registered to enable Spring Session functionality.
-<5> Then, a Spring `BeanPostProcessor` is registered to determine whether a GemFire Server at the designated host/port
-is running, blocking client startup until the server is available.
-<6> Next, we include a `Properties` bean to configure certain aspects of the GemFire client cache using
-http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System properties].
-In this case, we are just setting GemFire's `log-level` from a sample application-specific System property, defaulting
+<2> The `META-INF/spring/application.properties` file are used along with the `PropertySourcesPlaceholderConfigurer`
+bean to replace placeholders in the Spring XML configuration meta-data with the approrpriate property values.
+<3> Then the `GemFireCacheSeverReadyBeanPostProcessor`is registered to determine whether a GemFire Server
+at the designated host/port is running and listening for client connections, blocking client startup until
+the server is available and ready.
+<4> Next, we include a `Properties` bean to configure certain aspects of the GemFire client cache using
+http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System Properties].
+In this case, we are just setting GemFire's `log-level` from a application-specific System property, defaulting
to `warning` if unspecified.
-<7> Finally, we create the GemFire client cache and configure a Pool of client connections to talk to the GemFire Server
-in our Client/Server topology. In our configuration, we use sensible settings for timeouts, number of connections
-and so on. Also, our `Pool` has been configured to connect directly to a server.
+<5> Then we create a instance of a GemFire `ClientCache` initialized with our `gemfireProperties`.
+<6> We configure a Pool of client connections to talk to the GemFire Server in our Client/Server topology.
+In our configuration, we use sensible settings for timeouts, number of connections and so on. Also, our `Pool`
+has been configured to connect directly to a server.
+<7> Finally, the `GemFireHttpSessionConfiguration` is registered to enable Spring Session functionality.
TIP: In typical GemFire deployments, where the cluster includes potentially hundreds of GemFire data nodes (servers),
it is more common for clients to connect to one or more GemFire Locators running in the cluster. A Locator passes meta-data
@@ -110,8 +110,8 @@ NOTE: For more information on configuring _Spring Data GemFire_, refer to the ht
=== Server Configuration
-Now, we have only covered one side of the equation. We also need a GemFire Server for our client to talk to and pass
-session state information up to the server to manage.
+We have only covered one side of the equation. We also need a GemFire Server for our client to talk to and send
+session state information to the server to manage.
In this sample, we will use the following GemFire Server Java Configuration:
@@ -124,15 +124,16 @@ include::{samples-dir}httpsession-gemfire-clientserver-xml/src/main/resources/ME
Spring beans declared in the XML config that are annotated with either Spring or Standard Java annotations supported
by Spring will be configured appropriately.
<2> A `PropertySourcesPlaceholderConfigurer` is registered to replace placeholders in our Spring XML configuration
-meta-data with property values from `META-INF/spring/application.properties`.
-<3> We enable the same Spring Session functionality that we used on the client by registering an instance of `GemFireHttpSessionConfiguration`,
-except that we set the session expiration timeout to **30 seconds**. We will explain later what this means.
-<4> Next, we configure the GemFire Server using GemFire System properties very much like our P2P samples.
+meta-data with property values in the `META-INF/spring/application.properties` file.
+<3> Next, we configure the GemFire Server using GemFire System Properties very much like our P2P samples.
With the `mcast-port` set to 0 and no `locators` property specified, our server will be standalone. We also allow a
JMX client (e.g. _Gfsh_) to connect to our server with the use of the GemFire-specific JMX System properties.
-<5> Then, we create an instance of the GemFire peer cache using our GemFire System properties.
-<6> And finally, we also setup a GemFire `CacheServer` instance running on *localhost*, listening on port **11235**,
-to accept our client connection.
+<4> Then we create an instance of a GemFire peer `Cache` initialized with our GemFire System Properties.
+<5> We also setup a GemFire `CacheServer` instance running on *localhost*, listening to port **11235**,
+ready to accept our client connection.
+<6> Finally, we enable the same Spring Session functionality we used on the client by registering an instance of
+`GemFireHttpSessionConfiguration`, except that we set the session expiration timeout to **30 seconds**.
+We will explain later what this means.
The GemFire Server configuration gets bootstrapped with the following:
diff --git a/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver.adoc b/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver.adoc
index 3aa110d..8605524 100644
--- a/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver.adoc
+++ b/docs/src/docs/asciidoc/guides/httpsession-gemfire-clientserver.adoc
@@ -84,33 +84,26 @@ include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/Clie
----
<1> The `@EnableGemFireHttpSession` annotation creates a Spring bean named `springSessionRepositoryFilter` that
-implements `Filter`. The filter is what replaces the `HttpSession` with an implementation backed by Spring Session.
-In this instance, Spring Session is backed by GemFire.
+implements `Filter`. The filter is what replaces the `HttpSession` with an implementation backed by Spring Session
+and GemFire.
<2> Next, we register a `Properties` bean that allows us to configure certain aspects of the GemFire client cache
using http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html[GemFire's System properties].
-<3> Then, we configure a `Pool` of client connections to talk to the GemFire Server in our Client/Server topology. In our
+<3> We use the `Properties` to configure an instance of a GemFire `ClientCache`.
+<4> Then, we configure a `Pool` of client connections to talk to the GemFire Server in our Client/Server topology. In our
configuration, we have used sensible settings for timeouts, number of connections and so on. Also, the `Pool` has been
configured to connect directly to a server. Learn more about various `Pool` configuration settings from the
http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/PoolFactory.html[PoolFactory API].
-<4> After configuring a `Pool`, we create an instance of the GemFire client cache using the GemFire `Properties`
-and `Pool` to communicate with the server and perform cache data access operations.
-<5> Finally, we include a Spring `BeanPostProcessor` to block the client until our GemFire Server is up and running,
+<56> Finally, we include a Spring `BeanPostProcessor` to block the client until our GemFire Server is up and running,
listening for and accepting client connections.
The `gemfireCacheServerReadyBeanPostProcessor` is necessary in order to coordinate the client and server in
an automated fashion during testing, but unnecessary in situations where the GemFire cluster is already presently
-running, such as in production. This `BeanPostProcessor` implements 2 approaches to ensure our server has adequate
-time to startup.
+running, such as in production.
-The first approach uses a timed wait, checking at periodic intervals to determine whether a client `Socket` connection
-can be made to the server's `CacheServer` endpoint.
-
-The second approach uses a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/management/membership/ClientMembershipListener.html[ClientMembershipListener]
+The `BeanPostProcessor` uses a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/management/membership/ClientMembershipListener.html[ClientMembershipListener]
that will be notified when the client has successfully connected to the server. Once a connection has been established,
the listener releases the latch that the `BeanPostProcessor` will wait on (up to the specified timeout) in the
-`postProcessAfterInitialization` callback to block the client. Either one of these approaches are sufficient
-by themselves, but both are demonstrated here to illustrate how this might work and to give you ideas, or other options
-in practice.
+`postProcessAfterInitialization` callback to block the client.
TIP: In typical GemFire deployments, where the cluster includes potentially hundreds of GemFire data nodes (servers),
it is more common for clients to connect to one or more GemFire Locators running in the cluster. A Locator passes meta-data
@@ -122,11 +115,16 @@ NOTE: For more information on configuring _Spring Data GemFire_, refer to the ht
The `@EnableGemFireHttpSession` annotation enables a developer to configure certain aspects of both Spring Session
and GemFire out-of-the-box using the following attributes:
-* `maxInactiveIntervalInSeconds` - controls HttpSession idle-timeout expiration (defaults to **30 minutes**).
-* `regionName` - specifies the name of the GemFire Region used to store `HttpSession` state (defaults is "_ClusteredSpringSessions_").
-* `clientRegionShort` - specifies GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policies]
+* `maxInactiveIntervalInSeconds` - controls _HttpSession_ idle-timeout expiration (defaults to **30 minutes**).
+* `regionName` - specifies the name of the GemFire Region used to store `HttpSession` state (defaults is "*ClusteredSpringSessions*").
+* `clientRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
with a GemFire http://gemfire.docs.pivotal.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/client/ClientRegionShortcut.html[ClientRegionShortcut]
-(default is `PROXY`).
+(default is `PROXY`). This attribute is only used when configuring client Region.
+* `poolName` - name of the dedicated GemFire Pool used to connect a client to the cluster of servers. The attribute
+is only used when the application is a GemFire cache client. Defaults to `gemfirePool`.
+* `serverRegionShort` - specifies GemFire's http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/management_all_region_types/chapter_overview.html[data management policy]
+using a GemFire http://data-docs-samples.cfapps.io/docs-gemfire/latest/javadocs/japi/com/gemstone/gemfire/cache/RegionShortcut.html[RegionShortcut]
+(default is `PARTITION`). This attribute is only used when configuring server Regions, or when a p2p topology is employed.
NOTE: It is important to note that the GemFire client Region name must match a server Region by the same name if
the client Region is a `PROXY` or `CACHING_PROXY`. Names are not required to match if the client Region used to
@@ -134,13 +132,13 @@ store Spring Sessions is `LOCAL`, however, keep in mind that your session state
and you lose all benefits of using GemFire to store and manage distributed, replicated session state information
in a cluster.
-NOTE: `serverRegionShort` is ignored in a client/server cache configuration and only applies when a peer-to-peer (P2P) topology,
-and more specifically, a GemFire peer cache is used.
+NOTE: `serverRegionShort` is ignored in a client/server cache configuration and only applies when
+a peer-to-peer (P2P) topology, and more specifically, a GemFire peer cache is used.
=== Server Configuration
-Now, we have only covered one side of the equation. We also need a GemFire Server for our client to talk to and pass
-session state up to the server to manage.
+We have only covered one side of the equation. We also need a GemFire Server for our client to talk to and send
+session state to the server to manage.
In this sample, we will use the following GemFire Server Java Configuration:
@@ -149,15 +147,15 @@ In this sample, we will use the following GemFire Server Java Configuration:
include::{samples-dir}httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java[tags=class]
----
-<1> On the server, we also configure Spring Session using the `@EnableGemFireHttpSession` annotation. For one, this
-ensures that the Region names on both the client and server match (in this sample, we use the default "_ClusteredSpringSessions_").
+<1> On the server, we also configure Spring Session using the `@EnableGemFireHttpSession` annotation. This ensures
+the Region names on both the client and server match (in this sample, we use the default "_ClusteredSpringSessions_").
We have also set the session timeout to **30 seconds**. Later, we will see how this timeout is used.
-<2> Next, we configure the GemFire Server using GemFire System properties very much like our P2P samples.
+<2> Next, we configure the GemFire Server using GemFire System Properties very much like our P2P samples.
With the `mcast-port` set to 0 and no `locators` property specified, our server will be standalone. We also allow a
JMX client (e.g. _Gfsh_) to connect to our server with the use of the GemFire-specific JMX System properties.
-<3> Then, we create an instance of the GemFire peer cache using our GemFire System properties.
-<4> We also setup a GemFire `CacheServer` instance running on **localhost**, listening on port **12480**,
-to accept our client connection.
+<3> Then, we create an instance of a GemFire peer `Cache` initialized with our GemFire System Properties.
+<4> We also setup a GemFire `CacheServer` instance running on **localhost**, listening to port **12480**,
+ready to accept our client connection.
<5> Finally, we declare a `main` method as an entry point for launching and running our GemFire Server
from the command-line.
diff --git a/gradle.properties b/gradle.properties
index 371b93f..2870b71 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -5,6 +5,8 @@ jspApiVersion=2.0
servletApiVersion=3.0.1
jstlelVersion=1.2.5
version=1.3.0.BUILD-SNAPSHOT
+# TODO: upgrade to SD Redis 1.7.4.RELEASE - spring3Test suite Redis tests fail due to upgrade...
+# Caused by: java.lang.NoSuchMethodError: org.springframework.core.serializer.support.DeserializingConverter.(Ljava/lang/ClassLoader;)V
springDataRedisVersion=1.7.1.RELEASE
html5ShivVersion=3.7.3
commonsLoggingVersion=1.2
@@ -15,13 +17,13 @@ hazelcastVersion=3.6.5
springDataGeodeVersion=1.0.0.APACHE-GEODE-INCUBATING-M2
seleniumVersion=2.52.0
springSecurityVersion=4.2.0.RELEASE
-springVersion=4.2.5.RELEASE
+springVersion=4.3.3.RELEASE
httpClientVersion=4.5.1
jedisVersion=2.8.1
h2Version=1.4.192
-springDataMongoVersion=1.9.1.RELEASE
+springDataMongoVersion=1.9.4.RELEASE
springShellVersion=1.1.0.RELEASE
-springDataGemFireVersion=1.8.1.RELEASE
+springDataGemFireVersion=1.8.4.RELEASE
assertjVersion=2.5.0
spockVersion=1.0-groovy-2.4
webjarsTaglibVersion=0.3
diff --git a/samples/httpsession-gemfire-boot/src/main/java/sample/client/Application.java b/samples/httpsession-gemfire-boot/src/main/java/sample/client/Application.java
index e4f80c0..5405b20 100644
--- a/samples/httpsession-gemfire-boot/src/main/java/sample/client/Application.java
+++ b/samples/httpsession-gemfire-boot/src/main/java/sample/client/Application.java
@@ -16,8 +16,6 @@
package sample.client;
-import java.io.IOException;
-import java.net.Socket;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
@@ -26,7 +24,6 @@ import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.http.HttpSession;
@@ -34,8 +31,6 @@ import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.management.membership.ClientMembership;
import com.gemstone.gemfire.management.membership.ClientMembershipEvent;
import com.gemstone.gemfire.management.membership.ClientMembershipListenerAdapter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
@@ -47,8 +42,8 @@ import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
+import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
-import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
@@ -59,16 +54,14 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
- * A Spring Boot-based GemFire cache client web application that reveals the current state
- * of the HTTP Session.
+ * A Spring Boot, GemFire cache client, web application that reveals the current state of the HTTP Session.
*
* @author John Blum
* @see javax.servlet.http.HttpSession
* @see org.springframework.boot.SpringApplication
* @see org.springframework.boot.autoconfigure.SpringBootApplication
* @see org.springframework.context.annotation.Bean
- * @see org.springframework.session.data.gemfire.config.annotation.web.http.
- * EnableGemFireHttpSession
+ * @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.stereotype.Controller
* @see com.gemstone.gemfire.cache.client.ClientCache
* @since 1.2.1
@@ -79,63 +72,42 @@ import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Application {
- static final int MAX_CONNECTIONS = 50;
-
static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
- static final long DEFAULT_WAIT_INTERVAL = 500L;
static final CountDownLatch latch = new CountDownLatch(1);
- static final String DEFAULT_GEMFIRE_LOG_LEVEL = "config";
+ static final String DEFAULT_GEMFIRE_LOG_LEVEL = "warning";
static final String INDEX_TEMPLATE_VIEW_NAME = "index";
static final String PING_RESPONSE = "PONG";
static final String REQUEST_COUNT_ATTRIBUTE_NAME = "requestCount";
- static { // <6>
- ClientMembership
- .registerClientMembershipListener(new ClientMembershipListenerAdapter() {
- @Override
- public void memberJoined(ClientMembershipEvent event) {
- if (!event.isClient()) {
- latch.countDown();
- }
- }
- });
- }
-
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
- protected final Logger logger = LoggerFactory.getLogger(getClass());
-
@Bean
static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
- String applicationName() {
- return "samples:httpsession-gemfire-boot-"
- .concat(Application.class.getSimpleName());
- }
-
- String gemfireLogLevel() {
- return System.getProperty("gemfire.log-level", DEFAULT_GEMFIRE_LOG_LEVEL);
- }
-
- ConnectionEndpoint newConnectionEndpoint(String host, int port) {
- return new ConnectionEndpoint(host, port);
- }
-
Properties gemfireProperties() { // <2>
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", applicationName());
- gemfireProperties.setProperty("log-level", gemfireLogLevel());
+ gemfireProperties.setProperty("log-level", logLevel());
return gemfireProperties;
}
+ String applicationName() {
+ return "samples:httpsession-gemfire-boot:"
+ .concat(getClass().getSimpleName());
+ }
+
+ String logLevel() {
+ return System.getProperty("gemfire.log-level", DEFAULT_GEMFIRE_LOG_LEVEL);
+ }
+
@Bean
ClientCacheFactoryBean gemfireCache() { // <3>
ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();
@@ -153,18 +125,23 @@ public class Application {
PoolFactoryBean gemfirePool = new PoolFactoryBean();
- gemfirePool.setMaxConnections(MAX_CONNECTIONS);
- gemfirePool.setPingInterval(TimeUnit.SECONDS.toMillis(15));
+ gemfirePool.setKeepAlive(false);
+ gemfirePool.setPingInterval(TimeUnit.SECONDS.toMillis(5));
+ gemfirePool.setReadTimeout(Long.valueOf(TimeUnit.SECONDS.toMillis(2)).intValue());
gemfirePool.setRetryAttempts(1);
gemfirePool.setSubscriptionEnabled(true);
- gemfirePool.setServerEndpoints(
- Collections.singleton(newConnectionEndpoint(host, port)));
+ gemfirePool.setThreadLocalConnections(false);
+ gemfirePool.setServers(Collections.singleton(newConnectionEndpoint(host, port)));
return gemfirePool;
}
+ ConnectionEndpoint newConnectionEndpoint(String host, int port) {
+ return new ConnectionEndpoint(host, port);
+ }
+
@Bean
- BeanPostProcessor gemfireCacheServerAvailabilityBeanPostProcessor(
+ BeanPostProcessor gemfireCacheServerReadyBeanPostProcessor(
@Value("${gemfire.cache.server.host:localhost}") final String host,
@Value("${gemfire.cache.server.port:12480}") final int port) { // <5>
@@ -172,12 +149,15 @@ public class Application {
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
- if (!waitForCacheServerToStart(host, port)) {
- Application.this.logger.warn(
- "No GemFire Cache Server found on [host: {}, port: {}]",
- host, port);
- }
+
+ if ("gemfirePool".equals(beanName)) {
+ ClientMembership.registerClientMembershipListener(
+ new ClientMembershipListenerAdapter() {
+ @Override
+ public void memberJoined(ClientMembershipEvent event) {
+ latch.countDown();
+ }
+ });
}
return bean;
@@ -185,13 +165,12 @@ public class Application {
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
+
+ if (bean instanceof Pool && "gemfirePool".equals(beanName)) {
try {
- Assert.state(
- latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS),
- String.format(
- "GemFire Cache Server failed to start on [host: %1$s, port: %2$d]",
- host, port));
+ Assert.state(latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS),
+ String.format("GemFire Cache Server failed to start on host [%1$s] and port [%2$d]",
+ host, port));
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
@@ -204,23 +183,23 @@ public class Application {
}
@RequestMapping("/")
- public String index() { // <7>
+ public String index() { // <6>
return INDEX_TEMPLATE_VIEW_NAME;
}
@RequestMapping(method = RequestMethod.GET, path = "/ping")
@ResponseBody
- public String ping() { // <8>
+ public String ping() { // <7>
return PING_RESPONSE;
}
@RequestMapping(method = RequestMethod.POST, path = "/session")
public String session(HttpSession session, ModelMap modelMap,
@RequestParam(name = "attributeName", required = false) String name,
- @RequestParam(name = "attributeValue", required = false) String value) { // <9>
+ @RequestParam(name = "attributeValue", required = false) String value) { // <8>
modelMap.addAttribute("sessionAttributes",
- attributes(setAttribute(updateRequestCount(session), name, value)));
+ attributes(setAttribute(updateRequestCount(session), name, value)));
return INDEX_TEMPLATE_VIEW_NAME;
}
@@ -230,27 +209,24 @@ public class Application {
@SuppressWarnings("all")
HttpSession updateRequestCount(HttpSession session) {
synchronized (session) {
- Integer currentRequestCount = (Integer) session
- .getAttribute(REQUEST_COUNT_ATTRIBUTE_NAME);
- session.setAttribute(REQUEST_COUNT_ATTRIBUTE_NAME,
- nullSafeIncrement(currentRequestCount));
+ Integer currentRequestCount = (Integer) session.getAttribute(REQUEST_COUNT_ATTRIBUTE_NAME);
+ session.setAttribute(REQUEST_COUNT_ATTRIBUTE_NAME, nullSafeIncrement(currentRequestCount));
return session;
}
}
/* (non-Javadoc) */
Integer nullSafeIncrement(Integer value) {
- return (nullSafeInt(value) + 1);
+ return (nullSafeIntValue(value) + 1);
}
/* (non-Javadoc) */
- int nullSafeInt(Number value) {
+ int nullSafeIntValue(Number value) {
return (value != null ? value.intValue() : 0);
}
/* (non-Javadoc) */
- HttpSession setAttribute(HttpSession session, String attributeName,
- String attributeValue) {
+ HttpSession setAttribute(HttpSession session, String attributeName, String attributeValue) {
if (isSet(attributeName, attributeValue)) {
session.setAttribute(attributeName, attributeValue);
}
@@ -269,97 +245,25 @@ public class Application {
return set;
}
+ /* (non-Javadoc) */
Map attributes(HttpSession session) {
Map sessionAttributes = new HashMap();
for (String attributeName : toIterable(session.getAttributeNames())) {
sessionAttributes.put(attributeName,
- String.valueOf(session.getAttribute(attributeName)));
+ String.valueOf(session.getAttribute(attributeName)));
}
return sessionAttributes;
}
+ /* (non-Javadoc) */
Iterable toIterable(final Enumeration enumeration) {
return new Iterable() {
public Iterator iterator() {
return (enumeration == null ? Collections.emptyIterator()
- : new Iterator() {
- public boolean hasNext() {
- return enumeration.hasMoreElements();
- }
-
- public T next() {
- return enumeration.nextElement();
- }
-
- public void remove() {
- throw new UnsupportedOperationException(
- "Auto-generated method stub");
- }
- });
+ : CollectionUtils.toIterator(enumeration));
}
};
}
-
- /* (non-Javadoc) */
- boolean waitForCacheServerToStart(String host, int port) {
- return waitForCacheServerToStart(host, port, DEFAULT_WAIT_DURATION);
- }
-
- /* (non-Javadoc) */
- boolean waitForCacheServerToStart(final String host, final int port, long duration) {
- return waitOnCondition(new Condition() {
- AtomicBoolean connected = new AtomicBoolean(false);
-
- public boolean evaluate() {
- Socket socket = null;
-
- try {
- // NOTE: this code is not intended to be an atomic, compound action (a
- // possible race condition);
- // opening another connection (at the expense of using system
- // resources) after connectivity
- // has already been established is not detrimental in this use case
- if (!this.connected.get()) {
- socket = new Socket(host, port);
- this.connected.set(true);
- }
- }
- catch (IOException ignore) {
- }
- finally {
- GemFireUtils.close(socket);
- }
-
- return this.connected.get();
- }
- }, duration);
- }
-
- boolean waitOnCondition(Condition condition) {
- return waitOnCondition(condition, DEFAULT_WAIT_DURATION);
- }
-
- @SuppressWarnings("all")
- boolean waitOnCondition(Condition condition, long duration) {
- final long timeout = (System.currentTimeMillis() + duration);
-
- try {
- while (!condition.evaluate() && System.currentTimeMillis() < timeout) {
- synchronized (condition) {
- TimeUnit.MILLISECONDS.timedWait(condition, DEFAULT_WAIT_INTERVAL);
- }
- }
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
-
- return condition.evaluate();
- }
-
- interface Condition {
- boolean evaluate();
- }
}
diff --git a/samples/httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java b/samples/httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java
index fb9e365..53cda3b 100644
--- a/samples/httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java
+++ b/samples/httpsession-gemfire-boot/src/main/java/sample/server/GemFireServer.java
@@ -47,7 +47,7 @@ import org.springframework.session.data.gemfire.config.annotation.web.http.Enabl
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 20) // <1>
public class GemFireServer {
- static final String DEFAULT_GEMFIRE_LOG_LEVEL = "config";
+ static final String DEFAULT_GEMFIRE_LOG_LEVEL = "warning";
public static void main(String[] args) {
SpringApplication springApplication = new SpringApplication(GemFireServer.class);
@@ -60,25 +60,27 @@ public class GemFireServer {
return new PropertySourcesPlaceholderConfigurer();
}
- String applicationName() {
- return "samples:httpsession-gemfire-boot-"
- .concat(GemFireServer.class.getSimpleName());
- }
-
- String gemfireLogLevel() {
- return System.getProperty("gemfire.log-level", DEFAULT_GEMFIRE_LOG_LEVEL);
- }
-
Properties gemfireProperties() { // <2>
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", applicationName());
gemfireProperties.setProperty("mcast-port", "0");
- gemfireProperties.setProperty("log-level", gemfireLogLevel());
+ gemfireProperties.setProperty("log-level", logLevel());
+ gemfireProperties.setProperty("jmx-manager", "true");
+ gemfireProperties.setProperty("jmx-manager-start", "true");
return gemfireProperties;
}
+ String applicationName() {
+ return "samples:httpsession-gemfire-boot:"
+ .concat(getClass().getSimpleName());
+ }
+
+ String logLevel() {
+ return System.getProperty("gemfire.log-level", DEFAULT_GEMFIRE_LOG_LEVEL);
+ }
+
@Bean
CacheFactoryBean gemfireCache() { // <3>
CacheFactoryBean gemfireCache = new CacheFactoryBean();
@@ -98,12 +100,11 @@ public class GemFireServer {
CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean();
gemfireCacheServer.setAutoStartup(true);
- gemfireCacheServer.setCache(gemfireCache);
gemfireCacheServer.setBindAddress(bindAddress);
+ gemfireCacheServer.setCache(gemfireCache);
gemfireCacheServer.setHostNameForClients(hostnameForClients);
gemfireCacheServer.setMaxTimeBetweenPings(
- Long.valueOf(TimeUnit.MINUTES.toMillis(1)).intValue());
- gemfireCacheServer.setNotifyBySubscription(true);
+ Long.valueOf(TimeUnit.SECONDS.toMillis(60)).intValue());
gemfireCacheServer.setPort(port);
return gemfireCacheServer;
diff --git a/samples/httpsession-gemfire-clientserver-xml/build.gradle b/samples/httpsession-gemfire-clientserver-xml/build.gradle
index 96bdbf2..a4fd6ac 100644
--- a/samples/httpsession-gemfire-clientserver-xml/build.gradle
+++ b/samples/httpsession-gemfire-clientserver-xml/build.gradle
@@ -17,6 +17,8 @@ dependencies {
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
+ runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
+
testCompile "junit:junit:$junitVersion"
integrationTestCompile gebDependencies
diff --git a/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/Application.java b/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/Application.java
index fdaf83d..6e627c5 100644
--- a/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/Application.java
+++ b/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/Application.java
@@ -27,9 +27,8 @@ import org.springframework.context.annotation.ImportResource;
public class Application {
public static void main(final String[] args) {
- AnnotationConfigApplicationContext context =
- new AnnotationConfigApplicationContext(Application.class);
- context.registerShutdownHook();
+ new AnnotationConfigApplicationContext(Application.class)
+ .registerShutdownHook();
}
}
// tag::end[]
diff --git a/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/GemFireCacheServerReadyBeanPostProcessor.java b/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/GemFireCacheServerReadyBeanPostProcessor.java
index 0c624bb..63fc6be 100644
--- a/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/GemFireCacheServerReadyBeanPostProcessor.java
+++ b/samples/httpsession-gemfire-clientserver-xml/src/main/java/sample/GemFireCacheServerReadyBeanPostProcessor.java
@@ -16,14 +16,8 @@
package sample;
-import java.io.IOException;
-import java.net.Socket;
-import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.annotation.Resource;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.management.membership.ClientMembership;
@@ -33,53 +27,42 @@ import com.gemstone.gemfire.management.membership.ClientMembershipListenerAdapte
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
-import org.springframework.data.gemfire.client.PoolFactoryBean;
-import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.Assert;
public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcessor {
static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
- static final long DEFAULT_WAIT_INTERVAL = 500L;
static final CountDownLatch latch = new CountDownLatch(1);
- static final String DEFAULT_SERVER_HOST = "localhost";
-
@Value("${spring.session.data.gemfire.port:${application.gemfire.client-server.port}}")
int port;
- // tag::class[]
- static {
- ClientMembership.registerClientMembershipListener(
- new ClientMembershipListenerAdapter() {
- public void memberJoined(final ClientMembershipEvent event) {
- if (!event.isClient()) {
- latch.countDown();
- }
- }
- });
- }
-
- @SuppressWarnings("all")
- @Resource(name = "applicationProperties")
- private Properties applicationProperties;
+ @Value("${application.gemfire.client-server.host:localhost}")
+ String host;
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
- String host = getServerHost(DEFAULT_SERVER_HOST);
- Assert.isTrue(waitForCacheServerToStart(host, this.port),
- String.format("GemFire Server failed to start [host: '%1$s', port: %2$d]%n",
- host, this.port));
+ if ("gemfirePool".equals(beanName)) {
+ ClientMembership.registerClientMembershipListener(
+ new ClientMembershipListenerAdapter() {
+ @Override
+ public void memberJoined(ClientMembershipEvent event) {
+ latch.countDown();
+ }
+ });
}
return bean;
}
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+
+ if (bean instanceof Pool && "gemfirePool".equals(beanName)) {
try {
- latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
+ Assert.state(latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS),
+ String.format("GemFire Cache Server failed to start on host [%1$s] and port [%2$d]",
+ this.host, this.port));
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
@@ -89,70 +72,4 @@ public class GemFireCacheServerReadyBeanPostProcessor implements BeanPostProcess
return bean;
}
// tag::end[]
-
- interface Condition {
- boolean evaluate();
- }
-
- String getServerHost(String defaultServerHost) {
- return this.applicationProperties
- .getProperty("application.gemfire.client-server.host", defaultServerHost);
- }
-
- boolean waitForCacheServerToStart(String host, int port) {
- return waitForCacheServerToStart(host, port, DEFAULT_WAIT_DURATION);
- }
-
- /* (non-Javadoc) */
- boolean waitForCacheServerToStart(final String host, final int port, long duration) {
- return waitOnCondition(new Condition() {
- AtomicBoolean connected = new AtomicBoolean(false);
-
- public boolean evaluate() {
- Socket socket = null;
-
- try {
- // NOTE: this code is not intended to be an atomic, compound action (a
- // possible race condition);
- // opening another connection (at the expense of using system
- // resources) after connectivity
- // has already been established is not detrimental in this use case
- if (!connected.get()) {
- socket = new Socket(host, port);
- connected.set(true);
- }
- }
- catch (IOException ignore) {
- }
- finally {
- GemFireUtils.close(socket);
- }
-
- return connected.get();
- }
- }, duration);
- }
-
- boolean waitOnCondition(Condition condition) {
- return waitOnCondition(condition, DEFAULT_WAIT_DURATION);
- }
-
- @SuppressWarnings("all")
- boolean waitOnCondition(Condition condition, long duration) {
- final long timeout = (System.currentTimeMillis() + duration);
-
- try {
- while (!condition.evaluate() && System.currentTimeMillis() < timeout) {
- synchronized (condition) {
- TimeUnit.MILLISECONDS.timedWait(condition, DEFAULT_WAIT_INTERVAL);
- }
- }
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
-
- return condition.evaluate();
- }
-
}
diff --git a/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/application.properties b/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/application.properties
index 1e7e05a..98fbf19 100644
--- a/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/application.properties
+++ b/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/application.properties
@@ -1,3 +1,2 @@
application.gemfire.client-server.host=localhost
-application.gemfire.client-server.port=11235
-application.gemfire.client-server.max-connections=50
+application.gemfire.client-server.port=12480
diff --git a/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/session-server.xml b/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/session-server.xml
index a160945..900f6fd 100644
--- a/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/session-server.xml
+++ b/samples/httpsession-gemfire-clientserver-xml/src/main/resources/META-INF/spring/session-server.xml
@@ -20,10 +20,6 @@
-
-
-
GemFireClientServerHttpSessionXmlSample0
@@ -32,15 +28,18 @@
true
-
-
+
+
-
+
+ host-name-for-clients="${application.gemfire.client-server.host}"
+ port="${spring.session.data.gemfire.port:${application.gemfire.client-server.port}}"/>
+
+
+
diff --git a/samples/httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml b/samples/httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml
index 4681882..9599181 100644
--- a/samples/httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml
+++ b/samples/httpsession-gemfire-clientserver-xml/src/main/webapp/WEB-INF/spring/session-client.xml
@@ -14,41 +14,36 @@
-
-
-
-
-
-
-
-
+
+
-
+
-
+
${sample.httpsession.gemfire.log-level:warning}
+
-
-
+
+ thread-local-connections="false">
+
+
+
diff --git a/samples/httpsession-gemfire-clientserver/build.gradle b/samples/httpsession-gemfire-clientserver/build.gradle
index 673ffc7..5b51a3d 100644
--- a/samples/httpsession-gemfire-clientserver/build.gradle
+++ b/samples/httpsession-gemfire-clientserver/build.gradle
@@ -12,6 +12,8 @@ dependencies {
providedCompile "javax.servlet:javax.servlet-api:$servletApiVersion"
+ runtime "org.springframework.shell:spring-shell:1.0.0.RELEASE"
+
testCompile "junit:junit:$junitVersion"
integrationTestCompile gebDependencies
diff --git a/samples/httpsession-gemfire-clientserver/src/main/java/sample/ClientConfig.java b/samples/httpsession-gemfire-clientserver/src/main/java/sample/ClientConfig.java
index 9ebe13a..2e85765 100644
--- a/samples/httpsession-gemfire-clientserver/src/main/java/sample/ClientConfig.java
+++ b/samples/httpsession-gemfire-clientserver/src/main/java/sample/ClientConfig.java
@@ -16,13 +16,10 @@
package sample;
-import java.io.IOException;
-import java.net.Socket;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.management.membership.ClientMembership;
@@ -38,7 +35,6 @@ import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
-import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.Assert;
// tag::class[]
@@ -46,39 +42,35 @@ import org.springframework.util.Assert;
public class ClientConfig {
static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
- static final long DEFAULT_WAIT_INTERVAL = 500L;
static final CountDownLatch latch = new CountDownLatch(1);
- static {
- System.setProperty("gemfire.log-level", logLevel());
-
- ClientMembership.registerClientMembershipListener(
- new ClientMembershipListenerAdapter() {
- public void memberJoined(ClientMembershipEvent event) {
- if (!event.isClient()) {
- latch.countDown();
- }
- }
- });
- }
-
- private static String logLevel() {
- return System.getProperty("sample.httpsession.gemfire.log-level", "warning");
- }
+ static final String DEFAULT_GEMFIRE_LOG_LEVEL = "warning";
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
- @Bean
Properties gemfireProperties() { // <2>
- return new Properties();
+ Properties gemfireProperties = new Properties();
+ gemfireProperties.setProperty("name", applicationName());
+ gemfireProperties.setProperty("log-level", logLevel());
+ return gemfireProperties;
+ }
+
+ String applicationName() {
+ return "samples:httpsession-gemfire-clientserver:"
+ .concat(getClass().getSimpleName());
+ }
+
+ String logLevel() {
+ return System.getProperty("sample.httpsession.gemfire.log-level",
+ DEFAULT_GEMFIRE_LOG_LEVEL);
}
@Bean
- ClientCacheFactoryBean gemfireCache() { // <4>
+ ClientCacheFactoryBean gemfireCache() { // <3>
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
clientCacheFactory.setClose(true);
@@ -88,46 +80,56 @@ public class ClientConfig {
}
@Bean
- PoolFactoryBean gemfirePool(// <3>
+ PoolFactoryBean gemfirePool(// <4>
@Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean();
- poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
poolFactory.setKeepAlive(false);
- poolFactory.setMaxConnections(ServerConfig.MAX_CONNECTIONS);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
- poolFactory.setRetryAttempts(2);
+ poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setThreadLocalConnections(false);
poolFactory.setServers(Collections.singletonList(
- new ConnectionEndpoint(ServerConfig.SERVER_HOSTNAME, port)));
+ newConnectionEndpoint(ServerConfig.SERVER_HOST, port)));
return poolFactory;
}
- @Bean
- BeanPostProcessor gemfireCacheServerReadyBeanPostProcessor(// <5>
- @Value("${spring.session.data.gemfire.port:" + ServerConfig.SERVER_PORT + "}") final int port) {
+ ConnectionEndpoint newConnectionEndpoint(String host, int port) {
+ return new ConnectionEndpoint(host, port);
+ }
+ @Bean
+ BeanPostProcessor gemfireCacheServerReadyBeanPostProcessor() { // <5>
return new BeanPostProcessor() {
- public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
- Assert.isTrue(waitForCacheServerToStart(ServerConfig.SERVER_HOSTNAME, port),
- String.format("GemFire Server failed to start [hostname: %1$s, port: %2$d]",
- ServerConfig.SERVER_HOSTNAME, port));
+ public Object postProcessBeforeInitialization(Object bean, String beanName)
+ throws BeansException {
+
+ if ("gemfirePool".equals(beanName)) {
+ ClientMembership.registerClientMembershipListener(
+ new ClientMembershipListenerAdapter() {
+ @Override
+ public void memberJoined(ClientMembershipEvent event) {
+ latch.countDown();
+ }
+ });
}
return bean;
}
- public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
- if (bean instanceof PoolFactoryBean || bean instanceof Pool) {
+ public Object postProcessAfterInitialization(Object bean, String beanName)
+ throws BeansException {
+
+ if (bean instanceof Pool && "gemfirePool".equals(beanName)) {
try {
- latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS);
+ Assert.state(latch.await(DEFAULT_WAIT_DURATION, TimeUnit.MILLISECONDS),
+ String.format("GemFire Cache Server failed to start on host [%1$s] and port [%2$d]",
+ ServerConfig.SERVER_HOST, ServerConfig.SERVER_PORT));
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
@@ -139,65 +141,4 @@ public class ClientConfig {
};
}
// end::class[]
-
- interface Condition {
- boolean evaluate();
- }
-
- boolean waitForCacheServerToStart(String host, int port) {
- return waitForCacheServerToStart(host, port, DEFAULT_WAIT_DURATION);
- }
-
- /* (non-Javadoc) */
- boolean waitForCacheServerToStart(final String host, final int port, long duration) {
- return waitOnCondition(new Condition() {
- AtomicBoolean connected = new AtomicBoolean(false);
-
- public boolean evaluate() {
- Socket socket = null;
-
- try {
- // NOTE: this code is not intended to be an atomic, compound action (a
- // possible race condition);
- // opening another connection (at the expense of using system
- // resources) after connectivity
- // has already been established is not detrimental in this use case
- if (!connected.get()) {
- socket = new Socket(host, port);
- connected.set(true);
- }
- }
- catch (IOException ignore) {
- }
- finally {
- GemFireUtils.close(socket);
- }
-
- return connected.get();
- }
- }, duration);
- }
-
- boolean waitOnCondition(Condition condition) {
- return waitOnCondition(condition, DEFAULT_WAIT_DURATION);
- }
-
- @SuppressWarnings("all")
- boolean waitOnCondition(Condition condition, long duration) {
- final long timeout = (System.currentTimeMillis() + duration);
-
- try {
- while (!condition.evaluate() && System.currentTimeMillis() < timeout) {
- synchronized (condition) {
- TimeUnit.MILLISECONDS.timedWait(condition, DEFAULT_WAIT_INTERVAL);
- }
- }
- }
- catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
-
- return condition.evaluate();
- }
-
}
diff --git a/samples/httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java b/samples/httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java
index d53b316..d1a86e4 100644
--- a/samples/httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java
+++ b/samples/httpsession-gemfire-clientserver/src/main/java/sample/ServerConfig.java
@@ -18,6 +18,7 @@ package sample;
import java.io.IOException;
import java.util.Properties;
+import java.util.concurrent.TimeUnit;
import com.gemstone.gemfire.cache.Cache;
@@ -33,13 +34,19 @@ import org.springframework.session.data.gemfire.config.annotation.web.http.Enabl
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = 30) // <1>
public class ServerConfig {
- static final int MAX_CONNECTIONS = 50;
static final int SERVER_PORT = 12480;
- static final String SERVER_HOSTNAME = "localhost";
+ static final String DEFAULT_GEMFIRE_LOG_LEVEL = "warning";
+ static final String SERVER_HOST = "localhost";
+
+ @SuppressWarnings("resource")
+ public static void main(String[] args) throws IOException { // <5>
+ new AnnotationConfigApplicationContext(ServerConfig.class)
+ .registerShutdownHook();
+ }
@Bean
- PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
+ static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@@ -47,7 +54,7 @@ public class ServerConfig {
Properties gemfireProperties() { // <2>
Properties gemfireProperties = new Properties();
- gemfireProperties.setProperty("name", "GemFireClientServerHttpSessionSample");
+ gemfireProperties.setProperty("name", applicationName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", logLevel());
gemfireProperties.setProperty("jmx-manager", "true");
@@ -56,8 +63,14 @@ public class ServerConfig {
return gemfireProperties;
}
- private String logLevel() {
- return System.getProperty("sample.httpsession.gemfire.log-level", "warning");
+ String applicationName() {
+ return "samples:httpsession-gemfire-clientserver:"
+ .concat(getClass().getSimpleName());
+ }
+
+ String logLevel() {
+ return System.getProperty("sample.httpsession.gemfire.log-level",
+ DEFAULT_GEMFIRE_LOG_LEVEL);
}
@Bean
@@ -71,25 +84,19 @@ public class ServerConfig {
}
@Bean
- CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache, // <4>
- @Value("${spring.session.data.gemfire.port:" + SERVER_PORT + "}") int port) {
+ CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
+ @Value("${spring.session.data.gemfire.port:" + SERVER_PORT + "}") int port) { // <4>
- CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
+ CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean();
- cacheServerFactory.setAutoStartup(true);
- cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
- cacheServerFactory.setCache(gemfireCache);
- cacheServerFactory.setHostNameForClients(SERVER_HOSTNAME);
- cacheServerFactory.setMaxConnections(MAX_CONNECTIONS);
- cacheServerFactory.setPort(port);
+ gemfireCacheServer.setAutoStartup(true);
+ gemfireCacheServer.setBindAddress(SERVER_HOST);
+ gemfireCacheServer.setCache(gemfireCache);
+ gemfireCacheServer.setHostNameForClients(SERVER_HOST);
+ gemfireCacheServer.setMaxTimeBetweenPings(Long.valueOf(TimeUnit.SECONDS.toMillis(60)).intValue());
+ gemfireCacheServer.setPort(port);
- return cacheServerFactory;
+ return gemfireCacheServer;
}
-
- @SuppressWarnings("resource")
- public static void main(final String[] args) throws IOException { // <5>
- new AnnotationConfigApplicationContext(ServerConfig.class).registerShutdownHook();
- }
-
}
// end::class[]
diff --git a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionJavaConfigurationTests.java b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionJavaConfigurationTests.java
index 58c7661..4b289ef 100644
--- a/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionJavaConfigurationTests.java
+++ b/spring-session/src/integration-test/java/org/springframework/session/data/gemfire/config/annotation/web/http/GemFireHttpSessionJavaConfigurationTests.java
@@ -42,9 +42,8 @@ import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
- * The GemFireHttpSessionJavaConfigurationTests class is a test suite of test cases
- * testing the configuration of Spring Session backed by GemFire using Java-based
- * configuration meta-data.
+ * Test suite of test cases testing the configuration of Spring Session backed by GemFire
+ * using Java-based configuration meta-data.
*
* @author John Blum
* @since 1.1.0
@@ -62,14 +61,14 @@ import static org.assertj.core.api.Assertions.assertThat;
@ContextConfiguration
@DirtiesContext
@WebAppConfiguration
-public class GemFireHttpSessionJavaConfigurationTests
- extends AbstractGemFireIntegrationTests {
+public class GemFireHttpSessionJavaConfigurationTests extends AbstractGemFireIntegrationTests {
@Autowired
private Cache gemfireCache;
protected Region assertCacheAndRegion(Cache gemfireCache,
String regionName, DataPolicy dataPolicy) {
+
assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue();
Region region = gemfireCache.getRegion(regionName);
@@ -81,16 +80,16 @@ public class GemFireHttpSessionJavaConfigurationTests
@Test
public void gemfireCacheConfigurationIsValid() {
- Region