Remove GemFire

Fixes gh-768
This commit is contained in:
Rob Winch
2017-04-26 19:26:14 -05:00
parent b254c7c6b9
commit 02da23a2a0
81 changed files with 0 additions and 13496 deletions

View File

@@ -10,7 +10,6 @@ dependencies {
optional "org.springframework:spring-messaging"
optional "org.springframework:spring-web"
optional "org.springframework:spring-websocket"
optional "org.springframework.data:spring-data-gemfire"
optional "org.springframework.data:spring-data-mongodb"
optional "org.springframework.data:spring-data-redis"
optional "org.springframework.security:spring-security-core"
@@ -27,7 +26,6 @@ dependencies {
integrationTestCompile "org.hsqldb:hsqldb"
integrationTestCompile "de.flapdoodle.embed:de.flapdoodle.embed.mongo"
integrationTestRuntime "org.springframework.shell:spring-shell"
testCompile "junit:junit"
testCompile "org.mockito:mockito-core"

View File

@@ -1,460 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.File;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.server.CacheServer;
import org.junit.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.events.AbstractSessionEvent;
import static org.assertj.core.api.Assertions.assertThat;
/**
* {@link AbstractGemFireIntegrationTests} is an abstract base class encapsulating common functionality
* for writing Spring Session GemFire integration tests.
*
* @author John Blum
* @since 1.1.0
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.query.Index
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.session.ExpiringSession
*/
public abstract class AbstractGemFireIntegrationTests {
protected static final boolean DEFAULT_ENABLE_QUERY_DEBUGGING = false;
protected static final boolean GEMFIRE_QUERY_DEBUG = Boolean.getBoolean("spring.session.data.gemfire.query.debug");
protected static final int DEFAULT_GEMFIRE_SERVER_PORT = CacheServer.DEFAULT_PORT;
protected static final long DEFAULT_WAIT_DURATION = TimeUnit.SECONDS.toMillis(20);
protected static final long DEFAULT_WAIT_INTERVAL = 500L;
protected static final File WORKING_DIRECTORY = new File(System.getProperty("user.dir"));
protected static final String DEFAULT_PROCESS_CONTROL_FILENAME = "process.ctl";
protected static final String GEMFIRE_LOG_FILE_NAME =
System.getProperty("spring.session.data.gemfire.log-file", "server.log");
protected static final String GEMFIRE_LOG_LEVEL =
System.getProperty("spring.session.data.gemfire.log-level", "error");
@Autowired
protected Cache gemfireCache;
@Autowired
protected GemFireOperationsSessionRepository gemfireSessionRepository;
@Before
public void setup() {
System.setProperty("gemfire.Query.VERBOSE", String.valueOf(isQueryDebuggingEnabled()));
}
/* (non-Javadoc) */
protected static File createDirectory(String pathname) {
File directory = new File(WORKING_DIRECTORY, pathname);
assertThat(directory.isDirectory() || directory.mkdirs())
.as(String.format("Failed to create directory (%1$s)", directory)).isTrue();
directory.deleteOnExit();
return directory;
}
/* (non-Javadoc) */
protected static List<String> createJavaProcessCommandLine(Class<?> type, String... args) {
List<String> commandLine = new ArrayList<String>();
String javaHome = System.getProperty("java.home");
String javaExe = new File(new File(javaHome, "bin"), "java").getAbsolutePath();
commandLine.add(javaExe);
commandLine.add("-server");
commandLine.add("-ea");
commandLine.add(String.format("-Dgemfire.log-file=%1$s", GEMFIRE_LOG_FILE_NAME));
commandLine.add(String.format("-Dgemfire.log-level=%1$s", GEMFIRE_LOG_LEVEL));
commandLine.add(String.format("-Dgemfire.Query.VERBOSE=%1$s", GEMFIRE_QUERY_DEBUG));
commandLine.addAll(extractJvmArguments(args));
commandLine.add("-classpath");
commandLine.add(System.getProperty("java.class.path"));
commandLine.add(type.getName());
commandLine.addAll(extractProgramArguments(args));
// System.err.printf("Java process command-line is (%1$s)%n", commandLine);
return commandLine;
}
/* (non-Javadoc) */
protected static List<String> extractJvmArguments(final String... args) {
List<String> jvmArgs = new ArrayList<String>(args.length);
for (String arg : args) {
if (arg.startsWith("-")) {
jvmArgs.add(arg);
}
}
return jvmArgs;
}
/* (non-Javadoc) */
protected static List<String> extractProgramArguments(final String... args) {
List<String> jvmArgs = new ArrayList<String>(args.length);
for (String arg : args) {
if (!arg.startsWith("-")) {
jvmArgs.add(arg);
}
}
return jvmArgs;
}
/* (non-Javadoc) */
protected static Process run(Class<?> type, File directory, String... args) throws IOException {
return new ProcessBuilder().command(createJavaProcessCommandLine(type, args)).directory(directory).start();
}
/* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer) {
return waitForCacheServerToStart(cacheServer, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(CacheServer cacheServer, long duration) {
return waitForCacheServerToStart(cacheServer.getBindAddress(), cacheServer.getPort(), duration);
}
/* (non-Javadoc) */
protected static boolean waitForCacheServerToStart(String host, int port) {
return waitForCacheServerToStart(host, port, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static 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 {
if (!connected.get()) {
socket = new Socket(host, port);
connected.set(true);
}
}
catch (IOException ignore) {
}
finally {
GemFireUtils.close(socket);
}
return connected.get();
}
}, duration);
}
// NOTE this method would not be necessary except Spring Sessions' build does not fork
// the test JVM
// for every test class.
/* (non-Javadoc) */
protected static boolean waitForClientCacheToClose() {
return waitForClientCacheToClose(DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static boolean waitForClientCacheToClose(long duration) {
try {
final ClientCache clientCache = ClientCacheFactory.getAnyInstance();
clientCache.close();
waitOnCondition(new Condition() {
public boolean evaluate() {
return clientCache.isClosed();
}
}, duration);
return clientCache.isClosed();
}
catch (CacheClosedException ignore) {
return true;
}
}
/* (non-Javadoc) */
protected static boolean waitForProcessToStart(Process process, File directory) {
return waitForProcessToStart(process, directory, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
@SuppressWarnings("all")
protected static boolean waitForProcessToStart(Process process, File directory, long duration) {
final File processControl = new File(directory, DEFAULT_PROCESS_CONTROL_FILENAME);
waitOnCondition(new Condition() {
public boolean evaluate() {
return processControl.isFile();
}
}, duration);
return process.isAlive();
}
/* (non-Javadoc) */
protected static int waitForProcessToStop(Process process, File directory) {
return waitForProcessToStop(process, directory, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
protected static int waitForProcessToStop(Process process, File directory, long duration) {
long timeout = (System.currentTimeMillis() + duration);
try {
while (process.isAlive() && System.currentTimeMillis() < timeout) {
if (process.waitFor(DEFAULT_WAIT_INTERVAL, TimeUnit.MILLISECONDS)) {
return process.exitValue();
}
}
}
catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return (process.isAlive() ? -1 : process.exitValue());
}
/* (non-Javadoc) */
protected static boolean waitOnCondition(Condition condition) {
return waitOnCondition(condition, DEFAULT_WAIT_DURATION);
}
/* (non-Javadoc) */
@SuppressWarnings("all")
protected static boolean waitOnCondition(Condition condition, long duration) {
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();
}
/* (non-Javadoc) */
protected static File writeProcessControlFile(File path) throws IOException {
assertThat(path != null && path.isDirectory()).isTrue();
File processControl = new File(path, DEFAULT_PROCESS_CONTROL_FILENAME);
assertThat(processControl.createNewFile()).isTrue();
processControl.deleteOnExit();
return processControl;
}
/* (non-Javadoc) */
protected void assertValidSession(ExpiringSession session) {
assertThat(session).isNotNull();
assertThat(session.getId()).isNotEmpty();
assertThat(session.isExpired()).isFalse();
}
/* (non-Javadoc) */
protected void assertRegion(Region<?, ?> actualRegion, String expectedName, DataPolicy expectedDataPolicy) {
assertThat(actualRegion).isNotNull();
assertThat(actualRegion.getName()).isEqualTo(expectedName);
assertThat(actualRegion.getFullPath()).isEqualTo(GemFireUtils.toRegionPath(expectedName));
assertThat(actualRegion.getAttributes()).isNotNull();
assertThat(actualRegion.getAttributes().getDataPolicy()).isEqualTo(expectedDataPolicy);
}
/* (non-Javadoc) */
protected void assertIndex(Index index, String expectedExpression, String expectedFromClause) {
assertThat(index).isNotNull();
assertThat(index.getIndexedExpression()).isEqualTo(expectedExpression);
assertThat(index.getFromClause()).isEqualTo(expectedFromClause);
}
/* (non-Javadoc) */
protected void assertEntryIdleTimeout(Region<?, ?> region, ExpirationAction expectedAction, int expectedTimeout) {
assertEntryIdleTimeout(region.getAttributes().getEntryIdleTimeout(), expectedAction, expectedTimeout);
}
/* (non-Javadoc) */
protected void assertEntryIdleTimeout(ExpirationAttributes actualExpirationAttributes,
ExpirationAction expectedAction, int expectedTimeout) {
assertThat(actualExpirationAttributes).isNotNull();
assertThat(actualExpirationAttributes.getAction()).isEqualTo(expectedAction);
assertThat(actualExpirationAttributes.getTimeout()).isEqualTo(expectedTimeout);
}
/* (non-Javadoc) */
protected boolean enableQueryDebugging() {
return DEFAULT_ENABLE_QUERY_DEBUGGING;
}
/* (non-Javadoc) */
protected boolean isQueryDebuggingEnabled() {
return (GEMFIRE_QUERY_DEBUG || enableQueryDebugging());
}
/* (non-Javadoc) */
protected List<String> listRegions(GemFireCache gemfireCache) {
Set<Region<?, ?>> regions = gemfireCache.rootRegions();
List<String> regionList = new ArrayList<String>(regions.size());
for (Region<?, ?> region : regions) {
regionList.add(region.getFullPath());
}
return regionList;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected <T extends ExpiringSession> T createSession() {
T expiringSession = (T) this.gemfireSessionRepository.createSession();
assertThat(expiringSession).isNotNull();
return expiringSession;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected <T extends ExpiringSession> T createSession(String principalName) {
GemFireOperationsSessionRepository.GemFireSession session = createSession();
session.setPrincipalName(principalName);
return (T) session;
}
/* (non-Javadoc) */
protected <T extends ExpiringSession> T delete(T session) {
this.gemfireSessionRepository.delete(session);
return session;
}
/* (non-Javadoc) */
protected <T extends ExpiringSession> T expire(T session) {
session.setLastAccessedTime(0L);
return session;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected <T extends ExpiringSession> T get(String sessionId) {
return (T) this.gemfireSessionRepository.getSession(sessionId);
}
/* (non-Javadoc) */
protected <T extends ExpiringSession> T save(T session) {
this.gemfireSessionRepository.save(session);
return session;
}
/* (non-Javadoc) */
protected <T extends ExpiringSession> T touch(T session) {
session.setLastAccessedTime(System.currentTimeMillis());
return session;
}
/**
* The SessionEventListener class is a Spring {@link ApplicationListener} listening
* for Spring HTTP Session application events.
*
* @see org.springframework.context.ApplicationListener
* @see org.springframework.session.events.AbstractSessionEvent
*/
public static class SessionEventListener implements ApplicationListener<AbstractSessionEvent> {
private volatile AbstractSessionEvent sessionEvent;
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
public <T extends AbstractSessionEvent> T getSessionEvent() {
T sessionEvent = (T) this.sessionEvent;
this.sessionEvent = null;
return sessionEvent;
}
/* (non-Javadoc) */
public void onApplicationEvent(AbstractSessionEvent event) {
this.sessionEvent = event;
}
/* (non-Javadoc) */
public <T extends AbstractSessionEvent> T waitForSessionEvent(long duration) {
waitOnCondition(new Condition() {
public boolean evaluate() {
return (SessionEventListener.this.sessionEvent != null);
}
}, duration);
return getSessionEvent();
}
}
/**
* The Condition interface defines a logical condition that must be satisfied before
* it is safe to proceed.
*/
protected interface Condition {
boolean evaluate();
}
}

View File

@@ -1,374 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests to test the functionality of GemFire-backed Spring Sessions using
* the GemFire client-server topology.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.server.CacheServer
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes =
ClientServerGemFireOperationsSessionRepositoryIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
@DirtiesContext
@WebAppConfiguration
public class ClientServerGemFireOperationsSessionRepositoryIntegrationTests
extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private static File processWorkingDirectory;
private static Process gemfireServer;
private static final String SPRING_SESSION_GEMFIRE_REGION_NAME = "TestClientServerSessions";
@Autowired
private SessionEventListener sessionEventListener;
@BeforeClass
public static void startGemFireServer() throws IOException {
long t0 = System.currentTimeMillis();
int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting a GemFire Server running on host [%1$s] listening on port [%2$d]%n",
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port);
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
String processWorkingDirectoryPathname =
String.format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port))
.isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
}
@AfterClass
public static void stopGemFireServer() {
if (gemfireServer != null) {
gemfireServer.destroy();
System.err.printf("GemFire Server [exit code = %1$d]%n",
waitForProcessToStop(gemfireServer, processWorkingDirectory));
}
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) {
FileSystemUtils.deleteRecursively(processWorkingDirectory);
}
assertThat(waitForClientCacheToClose(DEFAULT_WAIT_DURATION)).isTrue();
}
@Before
public void setup() {
assertThat(GemFireUtils.isClient(gemfireCache)).isTrue();
Region<Object, ExpiringSession> springSessionGemFireRegion =
gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertThat(springSessionGemFireRegion).isNotNull();
RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes =
springSessionGemFireRegion.getAttributes();
assertThat(springSessionGemFireRegionAttributes).isNotNull();
assertThat(springSessionGemFireRegionAttributes.getDataPolicy()).isEqualTo(DataPolicy.NORMAL);
}
@After
public void tearDown() {
this.sessionEventListener.getSessionEvent();
}
@Test
public void createSessionFiresSessionCreatedEvent() {
long beforeOrAtCreationTime = System.currentTimeMillis();
ExpiringSession expectedSession = save(createSession());
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
ExpiringSession createdSession = sessionEvent.getSession();
assertThat(createdSession.getId()).isEqualTo(expectedSession.getId());
assertThat(createdSession.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(createdSession.getLastAccessedTime()).isEqualTo(createdSession.getCreationTime());
assertThat(createdSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
createdSession.setAttribute("attrOne", 1);
assertThat(save(touch(createdSession)).<Integer>getAttribute("attrOne")).isEqualTo(1);
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isNull();
this.gemfireSessionRepository.delete(expectedSession.getId());
}
@Test
public void getExistingNonExpiredSessionBeforeAndAfterExpiration() {
ExpiringSession expectedSession = save(touch(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
assertThat(this.sessionEventListener.<SessionCreatedEvent>getSessionEvent()).isNull();
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
sessionEvent = this.sessionEventListener.waitForSessionEvent(
TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId());
ExpiringSession expiredSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(expiredSession).isNull();
}
@Test
public void deleteExistingNonExpiredSessionFiresSessionDeletedEventAndReturnsNullOnGet() {
ExpiringSession expectedSession = save(touch(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
this.gemfireSessionRepository.delete(expectedSession.getId());
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId());
ExpiringSession deletedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(deletedSession).isNull();
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME,
clientRegionShortcut = ClientRegionShortcut.CACHING_PROXY,
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionDataGemFireClientConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
@Bean
ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
clientCacheFactory.setClose(true);
clientCacheFactory.setProperties(gemfireProperties());
return clientCacheFactory;
}
@Bean
PoolFactoryBean gemfirePool(
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setKeepAlive(false);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
return poolFactory;
}
@Bean
public SessionEventListener sessionEventListener() {
return new SessionEventListener();
}
// used for debugging purposes
@SuppressWarnings("resource")
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(
SpringSessionDataGemFireClientConfiguration.class);
applicationContext.registerShutdownHook();
ClientCache clientCache = applicationContext.getBean(ClientCache.class);
for (InetSocketAddress server : clientCache.getCurrentServers()) {
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
server.getHostName(), server.getPort());
}
}
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME,
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionDataGemFireServerConfiguration {
static final String SERVER_HOSTNAME = "localhost";
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return ClientServerGemFireOperationsSessionRepositoryIntegrationTests.class.getName();
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setPort(port);
return cacheServerFactory;
}
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}
}
}

View File

@@ -1,285 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests testing the addition/removal of HTTP Session Attributes
* and the proper persistence of the HTTP Session state in a GemFire cache
* across a client/server topology.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @since 1.3.1
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes =
ClientServerHttpSessionAttributesDeltaIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
public class ClientServerHttpSessionAttributesDeltaIntegrationTests extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private static File processWorkingDirectory;
private static Process gemfireServer;
@BeforeClass
public static void startGemFireServer() throws IOException {
long t0 = System.currentTimeMillis();
int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting a GemFire Server running on host [%1$s] listening on port [%2$d]%n",
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port);
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
String processWorkingDirectoryPathname =
String.format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port))
.isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
}
@AfterClass
public static void stopGemFireServer() {
if (gemfireServer != null) {
gemfireServer.destroy();
System.err.printf("GemFire Server [exit code = %1$d]%n",
waitForProcessToStop(gemfireServer, processWorkingDirectory));
}
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) {
FileSystemUtils.deleteRecursively(processWorkingDirectory);
}
assertThat(waitForClientCacheToClose(DEFAULT_WAIT_DURATION)).isTrue();
}
@Test
public void sessionCreationAndAccessIsSuccessful() {
ExpiringSession session = save(touch(createSession()));
assertThat(session).isNotNull();
assertThat(session.isExpired()).isFalse();
session.setAttribute("attrOne", 1);
session.setAttribute("attrTwo", 2);
save(touch(session));
ExpiringSession loadedSession = get(session.getId());
assertThat(loadedSession).isNotNull();
assertThat(loadedSession.isExpired()).isFalse();
assertThat(loadedSession).isNotSameAs(session);
assertThat(loadedSession.getId()).isEqualTo(session.getId());
assertThat(loadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
assertThat(loadedSession.<Integer>getAttribute("attrTwo")).isEqualTo(2);
loadedSession.removeAttribute("attrTwo");
assertThat(loadedSession.getAttributeNames()).doesNotContain("attrTwo");
assertThat(loadedSession.getAttributeNames()).hasSize(1);
save(touch(loadedSession));
ExpiringSession reloadedSession = get(loadedSession.getId());
assertThat(reloadedSession).isNotNull();
assertThat(reloadedSession.isExpired()).isFalse();
assertThat(reloadedSession).isNotSameAs(loadedSession);
assertThat(reloadedSession.getId()).isEqualTo(loadedSession.getId());
assertThat(reloadedSession.getAttributeNames()).hasSize(1);
assertThat(reloadedSession.getAttributeNames()).doesNotContain("attrTwo");
assertThat(reloadedSession.<Integer>getAttribute("attrOne")).isEqualTo(1);
}
@EnableGemFireHttpSession
static class SpringSessionDataGemFireClientConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
@Bean
ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
clientCacheFactory.setClose(true);
clientCacheFactory.setProperties(gemfireProperties());
return clientCacheFactory;
}
@Bean
PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:"
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setKeepAlive(false);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
return poolFactory;
}
// used for debugging purposes
@SuppressWarnings("resource")
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireClientConfiguration.class);
applicationContext.registerShutdownHook();
ClientCache clientCache = applicationContext.getBean(ClientCache.class);
for (InetSocketAddress server : clientCache.getCurrentServers()) {
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
server.getHostName(), server.getPort());
}
}
}
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionDataGemFireServerConfiguration {
static final String SERVER_HOSTNAME = "localhost";
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return ClientServerHttpSessionAttributesDeltaIntegrationTests.class.getName();
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setPort(port);
return cacheServerFactory;
}
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}
}
}

View File

@@ -1,309 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.client.ClientCache;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* The ClientServerProxyRegionSessionOperationsIntegrationTests class...
*
* @author John Blum
* @since 1.0.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(classes =
ClientServerProxyRegionSessionOperationsIntegrationTests.SpringSessionDataGemFireClientConfiguration.class)
public class ClientServerProxyRegionSessionOperationsIntegrationTests extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private static File processWorkingDirectory;
private static Process gemfireServer;
@Autowired
private SessionEventListener sessionEventListener;
@BeforeClass
public static void startGemFireServer() throws IOException {
long t0 = System.currentTimeMillis();
int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting a GemFire Server running on host [%1$s] listening on port [%2$d]%n",
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port);
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
String processWorkingDirectoryPathname =
String.format("gemfire-client-server-tests-%1$s", TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionDataGemFireServerConfiguration.class, processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port))
.isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
}
@AfterClass
public static void stopGemFireServer() {
if (gemfireServer != null) {
gemfireServer.destroy();
System.err.printf("GemFire Server [exit code = %1$d]%n",
waitForProcessToStop(gemfireServer, processWorkingDirectory));
}
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) {
FileSystemUtils.deleteRecursively(processWorkingDirectory);
}
assertThat(waitForClientCacheToClose(DEFAULT_WAIT_DURATION)).isTrue();
}
@Test
public void createReadUpdateExpireRecreateDeleteRecreateSessionResultsCorrectSessionCreatedEvents() {
ExpiringSession session = save(touch(createSession()));
assertValidSession(session);
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
// GET
ExpiringSession loadedSession = get(session.getId());
assertThat(loadedSession).isNotNull();
assertThat(loadedSession.getId()).isEqualTo(session.getId());
assertThat(loadedSession.getCreationTime()).isEqualTo(session.getCreationTime());
assertThat(loadedSession.getLastAccessedTime()).isGreaterThanOrEqualTo((session.getLastAccessedTime()));
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isNull();
loadedSession.setAttribute("attrOne", 1);
loadedSession.setAttribute("attrTwo", 2);
// UPDATE
save(touch(loadedSession));
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isNull();
// EXPIRE
sessionEvent = this.sessionEventListener.waitForSessionEvent(
TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
// RECREATE
save(touch(session));
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
// DELETE
delete(session);
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
// RECREATE
save(touch(session));
sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(session.getId());
}
@EnableGemFireHttpSession
static class SpringSessionDataGemFireClientConfiguration {
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
@Bean
ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean clientCacheFactory = new ClientCacheFactoryBean();
clientCacheFactory.setClose(true);
clientCacheFactory.setProperties(gemfireProperties());
return clientCacheFactory;
}
@Bean
PoolFactoryBean gemfirePool(@Value("${spring.session.data.gemfire.port:"
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setKeepAlive(false);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setServers(Collections.singletonList(new ConnectionEndpoint(
SpringSessionDataGemFireServerConfiguration.SERVER_HOSTNAME, port)));
return poolFactory;
}
@Bean
public SessionEventListener sessionEventListener() {
return new SessionEventListener();
}
// used for debugging purposes
@SuppressWarnings("resource")
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireClientConfiguration.class);
applicationContext.registerShutdownHook();
ClientCache clientCache = applicationContext.getBean(ClientCache.class);
for (InetSocketAddress server : clientCache.getCurrentServers()) {
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
server.getHostName(), server.getPort());
}
}
}
@EnableGemFireHttpSession(maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionDataGemFireServerConfiguration {
static final String SERVER_HOSTNAME = "localhost";
@Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return ClientServerProxyRegionSessionOperationsIntegrationTests.class.getName();
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setPort(port);
return cacheServerFactory;
}
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(SpringSessionDataGemFireServerConfiguration.class);
context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}
}
}

View File

@@ -1,459 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.UUID;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.Query;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.cache.query.SelectResults;
import org.apache.geode.pdx.PdxReader;
import org.apache.geode.pdx.PdxSerializable;
import org.apache.geode.pdx.PdxWriter;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to test the {@code findByPrincipalName} query method
* on {@link GemFireOperationsSessionRepository}.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
@WebAppConfiguration
public class GemFireOperationsSessionRepositoryIntegrationTests extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 300;
private static final String GEMFIRE_LOG_LEVEL = "warning";
private static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
private static final String SPRING_SESSION_GEMFIRE_REGION_NAME = "TestPartitionedSessions";
SecurityContext context;
SecurityContext changedContext;
@Before
public void setup() {
this.context = SecurityContextHolder.createEmptyContext();
this.context.setAuthentication(
new UsernamePasswordAuthenticationToken("username-" + UUID.randomUUID(),
"na", AuthorityUtils.createAuthorityList("ROLE_USER")));
this.changedContext = SecurityContextHolder.createEmptyContext();
this.changedContext.setAuthentication(new UsernamePasswordAuthenticationToken(
"changedContext-" + UUID.randomUUID(), "na",
AuthorityUtils.createAuthorityList("ROLE_USER")));
assertThat(this.gemfireCache).isNotNull();
assertThat(this.gemfireSessionRepository).isNotNull();
assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
Region<Object, ExpiringSession> sessionRegion = this.gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME, DataPolicy.PARTITION);
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE, MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
protected Map<String, ExpiringSession> doFindByIndexNameAndIndexValue(
String indexName, String indexValue) {
return this.gemfireSessionRepository.findByIndexNameAndIndexValue(indexName,
indexValue);
}
protected Map<String, ExpiringSession> doFindByPrincipalName(String principalName) {
return doFindByIndexNameAndIndexValue(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME,
principalName);
}
@SuppressWarnings({ "unchecked" })
protected Map<String, ExpiringSession> doFindByPrincipalName(String regionName,
String principalName) {
try {
Region<String, ExpiringSession> region = this.gemfireCache.getRegion(regionName);
assertThat(region).isNotNull();
QueryService queryService = region.getRegionService().getQueryService();
String queryString = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
region.getFullPath());
Query query = queryService.newQuery(queryString);
SelectResults<ExpiringSession> results =
(SelectResults<ExpiringSession>) query.execute(new Object[] { principalName });
Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(results.size());
for (ExpiringSession session : results.asList()) {
sessions.put(session.getId(), session);
}
return sessions;
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
protected boolean enableQueryDebugging() {
return true;
}
protected ExpiringSession setAttribute(ExpiringSession session, String attributeName,
Object attributeValue) {
session.setAttribute(attributeName, attributeValue);
return session;
}
@Test
public void findSessionsByIndexedSessionAttributeNameValues() {
ExpiringSession johnBlumSession = save(touch(setAttribute(
createSession("johnBlum"), "vip", "yes")));
ExpiringSession robWinchSession = save(touch(setAttribute(
createSession("robWinch"), "vip", "yes")));
ExpiringSession jonDoeSession = save(touch(setAttribute(
createSession("jonDoe"), "vip", "no")));
ExpiringSession pieDoeSession = save(touch(setAttribute(
createSession("pieDoe"), "viper", "true")));
ExpiringSession sourDoeSession = save(touch(createSession("sourDoe")));
assertThat(this.<ExpiringSession>get(johnBlumSession.getId())).isEqualTo(johnBlumSession);
assertThat(johnBlumSession.<String>getAttribute("vip")).isEqualTo("yes");
assertThat(this.<ExpiringSession>get(robWinchSession.getId())).isEqualTo(robWinchSession);
assertThat(robWinchSession.<String>getAttribute("vip")).isEqualTo("yes");
assertThat(this.<ExpiringSession>get(jonDoeSession.getId())).isEqualTo(jonDoeSession);
assertThat(jonDoeSession.<String>getAttribute("vip")).isEqualTo("no");
assertThat(this.<ExpiringSession>get(pieDoeSession.getId())).isEqualTo(pieDoeSession);
assertThat(pieDoeSession.getAttributeNames().contains("vip")).isFalse();
assertThat(this.<ExpiringSession>get(sourDoeSession.getId())).isEqualTo(sourDoeSession);
assertThat(sourDoeSession.getAttributeNames().contains("vip")).isFalse();
Map<String, ExpiringSession> vipSessions = doFindByIndexNameAndIndexValue("vip", "yes");
assertThat(vipSessions).isNotNull();
assertThat(vipSessions.size()).isEqualTo(2);
assertThat(vipSessions.get(johnBlumSession.getId())).isEqualTo(johnBlumSession);
assertThat(vipSessions.get(robWinchSession.getId())).isEqualTo(robWinchSession);
assertThat(vipSessions.containsKey(jonDoeSession.getId()));
assertThat(vipSessions.containsKey(pieDoeSession.getId()));
assertThat(vipSessions.containsKey(sourDoeSession.getId()));
Map<String, ExpiringSession> nonVipSessions = doFindByIndexNameAndIndexValue(
"vip", "no");
assertThat(nonVipSessions).isNotNull();
assertThat(nonVipSessions.size()).isEqualTo(1);
assertThat(nonVipSessions.get(jonDoeSession.getId())).isEqualTo(jonDoeSession);
assertThat(nonVipSessions.containsKey(johnBlumSession.getId()));
assertThat(nonVipSessions.containsKey(robWinchSession.getId()));
assertThat(nonVipSessions.containsKey(pieDoeSession.getId()));
assertThat(nonVipSessions.containsKey(sourDoeSession.getId()));
Map<String, ExpiringSession> noSessions = doFindByIndexNameAndIndexValue(
"nonExistingAttribute", "test");
assertThat(noSessions).isNotNull();
assertThat(noSessions.isEmpty()).isTrue();
}
@Test
public void findSessionsByPrincipalName() {
ExpiringSession sessionOne = save(touch(createSession("robWinch")));
ExpiringSession sessionTwo = save(touch(createSession("johnBlum")));
ExpiringSession sessionThree = save(touch(createSession("robWinch")));
ExpiringSession sessionFour = save(touch(createSession("johnBlum")));
ExpiringSession sessionFive = save(touch(createSession("robWinch")));
assertThat(this.<ExpiringSession>get(sessionOne.getId())).isEqualTo(sessionOne);
assertThat(this.<ExpiringSession>get(sessionTwo.getId())).isEqualTo(sessionTwo);
assertThat(this.<ExpiringSession>get(sessionThree.getId())).isEqualTo(sessionThree);
assertThat(this.<ExpiringSession>get(sessionFour.getId())).isEqualTo(sessionFour);
assertThat(this.<ExpiringSession>get(sessionFive.getId())).isEqualTo(sessionFive);
Map<String, ExpiringSession> johnBlumSessions = doFindByPrincipalName("johnBlum");
assertThat(johnBlumSessions).isNotNull();
assertThat(johnBlumSessions.size()).isEqualTo(2);
assertThat(johnBlumSessions.containsKey(sessionOne.getId())).isFalse();
assertThat(johnBlumSessions.containsKey(sessionThree.getId())).isFalse();
assertThat(johnBlumSessions.containsKey(sessionFive.getId())).isFalse();
assertThat(johnBlumSessions.get(sessionTwo.getId())).isEqualTo(sessionTwo);
assertThat(johnBlumSessions.get(sessionFour.getId())).isEqualTo(sessionFour);
Map<String, ExpiringSession> robWinchSessions = doFindByPrincipalName("robWinch");
assertThat(robWinchSessions).isNotNull();
assertThat(robWinchSessions.size()).isEqualTo(3);
assertThat(robWinchSessions.containsKey(sessionTwo.getId())).isFalse();
assertThat(robWinchSessions.containsKey(sessionFour.getId())).isFalse();
assertThat(robWinchSessions.get(sessionOne.getId())).isEqualTo(sessionOne);
assertThat(robWinchSessions.get(sessionThree.getId())).isEqualTo(sessionThree);
assertThat(robWinchSessions.get(sessionFive.getId())).isEqualTo(sessionFive);
}
@Test
public void findSessionsBySecurityPrincipalName() {
ExpiringSession toSave = this.gemfireSessionRepository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
save(toSave);
Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(getSecurityName());
assertThat(findByPrincipalName).hasSize(1);
assertThat(findByPrincipalName.keySet()).containsOnly(toSave.getId());
}
@Test
public void findSessionsByChangedSecurityPrincipalName() {
ExpiringSession toSave = this.gemfireSessionRepository.createSession();
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.context);
save(toSave);
toSave.setAttribute(SPRING_SECURITY_CONTEXT, this.changedContext);
save(toSave);
Map<String, ExpiringSession> findByPrincipalName = doFindByPrincipalName(getSecurityName());
assertThat(findByPrincipalName).isEmpty();
findByPrincipalName = doFindByPrincipalName(getChangedSecurityName());
assertThat(findByPrincipalName).hasSize(1);
}
@Test
public void findsNoSessionsByNonExistingPrincipal() {
Map<String, ExpiringSession> nonExistingPrincipalSessions =
doFindByPrincipalName("nonExistingPrincipalName");
assertThat(nonExistingPrincipalSessions).isNotNull();
assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue();
}
@Test
public void findsNoSessionsAfterPrincipalIsRemoved() {
String username = "doesNotFindAfterPrincipalRemoved";
ExpiringSession session = save(touch(createSession(username)));
session.setAttribute(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, null);
save(session);
Map<String, ExpiringSession> nonExistingPrincipalSessions = doFindByPrincipalName(username);
assertThat(nonExistingPrincipalSessions).isNotNull();
assertThat(nonExistingPrincipalSessions.isEmpty()).isTrue();
}
@Test
public void saveAndReadSessionWithAttributes() {
ExpiringSession expectedSession = this.gemfireSessionRepository.createSession();
assertThat(expectedSession).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
((AbstractGemFireOperationsSessionRepository.GemFireSession) expectedSession).setPrincipalName("jblum");
List<String> expectedAttributeNames = Arrays.asList("booleanAttribute", "numericAttribute", "stringAttribute",
"personAttribute");
Person jonDoe = new Person("Jon", "Doe");
expectedSession.setAttribute(expectedAttributeNames.get(0), true);
expectedSession.setAttribute(expectedAttributeNames.get(1), Math.PI);
expectedSession.setAttribute(expectedAttributeNames.get(2), "test");
expectedSession.setAttribute(expectedAttributeNames.get(3), jonDoe);
this.gemfireSessionRepository.save(touch(expectedSession));
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
assertThat(savedSession).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(((AbstractGemFireOperationsSessionRepository.GemFireSession) savedSession).getPrincipalName())
.isEqualTo("jblum");
assertThat(savedSession.getAttributeNames().containsAll(expectedAttributeNames))
.as(String.format("Expected (%1$s); but was (%2$s)", expectedAttributeNames, savedSession.getAttributeNames()))
.isTrue();
assertThat(savedSession.<Boolean>getAttribute(expectedAttributeNames.get(0))).isTrue();
assertThat(savedSession.<Double>getAttribute(expectedAttributeNames.get(1))).isEqualTo(Math.PI);
assertThat(savedSession.<String>getAttribute(expectedAttributeNames.get(2))).isEqualTo("test");
assertThat(savedSession.<Person>getAttribute(expectedAttributeNames.get(3))).isEqualTo(jonDoe);
}
private String getSecurityName() {
return this.context.getAuthentication().getName();
}
private String getChangedSecurityName() {
return this.changedContext.getAuthentication().getName();
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireConfiguration {
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", GemFireOperationsSessionRepositoryIntegrationTests.class.getName());
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
}
public static class Person implements Comparable<Person>, PdxSerializable {
private String firstName;
private String lastName;
public Person() {
}
public Person(String firstName, String lastName) {
this.firstName = validate(firstName);
this.lastName = validate(lastName);
}
private String validate(String value) {
Assert.hasText(value, String.format("The String value (%1$s) must be specified!", value));
return value;
}
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
public String getName() {
return String.format("%1$s %2$s", getFirstName(), getLastName());
}
public void toData(PdxWriter pdxWriter) {
pdxWriter.writeString("firstName", getFirstName());
pdxWriter.writeString("lastName", getLastName());
}
public void fromData(final PdxReader pdxReader) {
this.firstName = pdxReader.readString("firstName");
this.lastName = pdxReader.readString("lastName");
}
@SuppressWarnings("all")
public int compareTo(final Person person) {
int compareValue = getLastName().compareTo(person.getLastName());
return (compareValue != 0 ? compareValue
: getFirstName().compareTo(person.getFirstName()));
}
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Person)) {
return false;
}
Person that = (Person) obj;
return ObjectUtils.nullSafeEquals(this.getFirstName(), that.getFirstName())
&& ObjectUtils.nullSafeEquals(this.getLastName(), that.getLastName());
}
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getFirstName());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getLastName());
return hashValue;
}
@Override
public String toString() {
return getName();
}
}
}

View File

@@ -1,344 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.client.ClientCache;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.SocketUtils;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to test the functionality of a GemFire cache client in a Spring Session application
* using a specifically named GemFire {@link org.apache.geode.cache.client.Pool} configured with
* the 'poolName' attribute in the Spring Session Data GemFire {@link EnableGemFireHttpSession} annotation.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.server.CacheServer
* @since 1.3.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MultiPoolClientServerGemFireOperationsSessionRepositoryIntegrationTests
.SpringSessionGemFireClientConfiguration.class)
@DirtiesContext
@WebAppConfiguration
public class MultiPoolClientServerGemFireOperationsSessionRepositoryIntegrationTests
extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final DateFormat TIMESTAMP = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
private static File processWorkingDirectory;
private static Process gemfireServer;
private static final String SPRING_SESSION_GEMFIRE_REGION_NAME = "TestMultiPoolClientServerSessions";
@Autowired
private SessionEventListener sessionEventListener;
@BeforeClass
public static void startGemFireServer() throws IOException {
final long t0 = System.currentTimeMillis();
final int port = SocketUtils.findAvailableTcpPort();
System.err.printf("Starting a GemFire Server on [%1$s] listening on port [%2$d]%n",
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port);
System.setProperty("spring.session.data.gemfire.port", String.valueOf(port));
String processWorkingDirectoryPathname = String.format("gemfire-multipool-client-server-tests-%1$s",
TIMESTAMP.format(new Date()));
processWorkingDirectory = createDirectory(processWorkingDirectoryPathname);
gemfireServer = run(SpringSessionGemFireServerConfiguration.class, processWorkingDirectory,
String.format("-Dspring.session.data.gemfire.port=%1$d", port));
assertThat(waitForCacheServerToStart(SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port)).isTrue();
System.err.printf("GemFire Server [startup time = %1$d ms]%n", System.currentTimeMillis() - t0);
}
@AfterClass
public static void stopGemFireServerAndDeleteArtifacts() {
if (gemfireServer != null) {
gemfireServer.destroyForcibly();
System.err.printf("GemFire Server [exit code = %1$d]%n",
waitForProcessToStop(gemfireServer, processWorkingDirectory));
}
if (Boolean.valueOf(System.getProperty("spring.session.data.gemfire.fork.clean", Boolean.TRUE.toString()))) {
FileSystemUtils.deleteRecursively(processWorkingDirectory);
}
assertThat(waitForClientCacheToClose(DEFAULT_WAIT_DURATION)).isTrue();
}
@Before
public void setup() {
assertThat(GemFireUtils.isClient(gemfireCache)).isTrue();
Region<Object, ExpiringSession> springSessionGemFireRegion =
gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertThat(springSessionGemFireRegion).isNotNull();
RegionAttributes<Object, ExpiringSession> springSessionGemFireRegionAttributes =
springSessionGemFireRegion.getAttributes();
assertThat(springSessionGemFireRegionAttributes).isNotNull();
assertThat(springSessionGemFireRegionAttributes.getDataPolicy()).isEqualTo(DataPolicy.EMPTY);
}
protected static ConnectionEndpoint newConnectionEndpoint(String host, int port) {
return new ConnectionEndpoint(host, port);
}
@Test
public void getExistingNonExpiredSessionBeforeAndAfterExpiration() {
ExpiringSession expectedSession = save(touch(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.waitForSessionEvent(500);
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isEqualTo(expectedSession);
assertThat(this.sessionEventListener.<SessionCreatedEvent>getSessionEvent()).isNull();
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
this.sessionEventListener.getSessionEvent();
sessionEvent = this.sessionEventListener.waitForSessionEvent(
TimeUnit.SECONDS.toMillis(MAX_INACTIVE_INTERVAL_IN_SECONDS + 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSession.getId());
ExpiringSession expiredSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(expiredSession).isNull();
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, poolName = "serverPool",
maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireClientConfiguration {
@Bean
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return SpringSessionGemFireClientConfiguration.class.getName();
}
@Bean
ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setPoolName("gemfirePool");
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
PoolFactoryBean gemfirePool() {
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
poolFactory.setKeepAlive(false);
poolFactory.setMinConnections(0);
poolFactory.setReadTimeout(500);
// deliberately set to a non-existing GemFire (Cache) Server
poolFactory.addServers(newConnectionEndpoint("localhost", 53135));
return poolFactory;
}
@Bean
PoolFactoryBean serverPool(@Value("${spring.session.data.gemfire.port:"
+ DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
PoolFactoryBean poolFactory = new PoolFactoryBean();
poolFactory.setFreeConnectionTimeout(5000); // 5 seconds
poolFactory.setKeepAlive(false);
poolFactory.setMaxConnections(SpringSessionGemFireServerConfiguration.MAX_CONNECTIONS);
poolFactory.setPingInterval(TimeUnit.SECONDS.toMillis(5));
poolFactory.setReadTimeout(2000); // 2 seconds
poolFactory.setRetryAttempts(1);
poolFactory.setSubscriptionEnabled(true);
poolFactory.setThreadLocalConnections(false);
poolFactory.addServers(newConnectionEndpoint(
SpringSessionGemFireServerConfiguration.SERVER_HOSTNAME, port));
return poolFactory;
}
@Bean
public AbstractGemFireIntegrationTests.SessionEventListener sessionEventListener() {
return new AbstractGemFireIntegrationTests.SessionEventListener();
}
// used for debugging purposes
@SuppressWarnings("resource")
public static void main(final String[] args) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(
SpringSessionGemFireClientConfiguration.class);
applicationContext.registerShutdownHook();
ClientCache clientCache = applicationContext.getBean(ClientCache.class);
for (InetSocketAddress server : clientCache.getCurrentServers()) {
System.err.printf("GemFire Server [host: %1$s, port: %2$d]%n",
server.getHostName(), server.getPort());
}
}
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS)
static class SpringSessionGemFireServerConfiguration {
static final int MAX_CONNECTIONS = 50;
static final String SERVER_HOSTNAME = "localhost";
@Bean
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", name());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-file", "server.log");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
String name() {
return SpringSessionGemFireServerConfiguration.class.getName();
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache,
@Value("${spring.session.data.gemfire.port:" + DEFAULT_GEMFIRE_SERVER_PORT + "}") int port) {
CacheServerFactoryBean cacheServerFactory = new CacheServerFactoryBean();
cacheServerFactory.setAutoStartup(true);
cacheServerFactory.setBindAddress(SERVER_HOSTNAME);
cacheServerFactory.setCache(gemfireCache);
cacheServerFactory.setMaxConnections(MAX_CONNECTIONS);
cacheServerFactory.setPort(port);
return cacheServerFactory;
}
@SuppressWarnings("resource")
public static void main(final String[] args) throws IOException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
SpringSessionGemFireServerConfiguration.class);
context.registerShutdownHook();
writeProcessControlFile(WORKING_DIRECTORY);
}
}
}

View File

@@ -1,254 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.util.Properties;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* The EnableGemFireHttpSessionEventsIntegrationTests class is a test suite of test cases
* testing the Session Event functionality and behavior of the
* GemFireOperationsSessionRepository and GemFire's configuration.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.session.events.SessionCreatedEvent
* @see org.springframework.session.events.SessionDeletedEvent
* @see org.springframework.session.events.SessionExpiredEvent
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Region
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
@WebAppConfiguration
public class EnableGemFireHttpSessionEventsIntegrationTests extends AbstractGemFireIntegrationTests {
private static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 1;
private static final String GEMFIRE_LOG_LEVEL = "warning";
private static final String SPRING_SESSION_GEMFIRE_REGION_NAME = "TestReplicatedSessions";
@Autowired
private SessionEventListener sessionEventListener;
@Before
public void setup() {
assertThat(GemFireUtils.isPeer(this.gemfireCache)).isTrue();
assertThat(this.gemfireSessionRepository).isNotNull();
assertThat(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(this.sessionEventListener).isNotNull();
Region<Object, ExpiringSession> sessionRegion = this.gemfireCache.getRegion(SPRING_SESSION_GEMFIRE_REGION_NAME);
assertRegion(sessionRegion, SPRING_SESSION_GEMFIRE_REGION_NAME, DataPolicy.REPLICATE);
assertEntryIdleTimeout(sessionRegion, ExpirationAction.INVALIDATE, MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
@After
public void tearDown() {
this.sessionEventListener.getSessionEvent();
}
@Test
public void sessionCreatedEvent() {
final long beforeOrAtCreationTime = System.currentTimeMillis();
ExpiringSession expectedSession = save(createSession());
AbstractSessionEvent sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
ExpiringSession createdSession = sessionEvent.getSession();
assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.getId()).isNotNull();
assertThat(createdSession.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(createdSession.getLastAccessedTime()).isEqualTo(createdSession.getCreationTime());
assertThat(createdSession.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(createdSession.isExpired()).isFalse();
}
@Test
public void getExistingNonExpiredSession() {
ExpiringSession expectedSession = save(touch(createSession()));
assertThat(expectedSession.isExpired()).isFalse();
// NOTE though unlikely, a possible race condition exists between save and get...
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
}
@Test
public void getExistingExpiredSession() {
ExpiringSession expectedSession = save(expire(createSession()));
AbstractSessionEvent sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
ExpiringSession createdSession = sessionEvent.getSession();
assertThat(createdSession).isEqualTo(expectedSession);
assertThat(createdSession.isExpired()).isTrue();
assertThat(this.gemfireSessionRepository.getSession(createdSession.getId())).isNull();
}
@Test
public void getNonExistingSession() {
assertThat(this.gemfireSessionRepository.getSession(UUID.randomUUID().toString())).isNull();
}
@Test
public void deleteExistingNonExpiredSession() {
ExpiringSession expectedSession = save(touch(createSession()));
ExpiringSession savedSession = this.gemfireSessionRepository.getSession(expectedSession.getId());
assertThat(savedSession).isEqualTo(expectedSession);
assertThat(savedSession.isExpired()).isFalse();
this.gemfireSessionRepository.delete(savedSession.getId());
AbstractSessionEvent sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.getSessionId()).isEqualTo(savedSession.getId());
ExpiringSession deletedSession = sessionEvent.getSession();
assertThat(deletedSession).isEqualTo(savedSession);
assertThat(this.gemfireSessionRepository.getSession(deletedSession.getId())).isNull();
}
@Test
public void deleteExistingExpiredSession() {
ExpiringSession expectedSession = save(createSession());
AbstractSessionEvent sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionCreatedEvent.class);
ExpiringSession createdSession = sessionEvent.getSession();
assertThat(createdSession).isEqualTo(expectedSession);
sessionEvent = this.sessionEventListener.waitForSessionEvent(
TimeUnit.SECONDS.toMillis(this.gemfireSessionRepository.getMaxInactiveIntervalInSeconds() + 1));
assertThat(sessionEvent).isInstanceOf(SessionExpiredEvent.class);
ExpiringSession expiredSession = sessionEvent.getSession();
assertThat(expiredSession).isEqualTo(createdSession);
assertThat(expiredSession.isExpired()).isTrue();
this.gemfireSessionRepository.delete(expectedSession.getId());
sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isNull();
assertThat(sessionEvent.getSessionId()).isEqualTo(expiredSession.getId());
assertThat(this.gemfireSessionRepository.<ExpiringSession>getSession(sessionEvent.getSessionId())).isNull();
}
@Test
public void deleteNonExistingSession() {
String expectedSessionId = UUID.randomUUID().toString();
assertThat(this.gemfireSessionRepository.<ExpiringSession>getSession(expectedSessionId)).isNull();
this.gemfireSessionRepository.delete(expectedSessionId);
AbstractSessionEvent sessionEvent = this.sessionEventListener.getSessionEvent();
assertThat(sessionEvent).isInstanceOf(SessionDeletedEvent.class);
assertThat(sessionEvent.<ExpiringSession>getSession()).isNull();
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
}
@EnableGemFireHttpSession(regionName = SPRING_SESSION_GEMFIRE_REGION_NAME, maxInactiveIntervalInSeconds = MAX_INACTIVE_INTERVAL_IN_SECONDS, serverRegionShortcut = RegionShortcut.REPLICATE)
static class SpringSessionGemFireConfiguration {
@Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name",
EnableGemFireHttpSessionEventsIntegrationTests.class.getName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", GEMFIRE_LOG_LEVEL);
return gemfireProperties;
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
@Bean
SessionEventListener sessionEventListener() {
return new SessionEventListener();
}
}
}

View File

@@ -1,148 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.util.Properties;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.QueryService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration test to test the configuration of Spring Session backed by GemFire
* using Java-based configuration meta-data.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
@WebAppConfiguration
public class GemFireHttpSessionJavaConfigurationTests extends AbstractGemFireIntegrationTests {
@Autowired
private Cache gemfireCache;
protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache,
String regionName, DataPolicy dataPolicy) {
assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue();
Region<K, V> region = gemfireCache.getRegion(regionName);
assertRegion(region, regionName, dataPolicy);
return region;
}
@Test
public void gemfireCacheConfigurationIsValid() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "JavaExample", DataPolicy.REPLICATE);
assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 900);
}
@Test
public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "JavaExample", DataPolicy.REPLICATE);
QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull();
Index principalNameIndex = queryService.getIndex(example, "principalNameIndex");
assertIndex(principalNameIndex, "principalName", example.getFullPath());
}
@Test
public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasNotCreated() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "JavaExample", DataPolicy.REPLICATE);
QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull();
Index sessionAttributesIndex = queryService.getIndex(example, "sessionAttributesIndex");
assertThat(sessionAttributesIndex).isNull();
}
@EnableGemFireHttpSession(indexableSessionAttributes = {}, maxInactiveIntervalInSeconds = 900,
regionName = "JavaExample", serverRegionShortcut = RegionShortcut.REPLICATE)
public static class GemFireConfiguration {
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", applicationName());
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", logLevel());
return gemfireProperties;
}
String applicationName() {
return GemFireHttpSessionJavaConfigurationTests.class.getName();
}
String logLevel() {
return "warning";
}
@Bean
CacheFactoryBean gemfireCache() {
CacheFactoryBean cacheFactory = new CacheFactoryBean();
cacheFactory.setClose(true);
cacheFactory.setProperties(gemfireProperties());
return cacheFactory;
}
}
}

View File

@@ -1,113 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.Index;
import org.apache.geode.cache.query.QueryService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Test suite of test cases testing the configuration of Spring Session backed by GemFire
* using XML configuration meta-data.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireIntegrationTests
* @see org.springframework.test.annotation.DirtiesContext
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner
* @see org.springframework.test.context.web.WebAppConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.Region
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@DirtiesContext
@WebAppConfiguration
public class GemFireHttpSessionXmlConfigurationTests extends AbstractGemFireIntegrationTests {
@Autowired
private Cache gemfireCache;
protected <K, V> Region<K, V> assertCacheAndRegion(Cache gemfireCache,
String regionName, DataPolicy dataPolicy) {
assertThat(GemFireUtils.isPeer(gemfireCache)).isTrue();
Region<K, V> region = gemfireCache.getRegion(regionName);
assertRegion(region, regionName, dataPolicy);
return region;
}
@Test
public void gemfireCacheConfigurationIsValid() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL);
assertEntryIdleTimeout(example, ExpirationAction.INVALIDATE, 3600);
}
@Test
public void verifyGemFireExampleCacheRegionPrincipalNameIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL);
QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull();
Index principalNameIndex = queryService.getIndex(example, "principalNameIndex");
assertIndex(principalNameIndex, "principalName", example.getFullPath());
}
@Test
public void verifyGemFireExampleCacheRegionSessionAttributesIndexWasCreatedSuccessfully() {
Region<Object, ExpiringSession> example =
assertCacheAndRegion(this.gemfireCache, "XmlExample", DataPolicy.NORMAL);
QueryService queryService = example.getRegionService().getQueryService();
assertThat(queryService).isNotNull();
Index sessionAttributesIndex = queryService.getIndex(example, "sessionAttributesIndex");
assertIndex(sessionAttributesIndex, "s.attributes['one', 'two', 'three']",
String.format("%1$s s", example.getFullPath()));
}
}

View File

@@ -1,956 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.DataSerializable;
import org.apache.geode.DataSerializer;
import org.apache.geode.Delta;
import org.apache.geode.Instantiator;
import org.apache.geode.InvalidDeltaException;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.Operation;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.util.CacheListenerAdapter;
import org.apache.geode.internal.concurrent.ConcurrentHashSet;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.data.gemfire.GemfireAccessor;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.Session;
import org.springframework.session.SessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.session.events.SessionCreatedEvent;
import org.springframework.session.events.SessionDeletedEvent;
import org.springframework.session.events.SessionDestroyedEvent;
import org.springframework.session.events.SessionExpiredEvent;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* {@link AbstractGemFireOperationsSessionRepository} is an abstract base class encapsulating functionality
* common to all implementations that support {@link SessionRepository} operations backed by GemFire.
*
* @author John Blum
* @since 1.1.0
* @see org.apache.geode.DataSerializable
* @see org.apache.geode.DataSerializer
* @see org.apache.geode.Delta
* @see org.apache.geode.Instantiator
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.util.CacheListenerAdapter
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.context.ApplicationEventPublisher
* @see org.springframework.context.ApplicationEventPublisherAware
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.Session
* @see org.springframework.session.SessionRepository
* @see org.springframework.session.FindByIndexNameSessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
*/
public abstract class AbstractGemFireOperationsSessionRepository extends CacheListenerAdapter<Object, ExpiringSession>
implements ApplicationEventPublisherAware, FindByIndexNameSessionRepository<ExpiringSession>, InitializingBean {
private int maxInactiveIntervalInSeconds = GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
private ApplicationEventPublisher applicationEventPublisher = new ApplicationEventPublisher() {
public void publishEvent(ApplicationEvent event) {
}
public void publishEvent(Object event) {
}
};
private final Set<Integer> cachedSessionIds = new ConcurrentHashSet<Integer>();
private final GemfireOperations template;
protected final Log logger = newLogger();
private String fullyQualifiedRegionName;
/**
* Constructs an instance of AbstractGemFireOperationsSessionRepository with a
* required GemfireOperations instance used to perform GemFire data access operations
* and interactions supporting the SessionRepository operations.
*
* @param template the GemfireOperations instance used to interact with GemFire.
* @see org.springframework.data.gemfire.GemfireOperations
*/
public AbstractGemFireOperationsSessionRepository(GemfireOperations template) {
Assert.notNull(template, "GemfireOperations must not be null");
this.template = template;
}
/**
* Used for testing purposes only to override the Log implementation with a mock.
*
* @return an instance of Log constructed from Apache commons-logging LogFactory.
* @see org.apache.commons.logging.LogFactory#getLog(Class)
*/
Log newLogger() {
return LogFactory.getLog(getClass());
}
/**
* Sets the ApplicationEventPublisher used to publish Session events corresponding to
* GemFire cache events.
*
* @param applicationEventPublisher the Spring ApplicationEventPublisher used to
* publish Session-based events.
* @see org.springframework.context.ApplicationEventPublisher
*/
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
Assert.notNull(applicationEventPublisher, "ApplicationEventPublisher must not be null");
this.applicationEventPublisher = applicationEventPublisher;
}
/**
* Gets the ApplicationEventPublisher used to publish Session events corresponding to
* GemFire cache events.
*
* @return the Spring ApplicationEventPublisher used to publish Session-based events.
* @see org.springframework.context.ApplicationEventPublisher
*/
protected ApplicationEventPublisher getApplicationEventPublisher() {
return this.applicationEventPublisher;
}
/**
* Gets the fully-qualified name of the GemFire cache {@link Region} used to store and
* manage Session data.
*
* @return a String indicating the fully qualified name of the GemFire cache
* {@link Region} used to store and manage Session data.
*/
protected String getFullyQualifiedRegionName() {
return this.fullyQualifiedRegionName;
}
/**
* Sets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
*
* @param maxInactiveIntervalInSeconds an integer value specifying the maximum
* interval in seconds that a Session can remain inactive before it is considered
* expired.
*/
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
/**
* Gets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
*
* @return an integer value specifying the maximum interval in seconds that a Session
* can remain inactive before it is considered expired.
*/
public int getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds;
}
/**
* Gets a reference to the GemfireOperations (template) used to perform data access
* operations and other interactions on the GemFire cache {@link Region} backing this
* SessionRepository.
*
* @return a reference to the GemfireOperations used to interact with GemFire.
* @see org.springframework.data.gemfire.GemfireOperations
*/
public GemfireOperations getTemplate() {
return this.template;
}
/**
* Callback method during Spring bean initialization that will capture the fully-qualified name
* of the GemFire cache {@link Region} used to manage Session state and register this SessionRepository
* as a GemFire {@link org.apache.geode.cache.CacheListener}.
*
* Additionally, this method registers GemFire {@link Instantiator}s for the {@link GemFireSession}
* and {@link GemFireSessionAttributes} types to optimize GemFire's instantiation logic on deserialization
* using the data serialization framework when accessing the {@link Session}'s state stored in GemFire.
*
* @throws Exception if an error occurs during the initialization process.
*/
public void afterPropertiesSet() throws Exception {
GemfireOperations template = getTemplate();
Assert.isInstanceOf(GemfireAccessor.class, template);
Region<Object, ExpiringSession> region = ((GemfireAccessor) template).getRegion();
this.fullyQualifiedRegionName = region.getFullPath();
region.getAttributesMutator().addCacheListener(this);
Instantiator.register(GemFireSessionInstantiator.create());
Instantiator.register(GemFireSessionAttributesInstantiator.create());
}
/* (non-Javadoc) */
boolean isCreate(EntryEvent<?, ?> event) {
return (isCreate(event.getOperation()) && isNotUpdate(event) && isExpiringSessionOrNull(event.getNewValue()));
}
/* (non-Javadoc) */
private boolean isCreate(Operation operation) {
return (operation.isCreate() && !Operation.LOCAL_LOAD_CREATE.equals(operation));
}
/**
* Used to determine whether the developer is storing (HTTP) Sessions with other, arbitrary application
* domain objects in the same GemFire cache {@link Region}; crazier things have happened!
*
* @param obj {@link Object} to evaluate.
* @return a boolean value indicating whether the {@link Object} from the entry event is indeed
* a {@link ExpiringSession}.
* @see org.springframework.session.ExpiringSession
*/
private boolean isExpiringSessionOrNull(Object obj) {
return (obj instanceof ExpiringSession || obj == null);
}
/* (non-Javadoc) */
private boolean isNotUpdate(EntryEvent event) {
return (isNotProxyRegion() || !this.cachedSessionIds.contains(ObjectUtils.nullSafeHashCode(event.getKey())));
}
/* (non-Javadoc) */
private boolean isNotProxyRegion() {
return !isProxyRegion();
}
/* (non-Javadoc) */
private boolean isProxyRegion() {
return GemFireUtils.isProxy(((GemfireAccessor) getTemplate()).getRegion());
}
boolean forget(Object sessionId) {
return this.cachedSessionIds.remove(ObjectUtils.nullSafeHashCode(sessionId));
}
boolean remember(Object sessionId) {
return (isProxyRegion() && this.cachedSessionIds.add(ObjectUtils.nullSafeHashCode(sessionId)));
}
/* (non-Javadoc) */
ExpiringSession toExpiringSession(Object obj) {
return (obj instanceof ExpiringSession ? (ExpiringSession) obj : null);
}
/**
* Callback method triggered when an entry is created in the GemFire cache {@link Region}.
*
* @param event {@link EntryEvent} containing the details of the cache {@link Region} operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleCreated(String, ExpiringSession)
*/
@Override
public void afterCreate(EntryEvent<Object, ExpiringSession> event) {
if (isCreate(event)) {
handleCreated(event.getKey().toString(), toExpiringSession(event.getNewValue()));
}
}
/**
* Callback method triggered when an entry is destroyed in the GemFire cache
* {@link Region}.
*
* @param event an EntryEvent containing the details of the cache operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleDestroyed(String, ExpiringSession)
*/
@Override
public void afterDestroy(EntryEvent<Object, ExpiringSession> event) {
handleDestroyed(event.getKey().toString(), toExpiringSession(event.getOldValue()));
}
/**
* Callback method triggered when an entry is invalidated in the GemFire cache
* {@link Region}.
*
* @param event an EntryEvent containing the details of the cache operation.
* @see org.apache.geode.cache.EntryEvent
* @see #handleExpired(String, ExpiringSession)
*/
@Override
public void afterInvalidate(EntryEvent<Object, ExpiringSession> event) {
handleExpired(event.getKey().toString(), toExpiringSession(event.getOldValue()));
}
/**
* Deletes the given {@link Session} from GemFire.
*
* @param session {@link Session} to delete.
* @return {@literal null}.
* @see org.springframework.session.Session
* @see #delete(String)
*/
protected ExpiringSession delete(Session session) {
delete(session.getId());
return null;
}
/**
* Causes Session created events to be published to the Spring application context.
*
* @param sessionId a String indicating the ID of the Session.
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionCreatedEvent
* @see org.springframework.session.ExpiringSession
* @see #publishEvent(ApplicationEvent)
*/
protected void handleCreated(String sessionId, ExpiringSession session) {
remember(sessionId);
publishEvent(session != null ? new SessionCreatedEvent(this, session)
: new SessionCreatedEvent(this, sessionId));
}
/**
* Causes Session deleted events to be published to the Spring application context.
*
* @param sessionId a String indicating the ID of the Session.
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionDeletedEvent
* @see org.springframework.session.ExpiringSession
* @see #publishEvent(ApplicationEvent)
*/
protected void handleDeleted(String sessionId, ExpiringSession session) {
forget(sessionId);
publishEvent(session != null ? new SessionDeletedEvent(this, session)
: new SessionDeletedEvent(this, sessionId));
}
/**
* Causes Session destroyed events to be published to the Spring application context.
*
* @param sessionId a String indicating the ID of the Session.
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionDestroyedEvent
* @see org.springframework.session.ExpiringSession
* @see #publishEvent(ApplicationEvent)
*/
protected void handleDestroyed(String sessionId, ExpiringSession session) {
forget(sessionId);
publishEvent(session != null ? new SessionDestroyedEvent(this, session)
: new SessionDestroyedEvent(this, sessionId));
}
/**
* Causes Session expired events to be published to the Spring application context.
*
* @param sessionId a String indicating the ID of the Session.
* @param session a reference to the Session triggering the event.
* @see org.springframework.session.events.SessionExpiredEvent
* @see org.springframework.session.ExpiringSession
* @see #publishEvent(ApplicationEvent)
*/
protected void handleExpired(String sessionId, ExpiringSession session) {
forget(sessionId);
publishEvent(session != null ? new SessionExpiredEvent(this, session)
: new SessionExpiredEvent(this, sessionId));
}
/**
* Publishes the specified ApplicationEvent to the Spring application context.
*
* @param event the ApplicationEvent to publish.
* @see org.springframework.context.ApplicationEventPublisher#publishEvent(ApplicationEvent)
* @see org.springframework.context.ApplicationEvent
*/
protected void publishEvent(ApplicationEvent event) {
try {
getApplicationEventPublisher().publishEvent(event);
}
catch (Throwable t) {
this.logger.error(String.format("Error occurred publishing event [%s]", event), t);
}
}
/**
* Updates the {@link ExpiringSession#setLastAccessedTime(long)} property of the {@link ExpiringSession}.
*
* @param <T> {@link Class} sub-type of the {@link ExpiringSession}.
* @param expiringSession {@link ExpiringSession} to touch.
* @return the {@link ExpiringSession}.
* @see org.springframework.session.ExpiringSession#setLastAccessedTime(long)
*/
protected <T extends ExpiringSession> T touch(T expiringSession) {
expiringSession.setLastAccessedTime(System.currentTimeMillis());
return expiringSession;
}
/**
* GemFireSession is a GemFire representation model of a Spring {@link ExpiringSession}
* that stores and manages Session state information in GemFire. This class implements
* GemFire's {@link DataSerializable} interface to better handle replication of Session
* state information across the GemFire cluster.
*/
@SuppressWarnings("serial")
public static class GemFireSession implements Comparable<ExpiringSession>,
DataSerializable, Delta, ExpiringSession {
protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true;
protected static final DateFormat TO_STRING_DATE_FORMAT = new SimpleDateFormat("YYYY-MM-dd-HH-mm-ss");
protected static final String SPRING_SECURITY_CONTEXT = "SPRING_SECURITY_CONTEXT";
private transient boolean delta = false;
private int maxInactiveIntervalInSeconds;
private long creationTime;
private long lastAccessedTime;
private transient final GemFireSessionAttributes sessionAttributes = new GemFireSessionAttributes(this);
private transient final SpelExpressionParser parser = new SpelExpressionParser();
private String id;
/* (non-Javadoc) */
protected GemFireSession() {
this(UUID.randomUUID().toString());
}
/* (non-Javadoc) */
protected GemFireSession(String id) {
this.id = validateId(id);
this.creationTime = System.currentTimeMillis();
this.lastAccessedTime = this.creationTime;
}
/* (non-Javadoc) */
protected GemFireSession(ExpiringSession session) {
Assert.notNull(session, "The ExpiringSession to copy cannot be null");
this.id = session.getId();
this.creationTime = session.getCreationTime();
this.lastAccessedTime = session.getLastAccessedTime();
this.maxInactiveIntervalInSeconds = session.getMaxInactiveIntervalInSeconds();
this.sessionAttributes.from(session);
}
/* (non-Javadoc) */
public static GemFireSession create(int maxInactiveIntervalInSeconds) {
GemFireSession session = new GemFireSession();
session.setMaxInactiveIntervalInSeconds(maxInactiveIntervalInSeconds);
return session;
}
public static GemFireSession copy(ExpiringSession session) {
return new GemFireSession(session);
}
/* (non-Javadoc) */
public static GemFireSession from(ExpiringSession session) {
return (session instanceof GemFireSession ? (GemFireSession) session : copy(session));
}
/* (non-Javadoc) */
private String validateId(String id) {
Assert.hasText(id, "ID must be specified");
return id;
}
/* (non-Javadoc) */
protected boolean allowJavaSerialization() {
return DEFAULT_ALLOW_JAVA_SERIALIZATION;
}
/* (non-Javadoc) */
public synchronized String getId() {
return this.id;
}
/* (non-Javadoc) */
public synchronized long getCreationTime() {
return this.creationTime;
}
/* (non-Javadoc) */
public void setAttribute(String attributeName, Object attributeValue) {
this.sessionAttributes.setAttribute(attributeName, attributeValue);
}
/* (non-Javadoc) */
public void removeAttribute(String attributeName) {
this.sessionAttributes.removeAttribute(attributeName);
}
/* (non-Javadoc) */
public <T> T getAttribute(String attributeName) {
return this.sessionAttributes.getAttribute(attributeName);
}
/* (non-Javadoc) */
public Set<String> getAttributeNames() {
return this.sessionAttributes.getAttributeNames();
}
/* (non-Javadoc) */
public GemFireSessionAttributes getAttributes() {
return this.sessionAttributes;
}
/* (non-Javadoc) */
public synchronized boolean isExpired() {
long lastAccessedTime = getLastAccessedTime();
long maxInactiveIntervalInSeconds = getMaxInactiveIntervalInSeconds();
return (maxInactiveIntervalInSeconds >= 0
&& (idleTimeout(maxInactiveIntervalInSeconds) >= lastAccessedTime));
}
/* (non-Javadoc) */
private long idleTimeout(long maxInactiveIntervalInSeconds) {
return (System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(maxInactiveIntervalInSeconds));
}
/* (non-Javadoc) */
public synchronized void setLastAccessedTime(long lastAccessedTime) {
this.delta |= (this.lastAccessedTime != lastAccessedTime);
this.lastAccessedTime = lastAccessedTime;
}
/* (non-Javadoc) */
public synchronized long getLastAccessedTime() {
return this.lastAccessedTime;
}
/* (non-Javadoc) */
public synchronized void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.delta |= (this.maxInactiveIntervalInSeconds != maxInactiveIntervalInSeconds);
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
/* (non-Javadoc) */
public synchronized int getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds;
}
/* (non-Javadoc) */
public synchronized void setPrincipalName(String principalName) {
setAttribute(PRINCIPAL_NAME_INDEX_NAME, principalName);
}
/* (non-Javadoc) */
public synchronized String getPrincipalName() {
String principalName = getAttribute(PRINCIPAL_NAME_INDEX_NAME);
if (principalName == null) {
Object authentication = getAttribute(SPRING_SECURITY_CONTEXT);
if (authentication != null) {
Expression expression = this.parser.parseExpression("authentication?.name");
principalName = expression.getValue(authentication, String.class);
}
}
return principalName;
}
/* (non-Javadoc) */
public synchronized void toData(DataOutput out) throws IOException {
out.writeUTF(getId());
out.writeLong(getCreationTime());
out.writeLong(getLastAccessedTime());
out.writeInt(getMaxInactiveIntervalInSeconds());
String principalName = getPrincipalName();
int length = (StringUtils.hasText(principalName) ? principalName.length() : 0);
out.writeInt(length);
if (length > 0) {
out.writeUTF(principalName);
}
writeObject(this.sessionAttributes, out);
this.delta = false;
}
/* (non-Javadoc) */
void writeObject(Object obj, DataOutput out) throws IOException {
DataSerializer.writeObject(obj, out, allowJavaSerialization());
}
/* (non-Javadoc) */
public synchronized void fromData(DataInput in) throws ClassNotFoundException, IOException {
this.id = in.readUTF();
this.creationTime = in.readLong();
setLastAccessedTime(in.readLong());
setMaxInactiveIntervalInSeconds(in.readInt());
int principalNameLength = in.readInt();
if (principalNameLength > 0) {
setPrincipalName(in.readUTF());
}
this.sessionAttributes.from(this.<GemFireSessionAttributes>readObject(in));
this.delta = false;
}
/* (non-Javadoc) */
<T> T readObject(DataInput in) throws ClassNotFoundException, IOException {
return DataSerializer.readObject(in);
}
/* (non-Javadoc) */
public synchronized boolean hasDelta() {
return (this.delta || this.sessionAttributes.hasDelta());
}
/* (non-Javadoc) */
public synchronized void toDelta(DataOutput out) throws IOException {
out.writeLong(getLastAccessedTime());
out.writeInt(getMaxInactiveIntervalInSeconds());
this.sessionAttributes.toDelta(out);
this.delta = false;
}
/* (non-Javadoc) */
public synchronized void fromDelta(DataInput in) throws IOException {
setLastAccessedTime(in.readLong());
setMaxInactiveIntervalInSeconds(in.readInt());
this.sessionAttributes.fromDelta(in);
this.delta = false;
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public int compareTo(ExpiringSession session) {
return (Long.valueOf(getCreationTime()).compareTo(session.getCreationTime()));
}
/* (non-Javadoc) */
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Session)) {
return false;
}
Session that = (Session) obj;
return this.getId().equals(that.getId());
}
/* (non-Javadoc) */
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + getId().hashCode();
return hashValue;
}
/* (non-Javadoc) */
@Override
public synchronized String toString() {
return String.format("{ @type = %1$s, id = %2$s, creationTime = %3$s, lastAccessedTime = %4$s"
+ ", maxInactiveIntervalInSeconds = %5$s, principalName = %6$s }",
getClass().getName(), getId(), toString(getCreationTime()), toString(getLastAccessedTime()),
getMaxInactiveIntervalInSeconds(), getPrincipalName());
}
/* (non-Javadoc) */
private String toString(long timestamp) {
return TO_STRING_DATE_FORMAT.format(new Date(timestamp));
}
}
/**
* GemFireSessionInstantiator is a GemFire {@link Instantiator} use to instantiate instances
* of the {@link GemFireSession} object used in GemFire's data serialization framework when
* persisting Session state in GemFire.
*/
public static class GemFireSessionInstantiator extends Instantiator {
public static GemFireSessionInstantiator create() {
return new GemFireSessionInstantiator(GemFireSession.class, 800813552);
}
public GemFireSessionInstantiator(Class<? extends DataSerializable> type, int id) {
super(type, id);
}
@Override
public DataSerializable newInstance() {
return new GemFireSession();
}
}
/**
* The GemFireSessionAttributes class is a container for Session attributes implementing
* both the {@link DataSerializable} and {@link Delta} GemFire interfaces for efficient
* storage and distribution (replication) in GemFire. Additionally, GemFireSessionAttributes
* extends {@link AbstractMap} providing {@link Map}-like behavior since attributes of a Session
* are effectively a name to value mapping.
*
* @see java.util.AbstractMap
* @see org.apache.geode.DataSerializable
* @see org.apache.geode.DataSerializer
* @see org.apache.geode.Delta
*/
@SuppressWarnings("serial")
public static class GemFireSessionAttributes extends AbstractMap<String, Object>
implements DataSerializable, Delta {
protected static final boolean DEFAULT_ALLOW_JAVA_SERIALIZATION = true;
private transient final Map<String, Object> sessionAttributes = new HashMap<String, Object>();
private transient final Map<String, Object> sessionAttributeDeltas = new HashMap<String, Object>();
private transient final Object lock;
/* (non-Javadoc) */
protected GemFireSessionAttributes() {
this.lock = this;
}
/* (non-Javadoc) */
protected GemFireSessionAttributes(Object lock) {
this.lock = (lock != null ? lock : this);
}
/* (non-Javadoc) */
public void setAttribute(String attributeName, Object attributeValue) {
synchronized (this.lock) {
if (attributeValue != null) {
if (!attributeValue.equals(this.sessionAttributes.put(attributeName, attributeValue))) {
this.sessionAttributeDeltas.put(attributeName, attributeValue);
}
}
else {
removeAttribute(attributeName);
}
}
}
/* (non-Javadoc) */
public void removeAttribute(String attributeName) {
synchronized (this.lock) {
if (this.sessionAttributes.remove(attributeName) != null) {
this.sessionAttributeDeltas.put(attributeName, null);
}
}
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
public <T> T getAttribute(String attributeName) {
synchronized (this.lock) {
return (T) this.sessionAttributes.get(attributeName);
}
}
/* (non-Javadoc) */
public Set<String> getAttributeNames() {
synchronized (this.lock) {
return Collections.unmodifiableSet(new HashSet<String>(this.sessionAttributes.keySet()));
}
}
/* (non-Javadoc) */
protected boolean allowJavaSerialization() {
return DEFAULT_ALLOW_JAVA_SERIALIZATION;
}
/* (non-Javadoc); NOTE: entrySet implementation is not Thread-safe. */
@Override
@SuppressWarnings("all")
public Set<Entry<String, Object>> entrySet() {
return new AbstractSet<Entry<String, Object>>() {
@Override
public Iterator<Entry<String, Object>> iterator() {
return Collections.unmodifiableMap(GemFireSessionAttributes.this.sessionAttributes)
.entrySet().iterator();
}
@Override
public int size() {
return GemFireSessionAttributes.this.sessionAttributes.size();
}
};
}
/* (non-Javadoc) */
public void from(Session session) {
synchronized (this.lock) {
for (String attributeName : session.getAttributeNames()) {
setAttribute(attributeName, session.getAttribute(attributeName));
}
}
}
/* (non-Javadoc) */
public void from(GemFireSessionAttributes sessionAttributes) {
synchronized (this.lock) {
for (String attributeName : sessionAttributes.getAttributeNames()) {
setAttribute(attributeName, sessionAttributes.getAttribute(attributeName));
}
}
}
/* (non-Javadoc) */
public void toData(DataOutput out) throws IOException {
synchronized (this.lock) {
Set<String> attributeNames = getAttributeNames();
out.writeInt(attributeNames.size());
for (String attributeName : attributeNames) {
out.writeUTF(attributeName);
writeObject(getAttribute(attributeName), out);
}
}
}
/* (non-Javadoc) */
void writeObject(Object obj, DataOutput out) throws IOException {
DataSerializer.writeObject(obj, out, allowJavaSerialization());
}
/* (non-Javadoc) */
public void fromData(DataInput in) throws IOException, ClassNotFoundException {
synchronized (this.lock) {
for (int count = in.readInt(); count > 0; count--) {
setAttribute(in.readUTF(), readObject(in));
}
this.sessionAttributeDeltas.clear();
}
}
/* (non-Javadoc) */
<T> T readObject(DataInput in) throws ClassNotFoundException, IOException {
return DataSerializer.readObject(in);
}
/* (non-Javadoc) */
public boolean hasDelta() {
synchronized (this.lock) {
return !this.sessionAttributeDeltas.isEmpty();
}
}
/* (non-Javadoc) */
public void toDelta(DataOutput out) throws IOException {
synchronized (this.lock) {
out.writeInt(this.sessionAttributeDeltas.size());
for (Map.Entry<String, Object> entry : this.sessionAttributeDeltas.entrySet()) {
out.writeUTF(entry.getKey());
writeObject(entry.getValue(), out);
}
this.sessionAttributeDeltas.clear();
}
}
/* (non-Javadoc) */
public void fromDelta(DataInput in) throws InvalidDeltaException, IOException {
synchronized (this.lock) {
try {
int count = in.readInt();
Map<String, Object> deltas = new HashMap<String, Object>(count);
while (count-- > 0) {
deltas.put(in.readUTF(), readObject(in));
}
for (Map.Entry<String, Object> entry : deltas.entrySet()) {
setAttribute(entry.getKey(), entry.getValue());
this.sessionAttributeDeltas.remove(entry.getKey());
}
}
catch (ClassNotFoundException e) {
throw new InvalidDeltaException("class type in data not found", e);
}
}
}
@Override
public String toString() {
return this.sessionAttributes.toString();
}
}
/**
* GemFireSessionAttributesInstantiator is a GemFire {@link Instantiator} use to instantiate instances
* of the {@link GemFireSessionAttributes} object used in GemFire's data serialization framework when
* persisting Session attributes state in GemFire.
*/
public static class GemFireSessionAttributesInstantiator extends Instantiator {
public static GemFireSessionAttributesInstantiator create() {
return new GemFireSessionAttributesInstantiator(GemFireSessionAttributes.class, 800828008);
}
public GemFireSessionAttributesInstantiator(Class<? extends DataSerializable> type, int id) {
super(type, id);
}
@Override
public DataSerializable newInstance() {
return new GemFireSessionAttributes();
}
}
}

View File

@@ -1,155 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.util.HashMap;
import java.util.Map;
import org.apache.geode.cache.query.SelectResults;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.session.ExpiringSession;
import org.springframework.session.SessionRepository;
/**
* The {@link GemFireOperationsSessionRepository} class is a Spring {@link SessionRepository} implementation
* that interfaces with and uses GemFire to back and store Spring Sessions.
*
* @author John Blum
* @since 1.1.0
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository
*/
public class GemFireOperationsSessionRepository extends AbstractGemFireOperationsSessionRepository {
// GemFire OQL query used to lookup Sessions by arbitrary attributes.
protected static final String FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY = "SELECT s FROM %1$s s WHERE s.attributes['%2$s'] = $1";
// GemFire OQL query used to look up Sessions by principal name.
protected static final String FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY = "SELECT s FROM %1$s s WHERE s.principalName = $1";
/**
* Constructs an instance of GemFireOperationsSessionRepository initialized with the
* required GemfireOperations object used to perform data access operations to manage
* Session state.
*
* @param template the GemfireOperations object used to access and manage Session
* state in GemFire.
* @see org.springframework.data.gemfire.GemfireOperations
*/
public GemFireOperationsSessionRepository(GemfireOperations template) {
super(template);
}
/**
* Looks up all available Sessions with the particular attribute indexed by name
* having the given value.
*
* @param indexName name of the indexed Session attribute. (e.g.
* {@link org.springframework.session.FindByIndexNameSessionRepository#PRINCIPAL_NAME_INDEX_NAME}
* ).
* @param indexValue value of the indexed Session attribute to search on (e.g.
* username).
* @return a mapping of Session ID to Session instances.
* @see org.springframework.session.ExpiringSession
* @see java.util.Map
* @see #prepareQuery(String)
*/
public Map<String, ExpiringSession> findByIndexNameAndIndexValue(String indexName, String indexValue) {
SelectResults<ExpiringSession> results = getTemplate().find(prepareQuery(indexName), indexValue);
Map<String, ExpiringSession> sessions = new HashMap<String, ExpiringSession>(results.size());
for (ExpiringSession session : results.asList()) {
sessions.put(session.getId(), session);
}
return sessions;
}
/**
* Prepares the appropriate GemFire OQL query based on the indexed Session attribute
* name.
*
* @param indexName a String indicating the name of the indexed Session attribute.
* @return an appropriate GemFire OQL statement for querying on a particular indexed
* Session attribute.
*/
protected String prepareQuery(String indexName) {
return (PRINCIPAL_NAME_INDEX_NAME.equals(indexName)
? String.format(FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY, getFullyQualifiedRegionName())
: String.format(FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY, getFullyQualifiedRegionName(), indexName));
}
/**
* Constructs a new {@link ExpiringSession} instance backed by GemFire.
*
* @return an instance of {@link ExpiringSession} backed by GemFire.
* @see AbstractGemFireOperationsSessionRepository.GemFireSession#create(int)
* @see org.springframework.session.ExpiringSession
* @see #getMaxInactiveIntervalInSeconds()
*/
public ExpiringSession createSession() {
return GemFireSession.create(getMaxInactiveIntervalInSeconds());
}
/**
* Gets a copy of an existing, non-expired {@link ExpiringSession} by ID. If the
* Session is expired, then it is deleted.
*
* @param sessionId a String indicating the ID of the Session to get.
* @return an existing {@link ExpiringSession} by ID or null if not Session exists.
* @see AbstractGemFireOperationsSessionRepository.GemFireSession#from(ExpiringSession)
* @see org.springframework.session.ExpiringSession
* @see #delete(String)
*/
public ExpiringSession getSession(String sessionId) {
ExpiringSession storedSession = getTemplate().get(sessionId);
if (storedSession != null) {
storedSession = storedSession.isExpired()
? delete(storedSession)
: touch(GemFireSession.from(storedSession));
}
return storedSession;
}
/**
* Saves the specified {@link ExpiringSession} to GemFire.
*
* @param session the {@link ExpiringSession} to save.
* @see org.springframework.data.gemfire.GemfireOperations#put(Object, Object)
* @see org.springframework.session.ExpiringSession
*/
public void save(ExpiringSession session) {
getTemplate().put(session.getId(), GemFireSession.from(session));
}
/**
* Deletes (removes) any existing {@link ExpiringSession} from GemFire. This operation
* also results in a SessionDeletedEvent.
*
* @param sessionId a String indicating the ID of the Session to remove from GemFire.
* @see org.springframework.data.gemfire.GemfireOperations#remove(Object)
* @see #handleDeleted(String, ExpiringSession)
*/
public void delete(String sessionId) {
handleDeleted(sessionId, getTemplate().<Object, ExpiringSession>remove(sessionId));
}
}

View File

@@ -1,170 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Add this annotation to a Spring {@code @Configuration} class to expose the SessionRepositoryFilter
* as a bean named "springSessionRepositoryFilter" and backed by Pivotal GemFire or Apache Geode.
*
* In order to leverage the annotation, a single Pivotal GemFire/Apache Geode
* {@link org.apache.geode.cache.Cache}
* or {@link org.apache.geode.cache.client.ClientCache} instance must be provided.
*
* For example:
*
* <pre>
* <code>
* {@literal @Configuration}
* {@literal @EnableGemFireHttpSession}
* public class GemFirePeerCacheHttpSessionConfiguration {
*
* {@literal @Bean}
* public Properties gemfireProperties() {
* Properties gemfireProperties = new Properties();
* gemfireProperties.setProperty("name", "ExamplePeer");
* gemfireProperties.setProperty("mcast-port", "0");
* gemfireProperties.setProperty("log-level", "warning");
* return gemfireProperties;
* }
*
* {@literal @Bean}
* public CacheFactoryBean gemfireCache() throws Exception {
* CacheFactoryBean cache = new CacheFactoryBean();
* cache.setProperties(gemfireProperties());
* return cache;
* }
* }
* </code> </pre>
*
* Alternatively, Spring Session can be configured to use Pivotal GemFire (Apache Geode) as a client
* using a dedicated GemFire Server cluster and a {@link org.apache.geode.cache.client.ClientCache}.
*
* For example:
*
* <code>
* {@literal @Configuration}
* {@literal @EnableGemFireHttpSession}
* public class GemFireClientCacheHttpSessionConfiguration {
*
* {@literal @Bean}
* public Properties gemfireProperties() {
* Properties gemfireProperties = new Properties();
* gemfireProperties.setProperty("name", "ExampleClient");
* gemfireProperties.setProperty("log-level", "warning");
* return gemfireProperties;
* }
*
* {@literal @Bean}
* public ClientCacheFactoryBean gemfireCache() throws Exception {
* ClientCacheFactoryBean clientCache = new ClientCacheFactoryBean();
* clientCache.setClose(true)
* clientCache.setProperties(gemfireProperties());
* return clientCache;
* }
*
* {@literal @Bean}
* public PoolFactoryBean gemfirePool() {
* PoolFactoryBean pool = new PoolFactoryBean();
* pool.addServer(new ConnectionEndpoint("serverHost", 40404);
* return pool;
* }
* }
* </code>
*
* More advanced configurations can extend {@link GemFireHttpSessionConfiguration} instead.
*
* @author John Blum
* @see org.springframework.session.config.annotation.web.http.EnableSpringHttpSession
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @since 1.1.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Configuration
@Import(GemFireHttpSessionConfiguration.class)
public @interface EnableGemFireHttpSession {
/**
* Defines the GemFire ClientCache Region DataPolicy.
*
* @return a ClientRegionShortcut used to specify and configure the ClientCache Region
* DataPolicy.
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY;
/**
* Identifies the Session attributes by name that should be indexed for query
* operations. For instance, find all Sessions in GemFire having attribute A defined
* with value X.
*
* @return an array of Strings identifying the names of Session attributes to index.
*/
String[] indexableSessionAttributes() default {};
/**
* Defines the maximum interval in seconds that a Session can remain inactive before
* it is considered expired. Defaults to 1800 seconds, or 30 minutes.
*
* @return an integer value defining the maximum inactive interval in seconds for
* declaring a Session expired.
*/
int maxInactiveIntervalInSeconds() default 1800;
/**
* Specifies the name of the specific GemFire {@link org.apache.geode.cache.client.Pool} used
* by the Spring Session Data GemFire client Region ('ClusteredSpringSessions') when performing
* cache operations. This is attribute is only used in the client/server topology.
*
* @return the name of the GemFire {@link org.apache.geode.cache.client.Pool} to be used
* by the client Region used to manage (HTTP) Sessions.
* @see org.springframework.data.gemfire.config.xml.GemfireConstants#DEFAULT_GEMFIRE_POOL_NAME
*/
String poolName() default GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME;
/**
* Defines the name of the GemFire (Client)Cache Region used to store Sessions.
*
* @return a String specifying the name of the GemFire (Client)Cache Region used to
* store Sessions.
* @see org.apache.geode.cache.Region#getName()
*/
String regionName() default "ClusteredSpringSessions";
/**
* Defines the GemFire, Peer Cache Region DataPolicy.
*
* @return a RegionShortcut used to specify and configure the Peer Cache Region
* DataPolicy.
* @see org.apache.geode.cache.RegionShortcut
*/
RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION;
}

View File

@@ -1,487 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.Pool;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.IndexType;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.session.ExpiringSession;
import org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration;
import org.springframework.session.data.gemfire.AbstractGemFireOperationsSessionRepository.GemFireSession;
import org.springframework.session.data.gemfire.GemFireOperationsSessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean;
import org.springframework.session.data.gemfire.config.annotation.web.http.support.SessionAttributesIndexFactoryBean;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.StringUtils;
/**
* The {@link GemFireHttpSessionConfiguration} class is a Spring {@link Configuration @Configuration} class
* used to configure and initialize Pivotal GemFire (or Apache Geode) as a clustered, replicated
* {@link javax.servlet.http.HttpSession} provider implementation in Spring {@link ExpiringSession}.
*
* @author John Blum
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.data.gemfire.GemfireTemplate
* @see org.springframework.session.ExpiringSession
* @see org.springframework.session.config.annotation.web.http.SpringHttpSessionConfiguration
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.EnableGemFireHttpSession
* @since 1.1.0
*/
@Configuration
public class GemFireHttpSessionConfiguration extends SpringHttpSessionConfiguration
implements BeanClassLoaderAware, ImportAware {
/**
* The default maximum interval in seconds in which a Session can remain inactive
* before it is considered expired.
*/
public static final int DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS = (int) TimeUnit.MINUTES.toSeconds(30);
protected static final Class<Object> SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT = Object.class;
protected static final Class<GemFireSession> SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT = GemFireSession.class;
/**
* The default {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* Region that will store Spring Sessions.
*/
public static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = ClientRegionShortcut.PROXY;
/**
* The default {@link RegionShortcut} used to configure the GemFire Cache Region that
* will store Spring Sessions.
*/
public static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionShortcut.PARTITION;
/**
* Name of the GemFire {@link Pool} used by the client Region for managing Session state information.
*/
public static final String DEFAULT_GEMFIRE_POOL_NAME = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
/**
* The default name of the Gemfire (Client)Cache Region used to store Sessions.
*/
public static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME = "ClusteredSpringSessions";
/**
* The default names of all Session attributes that should be indexed by GemFire.
*/
public static final String[] DEFAULT_INDEXABLE_SESSION_ATTRIBUTES = {};
private int maxInactiveIntervalInSeconds = DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS;
private ClassLoader beanClassLoader;
private ClientRegionShortcut clientRegionShortcut = DEFAULT_CLIENT_REGION_SHORTCUT;
private RegionShortcut serverRegionShortcut = DEFAULT_SERVER_REGION_SHORTCUT;
private String poolName = DEFAULT_GEMFIRE_POOL_NAME;
private String springSessionGemFireRegionName = DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME;
private String[] indexableSessionAttributes = DEFAULT_INDEXABLE_SESSION_ATTRIBUTES;
/**
* Sets a reference to the {@link ClassLoader} used to load bean definition class
* types in a Spring context.
*
* @param beanClassLoader the ClassLoader used by the Spring container to load bean
* class types.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader
*/
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Gets a reference to the {@link ClassLoader} used to load bean definition class
* types in a Spring context.
*
* @return the ClassLoader used by the Spring container to load bean class types.
* @see java.lang.ClassLoader
*/
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* Sets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* Region that will store Spring Sessions.
*
* @param shortcut the ClientRegionShortcut used to configure the GemFire ClientCache
* Region.
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
public void setClientRegionShortcut(ClientRegionShortcut shortcut) {
this.clientRegionShortcut = shortcut;
}
/**
* Gets the {@link ClientRegionShortcut} used to configure the GemFire ClientCache
* Region that will store Spring Sessions. Defaults to
* {@link ClientRegionShortcut#PROXY}.
*
* @return the ClientRegionShortcut used to configure the GemFire ClientCache Region.
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see EnableGemFireHttpSession#clientRegionShortcut()
*/
protected ClientRegionShortcut getClientRegionShortcut() {
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
}
/**
* Sets the names of all Session attributes that should be indexed by GemFire.
*
* @param indexableSessionAttributes an array of Strings indicating the names of all
* Session attributes for which an Index will be created by GemFire.
*/
public void setIndexableSessionAttributes(String[] indexableSessionAttributes) {
this.indexableSessionAttributes = indexableSessionAttributes;
}
/**
* Get the names of all Session attributes that should be indexed by GemFire.
*
* @return an array of Strings indicating the names of all Session attributes for
* which an Index will be created by GemFire. Defaults to an empty String array if
* unspecified.
* @see EnableGemFireHttpSession#indexableSessionAttributes()
*/
protected String[] getIndexableSessionAttributes() {
return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes
: DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
}
/**
* Sets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
*
* @param maxInactiveIntervalInSeconds an integer value specifying the maximum
* interval in seconds that a Session can remain inactive before it is considered
* expired.
*/
public void setMaxInactiveIntervalInSeconds(int maxInactiveIntervalInSeconds) {
this.maxInactiveIntervalInSeconds = maxInactiveIntervalInSeconds;
}
/**
* Gets the maximum interval in seconds in which a Session can remain inactive before
* it is considered expired.
*
* @return an integer value specifying the maximum interval in seconds that a Session
* can remain inactive before it is considered expired.
* @see EnableGemFireHttpSession#maxInactiveIntervalInSeconds()
*/
protected int getMaxInactiveIntervalInSeconds() {
return this.maxInactiveIntervalInSeconds;
}
/**
* Sets the name of the GemFire {@link Pool} used by the client Region for managing Sessions
* during cache operations involving the server.
*
* @param poolName the name of a GemFire {@link Pool}.
* @see Pool#getName()
*/
public void setPoolName(String poolName) {
this.poolName = poolName;
}
/**
* Returns the name of the GemFire {@link Pool} used by the client Region for managing Sessions
* during cache operations involving the server.
*
* @return the name of a GemFire {@link Pool}.
* @see Pool#getName()
*/
protected String getPoolName() {
return (StringUtils.hasText(this.poolName) ? this.poolName : DEFAULT_GEMFIRE_POOL_NAME);
}
/**
* Sets the {@link RegionShortcut} used to configure the GemFire Cache Region that
* will store Spring Sessions.
*
* @param shortcut the RegionShortcut used to configure the GemFire Cache Region.
* @see org.apache.geode.cache.RegionShortcut
*/
public void setServerRegionShortcut(RegionShortcut shortcut) {
this.serverRegionShortcut = shortcut;
}
/**
* Gets the {@link RegionShortcut} used to configure the GemFire Cache Region that
* will store Spring Sessions. Defaults to {@link RegionShortcut#PARTITION}.
*
* @return the RegionShortcut used to configure the GemFire Cache Region.
* @see org.apache.geode.cache.RegionShortcut
* @see EnableGemFireHttpSession#serverRegionShortcut()
*/
protected RegionShortcut getServerRegionShortcut() {
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
}
/**
* Sets the name of the Gemfire (Client)Cache Region used to store Sessions.
*
* @param springSessionGemFireRegionName a String specifying the name of the GemFire
* (Client)Cache Region used to store the Session.
*/
public void setSpringSessionGemFireRegionName(String springSessionGemFireRegionName) {
this.springSessionGemFireRegionName = springSessionGemFireRegionName;
}
/**
* Gets the name of the Gemfire (Client)Cache Region used to store Sessions. Defaults
* to 'ClusteredSpringSessions'.
*
* @return a String specifying the name of the GemFire (Client)Cache Region used to
* store the Session.
* @see org.apache.geode.cache.Region#getName()
* @see EnableGemFireHttpSession#regionName()
*/
protected String getSpringSessionGemFireRegionName() {
return (StringUtils.hasText(this.springSessionGemFireRegionName) ? this.springSessionGemFireRegionName
: DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
/**
* Callback with the {@link AnnotationMetadata} of the class containing @Import
* annotation that imported this @Configuration class.
*
* @param importMetadata the AnnotationMetadata of the class importing
* this @Configuration class.
*/
public void setImportMetadata(AnnotationMetadata importMetadata) {
AnnotationAttributes enableGemFireHttpSessionAnnotationAttributes =
AnnotationAttributes.fromMap(importMetadata.getAnnotationAttributes(
EnableGemFireHttpSession.class.getName()));
setClientRegionShortcut(ClientRegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes
.getEnum("clientRegionShortcut")));
setIndexableSessionAttributes(enableGemFireHttpSessionAnnotationAttributes
.getStringArray("indexableSessionAttributes"));
setMaxInactiveIntervalInSeconds(enableGemFireHttpSessionAnnotationAttributes
.getNumber("maxInactiveIntervalInSeconds").intValue());
setPoolName(enableGemFireHttpSessionAnnotationAttributes.getString("poolName"));
setServerRegionShortcut(RegionShortcut.class.cast(enableGemFireHttpSessionAnnotationAttributes
.getEnum("serverRegionShortcut")));
setSpringSessionGemFireRegionName(enableGemFireHttpSessionAnnotationAttributes
.getString("regionName"));
}
/**
* Defines the Spring SessionRepository bean used to interact with GemFire as a Spring
* Session provider.
*
* @param gemfireOperations an instance of {@link GemfireOperations} used to manage
* Spring Sessions in GemFire.
* @return a GemFireOperationsSessionRepository for managing (clustering/replicating)
* Sessions using GemFire.
*/
@Bean
public GemFireOperationsSessionRepository sessionRepository(
@Qualifier("sessionRegionTemplate") GemfireOperations gemfireOperations) {
GemFireOperationsSessionRepository sessionRepository =
new GemFireOperationsSessionRepository(gemfireOperations);
sessionRepository.setMaxInactiveIntervalInSeconds(getMaxInactiveIntervalInSeconds());
return sessionRepository;
}
/**
* Defines a Spring GemfireTemplate bean used to interact with GemFire's (Client)Cache
* {@link Region} storing Sessions.
*
* @param gemFireCache reference to the single GemFire cache instance used by the
* {@link GemfireTemplate} to perform GemFire cache data access operations.
* @return a {@link GemfireTemplate} used to interact with GemFire's (Client)Cache
* {@link Region} storing Sessions.
* @see org.springframework.data.gemfire.GemfireTemplate
* @see org.apache.geode.cache.Region
*/
@Bean
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public GemfireTemplate sessionRegionTemplate(GemFireCache gemFireCache) {
return new GemfireTemplate(gemFireCache.getRegion(getSpringSessionGemFireRegionName()));
}
/**
* Defines a Spring GemFire {@link org.apache.geode.cache.Cache} {@link Region}
* bean used to store and manage Sessions using either a client-server or peer-to-peer
* (p2p) topology.
*
* @param gemfireCache a reference to the GemFire
* {@link org.apache.geode.cache.Cache}.
* @param sessionRegionAttributes the GemFire {@link RegionAttributes} used to
* configure the {@link Region}.
* @return a {@link GemFireCacheTypeAwareRegionFactoryBean} used to configure and
* initialize a GemFire Cache {@link Region} for storing and managing Sessions.
* @see #getClientRegionShortcut()
* @see #getSpringSessionGemFireRegionName()
* @see #getServerRegionShortcut()
*/
@Bean(name = DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> sessionRegion(GemFireCache gemfireCache,
@Qualifier("sessionRegionAttributes") RegionAttributes<Object, ExpiringSession> sessionRegionAttributes) {
GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> sessionRegion =
new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
sessionRegion.setClientRegionShortcut(getClientRegionShortcut());
sessionRegion.setGemfireCache(gemfireCache);
sessionRegion.setPoolName(getPoolName());
sessionRegion.setRegionAttributes(sessionRegionAttributes);
sessionRegion.setRegionName(getSpringSessionGemFireRegionName());
sessionRegion.setServerRegionShortcut(getServerRegionShortcut());
return sessionRegion;
}
/**
* Defines a Spring GemFire {@link RegionAttributes} bean used to configure and
* initialize the GemFire cache {@link Region} storing Sessions. Expiration is also
* configured for the {@link Region} on the basis that the GemFire cache
* {@link Region} is a not a proxy, on either the client or server.
*
* @param gemfireCache a reference to the GemFire cache.
* @return an instance of {@link RegionAttributes} used to configure and initialize
* the GemFire cache {@link Region} for storing and managing Sessions.
* @see org.springframework.data.gemfire.RegionAttributesFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.PartitionAttributes
* @see #isExpirationAllowed(GemFireCache)
*/
@Bean
@SuppressWarnings({ "unchecked", "deprecation" })
public RegionAttributesFactoryBean sessionRegionAttributes(GemFireCache gemfireCache) {
RegionAttributesFactoryBean regionAttributes = new RegionAttributesFactoryBean();
regionAttributes.setKeyConstraint(SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT);
regionAttributes.setValueConstraint(SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT);
if (isExpirationAllowed(gemfireCache)) {
regionAttributes.setStatisticsEnabled(true);
regionAttributes.setEntryIdleTimeout(
new ExpirationAttributes(Math.max(getMaxInactiveIntervalInSeconds(), 0), ExpirationAction.INVALIDATE));
}
return regionAttributes;
}
/**
* Determines whether expiration configuration is allowed to be set on the GemFire
* cache {@link Region} used to store and manage Sessions.
*
* @param gemfireCache a reference to the GemFire cache.
* @return a boolean indicating if a {@link Region} can be configured for Region entry
* idle-timeout expiration.
* @see GemFireUtils#isClient(GemFireCache)
* @see GemFireUtils#isProxy(ClientRegionShortcut)
* @see GemFireUtils#isProxy(RegionShortcut)
*/
boolean isExpirationAllowed(GemFireCache gemfireCache) {
return !(GemFireUtils.isClient(gemfireCache) ? GemFireUtils.isProxy(getClientRegionShortcut())
: GemFireUtils.isProxy(getServerRegionShortcut()));
}
/**
* Defines a GemFire Index bean on the GemFire cache {@link Region} storing and managing Sessions,
* specifically on the 'principalName' property for quick lookup of Sessions by 'principalName'.
*
* @param gemfireCache a reference to the GemFire cache.
* @return a {@link IndexFactoryBean} to create an GemFire Index on the 'principalName' property
* for Sessions stored in the GemFire cache {@link Region}.
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.apache.geode.cache.GemFireCache
*/
@Bean
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public IndexFactoryBean principalNameIndex(GemFireCache gemfireCache) {
IndexFactoryBean index = new IndexFactoryBean();
index.setCache(gemfireCache);
index.setName("principalNameIndex");
index.setExpression("principalName");
index.setFrom(GemFireUtils.toRegionPath(getSpringSessionGemFireRegionName()));
index.setOverride(true);
index.setType(IndexType.HASH);
return index;
}
/**
* Defines a GemFire Index bean on the GemFire cache {@link Region} storing and managing Sessions,
* specifically on all Session attributes for quick lookup and queries on Session attribute names
* with a given value.
*
* @param gemfireCache a reference to the GemFire cache.
* @return a {@link IndexFactoryBean} to create an GemFire Index on attributes of Sessions
* stored in the GemFire cache {@link Region}.
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.apache.geode.cache.GemFireCache
*/
@Bean
@DependsOn(DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME)
public SessionAttributesIndexFactoryBean sessionAttributesIndex(GemFireCache gemfireCache) {
SessionAttributesIndexFactoryBean sessionAttributesIndex = new SessionAttributesIndexFactoryBean();
sessionAttributesIndex.setGemFireCache(gemfireCache);
sessionAttributesIndex.setIndexableSessionAttributes(getIndexableSessionAttributes());
sessionAttributesIndex.setRegionName(getSpringSessionGemFireRegionName());
return sessionAttributesIndex;
}
}

View File

@@ -1,384 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.InterestResultPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.Pool;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.GenericRegionFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.client.Interest;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link GemFireCacheTypeAwareRegionFactoryBean} class is a Spring {@link FactoryBean}
* used to construct, configure and initialize the GemFire cache {@link Region} used to
* store and manage Session state.
*
* @param <K> the type of keys
* @param <V> the type of values
* @author John Blum
* @since 1.1.0
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
*/
public class GemFireCacheTypeAwareRegionFactoryBean<K, V>
implements BeanFactoryAware, FactoryBean<Region<K, V>>, InitializingBean {
protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT =
GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT;
protected static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT =
GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT;
protected static final String DEFAULT_GEMFIRE_POOL_NAME =
GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME;
protected static final String DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME =
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME;
private BeanFactory beanFactory;
private ClientRegionShortcut clientRegionShortcut;
private GemFireCache gemfireCache;
private Region<K, V> region;
private RegionAttributes<K, V> regionAttributes;
private RegionShortcut serverRegionShortcut;
private String poolName;
private String regionName;
/**
* Post-construction initialization callback to create, configure and initialize the
* GemFire cache {@link Region} used to store, replicate (distribute) and manage
* Session state. This method intelligently handles both client-server and
* peer-to-peer (p2p) GemFire supported distributed system topologies.
*
* @throws Exception if the initialization of the GemFire cache {@link Region} fails.
* @see org.springframework.session.data.gemfire.support.GemFireUtils#isClient(GemFireCache)
* @see #getGemfireCache()
* @see #newClientRegion(GemFireCache)
* @see #newServerRegion(GemFireCache)
*/
public void afterPropertiesSet() throws Exception {
GemFireCache gemfireCache = getGemfireCache();
this.region = (GemFireUtils.isClient(gemfireCache) ? newClientRegion(gemfireCache)
: newServerRegion(gemfireCache));
}
/**
* Constructs a GemFire cache {@link Region} using a peer-to-peer (p2p) GemFire
* topology to store and manage Session state in a GemFire server cluster accessible
* from a GemFire cache client.
*
* @param gemfireCache a reference to the GemFire
* {@link org.apache.geode.cache.Cache}.
* @return a peer-to-peer-based GemFire cache {@link Region} to store and manage
* Session state.
* @throws Exception if the instantiation, configuration and initialization of the
* GemFire cache {@link Region} fails.
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see #getRegionAttributes()
* @see #getRegionName()
* @see #getServerRegionShortcut()
*/
protected Region<K, V> newServerRegion(GemFireCache gemfireCache) throws Exception {
GenericRegionFactoryBean<K, V> serverRegion = new GenericRegionFactoryBean<K, V>();
serverRegion.setAttributes(getRegionAttributes());
serverRegion.setCache(gemfireCache);
serverRegion.setRegionName(getRegionName());
serverRegion.setShortcut(getServerRegionShortcut());
serverRegion.afterPropertiesSet();
return serverRegion.getObject();
}
/**
* Constructs a GemFire cache {@link Region} using the client-server GemFire topology
* to store and manage Session state in a GemFire server cluster accessible from a
* GemFire cache client.
*
* @param gemfireCache a reference to the GemFire
* {@link org.apache.geode.cache.Cache}.
* @return a client-server-based GemFire cache {@link Region} to store and manage
* Session state.
* @throws Exception if the instantiation, configuration and initialization of the
* GemFire cache {@link Region} fails.
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see #getClientRegionShortcut()
* @see #getRegionAttributes()
* @see #getRegionName()
* @see #registerInterests(boolean)
*/
protected Region<K, V> newClientRegion(GemFireCache gemfireCache) throws Exception {
ClientRegionFactoryBean<K, V> clientRegion = new ClientRegionFactoryBean<K, V>();
ClientRegionShortcut shortcut = getClientRegionShortcut();
clientRegion.setAttributes(getRegionAttributes());
clientRegion.setBeanFactory(getBeanFactory());
clientRegion.setCache(gemfireCache);
clientRegion.setInterests(registerInterests(!GemFireUtils.isLocal(shortcut)));
clientRegion.setPoolName(getPoolName());
clientRegion.setRegionName(getRegionName());
clientRegion.setShortcut(shortcut);
clientRegion.afterPropertiesSet();
return clientRegion.getObject();
}
/**
* Decides whether interests will be registered for all keys. Interests is only registered on
* a client and typically only when the client is a (CACHING) PROXY to the server (i.e. non-LOCAL only).
*
* @param register a boolean value indicating whether interests should be registered.
* @return an array of Interests KEY/VALUE registrations.
* @see org.springframework.data.gemfire.client.Interest
*/
@SuppressWarnings("unchecked")
protected Interest<K>[] registerInterests(boolean register) {
return (!register ? new Interest[0] : new Interest[] {
new Interest<String>("ALL_KEYS", InterestResultPolicy.KEYS)
});
}
/**
* Returns a reference to the constructed GemFire cache {@link Region} used to store
* and manage Session state.
*
* @return the {@link Region} used to store and manage Session state.
* @throws Exception if the {@link Region} reference cannot be obtained.
* @see org.apache.geode.cache.Region
*/
public Region<K, V> getObject() throws Exception {
return this.region;
}
/**
* Returns the specific type of GemFire cache {@link Region} this factory creates when
* initialized or Region.class when uninitialized.
*
* @return the GemFire cache {@link Region} class type constructed by this factory.
* @see org.apache.geode.cache.Region
* @see java.lang.Class
*/
public Class<?> getObjectType() {
return (this.region != null ? this.region.getClass() : Region.class);
}
/**
* Returns true indicating the GemFire cache {@link Region} created by this factory is
* the sole instance.
*
* @return true to indicate the GemFire cache {@link Region} storing and managing
* Sessions is a Singleton.
*/
public boolean isSingleton() {
return true;
}
/**
* Sets a reference to the Spring {@link BeanFactory} responsible for
* creating GemFire components.
*
* @param beanFactory reference to the Spring {@link BeanFactory}
* @throws IllegalArgumentException if the {@link BeanFactory} reference is null.
* @see org.springframework.beans.factory.BeanFactory
*/
public void setBeanFactory(BeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}
/**
* Gets a reference to the Spring {@link BeanFactory} responsible for
* creating GemFire components.
*
* @return a reference to the Spring {@link BeanFactory}
* @throws IllegalStateException if the {@link BeanFactory} reference
* is null.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "A reference to the BeanFactory was not properly configured");
return this.beanFactory;
}
/**
* Sets the {@link Region} data policy used by the GemFire cache client to manage
* Session state.
*
* @param clientRegionShortcut a {@link ClientRegionShortcut} to specify the client
* {@link Region} data management policy.
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
public void setClientRegionShortcut(ClientRegionShortcut clientRegionShortcut) {
this.clientRegionShortcut = clientRegionShortcut;
}
/**
* Returns the {@link Region} data policy used by the GemFire cache client to manage
* Session state. Defaults to {@link ClientRegionShortcut#PROXY}.
*
* @return a {@link ClientRegionShortcut} specifying the client {@link Region} data
* management policy.
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration#DEFAULT_CLIENT_REGION_SHORTCUT
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
protected ClientRegionShortcut getClientRegionShortcut() {
return (this.clientRegionShortcut != null ? this.clientRegionShortcut : DEFAULT_CLIENT_REGION_SHORTCUT);
}
/**
* Sets a reference to the GemFire cache used to construct the appropriate
* {@link Region}.
*
* @param gemfireCache a reference to the GemFire cache.
* @throws IllegalArgumentException if the {@link GemFireCache} reference is null.
*/
public void setGemfireCache(GemFireCache gemfireCache) {
Assert.notNull(gemfireCache, "GemFireCache must not be null");
this.gemfireCache = gemfireCache;
}
/**
* Returns a reference to the GemFire cache used to construct the appropriate
* {@link Region}.
*
* @return a reference to the GemFire cache.
* @throws IllegalStateException if the {@link GemFireCache} reference is null.
*/
protected GemFireCache getGemfireCache() {
Assert.state(this.gemfireCache != null, "A reference to the GemFireCache was not properly configured");
return this.gemfireCache;
}
/**
* Sets the name of the GemFire {@link Pool} used by the client Region for managing Sessions
* during cache operations involving the server.
*
* @param poolName the name of a GemFire {@link Pool}.
* @see Pool#getName()
*/
public void setPoolName(final String poolName) {
this.poolName = poolName;
}
/**
* Returns the name of the GemFire {@link Pool} used by the client Region for managing Sessions
* during cache operations involving the server.
*
* @return the name of a GemFire {@link Pool}.
* @see Pool#getName()
*/
protected String getPoolName() {
return (StringUtils.hasText(this.poolName) ? this.poolName : DEFAULT_GEMFIRE_POOL_NAME);
}
/**
* Sets the GemFire {@link RegionAttributes} used to configure the GemFire cache
* {@link Region} used to store and manage Session state.
*
* @param regionAttributes the GemFire {@link RegionAttributes} used to configure the
* GemFire cache {@link Region}.
* @see org.apache.geode.cache.RegionAttributes
*/
public void setRegionAttributes(RegionAttributes<K, V> regionAttributes) {
this.regionAttributes = regionAttributes;
}
/**
* Returns the GemFire {@link RegionAttributes} used to configure the GemFire cache
* {@link Region} used to store and manage Session state.
*
* @return the GemFire {@link RegionAttributes} used to configure the GemFire cache
* {@link Region}.
* @see org.apache.geode.cache.RegionAttributes
*/
protected RegionAttributes<K, V> getRegionAttributes() {
return this.regionAttributes;
}
/**
* Sets the name of the GemFire cache {@link Region} use to store and manage Session
* state.
*
* @param regionName a String specifying the name of the GemFire cache {@link Region}.
*/
public void setRegionName(final String regionName) {
this.regionName = regionName;
}
/**
* Returns the configured name of the GemFire cache {@link Region} use to store and
* manage Session state. Defaults to "ClusteredSpringSessions"
*
* @return a String specifying the name of the GemFire cache {@link Region}.
* @see org.apache.geode.cache.Region#getName()
*/
protected String getRegionName() {
return (StringUtils.hasText(this.regionName) ? this.regionName : DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
/**
* Sets the {@link Region} data policy used by the GemFire peer cache to manage
* Session state.
*
* @param serverRegionShortcut a {@link RegionShortcut} to specify the peer
* {@link Region} data management policy.
* @see org.apache.geode.cache.RegionShortcut
*/
public void setServerRegionShortcut(RegionShortcut serverRegionShortcut) {
this.serverRegionShortcut = serverRegionShortcut;
}
/**
* Returns the {@link Region} data policy used by the GemFire peer cache to manage
* Session state. Defaults to {@link RegionShortcut#PARTITION}.
*
* @return a {@link RegionShortcut} specifying the peer {@link Region} data management
* policy.
* @see org.apache.geode.cache.RegionShortcut
*/
protected RegionShortcut getServerRegionShortcut() {
return (this.serverRegionShortcut != null ? this.serverRegionShortcut : DEFAULT_SERVER_REGION_SHORTCUT);
}
}

View File

@@ -1,175 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
import javax.servlet.http.HttpSession;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.query.Index;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.session.data.gemfire.support.GemFireUtils;
import org.springframework.util.ObjectUtils;
/**
* The SessionAttributesIndexFactoryBean class is a Spring {@link FactoryBean} that creates a GemFire {@link Index}
* on the session attributes of the {@link HttpSession} object.
*
* @author John Blum
* @since 1.3.0
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.apache.geode.cache.query.Index
*/
public class SessionAttributesIndexFactoryBean implements FactoryBean<Index>,
InitializingBean, BeanFactoryAware, BeanNameAware {
protected static final String[] DEFAULT_INDEXABLE_SESSION_ATTRIBUTES = {};
private BeanFactory beanFactory;
private GemFireCache gemfireCache;
private Index sessionAttributesIndex;
private String beanName;
private String regionName;
private String[] indexableSessionAttributes;
/* (non-Javadoc) */
public void afterPropertiesSet() throws Exception {
if (isIndexableSessionAttributesConfigured()) {
this.sessionAttributesIndex = newIndex();
}
}
/**
* Determines whether any indexable Session attributes were configured for this {@link FactoryBean}.
*
* @return a boolean value indicating whether any indexable Session attributes were configured
* for this {@link FactoryBean}
* @see #setIndexableSessionAttributes(String[])
*/
protected boolean isIndexableSessionAttributesConfigured() {
return !ObjectUtils.isEmpty(this.indexableSessionAttributes);
}
/**
* Constructs a GemFire {@link Index} over the attributes of the {@link HttpSession}.
*
* @return a GemFire {@link Index} over the {@link HttpSession} attributes.
* @throws Exception if an error occurs while initializing the GemFire {@link Index}.
* @see org.springframework.data.gemfire.IndexFactoryBean
*/
protected Index newIndex() throws Exception {
IndexFactoryBean indexFactory = new IndexFactoryBean();
indexFactory.setBeanFactory(this.beanFactory);
indexFactory.setBeanName(this.beanName);
indexFactory.setCache(this.gemfireCache);
indexFactory.setName("sessionAttributesIndex");
indexFactory.setExpression(String.format("s.attributes[%1$s]",
getIndexableSessionAttributesAsGemFireIndexExpression()));
indexFactory.setFrom(String.format("%1$s s", GemFireUtils.toRegionPath(this.regionName)));
indexFactory.setOverride(true);
indexFactory.afterPropertiesSet();
return indexFactory.getObject();
}
/**
* Gets the names of all Session attributes that will be indexed by GemFire as single, comma-delimited
* String value constituting the Index expression of the Index definition.
*
* @return a String composed of all the named Session attributes for which GemFire
* will create an Index as an Index definition expression. If the indexable Session
* attributes were not configured, then the wildcard ("*") is returned.
* @see org.apache.geode.cache.query.Index#getIndexedExpression()
*/
protected String getIndexableSessionAttributesAsGemFireIndexExpression() {
StringBuilder builder = new StringBuilder();
for (String sessionAttribute : getIndexableSessionAttributes()) {
builder.append(builder.length() > 0 ? ", " : "");
builder.append(String.format("'%s'", sessionAttribute));
}
String indexExpression = builder.toString();
return (indexExpression.isEmpty() ? "*" : indexExpression);
}
/* (non-Javadoc) */
public Index getObject() throws Exception {
return this.sessionAttributesIndex;
}
/* (non-Javadoc) */
public Class<?> getObjectType() {
return (this.sessionAttributesIndex != null ? this.sessionAttributesIndex.getClass() : Index.class);
}
/* (non-Javadoc) */
public boolean isSingleton() {
return true;
}
/* (non-Javadoc) */
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
public void setBeanName(String beanName) {
this.beanName = beanName;
}
/* (non-Javadoc) */
public void setGemFireCache(GemFireCache gemfireCache) {
this.gemfireCache = gemfireCache;
}
/* (non-Javadoc) */
public void setIndexableSessionAttributes(String[] indexableSessionAttributes) {
this.indexableSessionAttributes = indexableSessionAttributes;
}
/* (non-Javadoc) */
protected String[] getIndexableSessionAttributes() {
return (this.indexableSessionAttributes != null ? this.indexableSessionAttributes
: DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
}
/* (non-Javadoc) */
public void setRegionName(String regionName) {
this.regionName = regionName;
}
/* (non-Javadoc) */
protected String getRegionName() {
return this.regionName;
}
}

View File

@@ -1,170 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.support;
import java.io.Closeable;
import java.io.IOException;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.internal.cache.GemFireCacheImpl;
/**
* GemFireUtils is an abstract, extensible utility class for working with GemFire types
* and functionality and is used by Spring Session's GemFire adapter support classes.
*
* @author John Blum
* @since 1.1.0
*/
public abstract class GemFireUtils {
/**
* Null-safe method to close the given {@link Closeable} object.
*
* @param obj the {@link Closeable} object to close.
* @return true if the {@link Closeable} object is not null and was successfully
* closed, otherwise return false.
* @see java.io.Closeable
*/
public static boolean close(Closeable obj) {
if (obj != null) {
try {
obj.close();
return true;
}
catch (IOException ignore) {
}
}
return false;
}
/**
* Determines whether the GemFire cache is a client.
*
* @param gemFireCache a reference to the GemFire cache.
* @return a boolean value indicating whether the GemFire cache is a client.
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.GemFireCache
*/
public static boolean isClient(GemFireCache gemFireCache) {
boolean client = (gemFireCache instanceof ClientCache);
client &= (!(gemFireCache instanceof GemFireCacheImpl) || ((GemFireCacheImpl) gemFireCache).isClient());
return client;
}
/**
* Determines whether the GemFire cache is a peer.
*
* @param gemFireCache a reference to the GemFire cache.
* @return a boolean value indicating whether the GemFire cache is a peer.
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
*/
public static boolean isPeer(GemFireCache gemFireCache) {
return (gemFireCache instanceof Cache && !isClient(gemFireCache));
}
/**
* Determines whether the given {@link ClientRegionShortcut} is local only.
*
* @param shortcut the ClientRegionShortcut to evaluate.
* @return a boolean value indicating if the {@link ClientRegionShortcut} is local or
* not.
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
public static boolean isLocal(ClientRegionShortcut shortcut) {
switch (shortcut) {
case LOCAL:
case LOCAL_HEAP_LRU:
case LOCAL_OVERFLOW:
case LOCAL_PERSISTENT:
case LOCAL_PERSISTENT_OVERFLOW:
return true;
default:
return false;
}
}
/**
* Determines whether the client {@link ClientRegionShortcut} is a proxy-based
* shortcut. NOTE: "proxy"-based Regions keep no local state.
*
* @param shortcut the client {@link ClientRegionShortcut} to evaluate.
* @return a boolean value indicating whether the client {@link ClientRegionShortcut}
* refers to a proxy-based shortcut.
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
public static boolean isProxy(ClientRegionShortcut shortcut) {
switch (shortcut) {
case PROXY:
return true;
default:
return false;
}
}
/**
* Determines whether the given {@link Region} is a PROXY, which would be indicated by the {@link Region}
* having a {@link DataPolicy} of {@link DataPolicy#EMPTY}.
*
* @param region {@link Region} to evaluate.
* @return a boolean value indicating whether the {@link Region} is a PROXY.
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.Region
*/
public static boolean isProxy(Region<?, ?> region) {
return DataPolicy.EMPTY.equals(region.getAttributes().getDataPolicy());
}
/**
* Determines whether the peer {@link RegionShortcut} is a proxy-based shortcut. NOTE:
* "proxy"-based Regions keep no local state.
*
* @param shortcut the peer {@link RegionShortcut} to evaluate.
* @return a boolean value indicating whether the peer {@link RegionShortcut} refers
* to a proxy-based shortcut.
* @see org.apache.geode.cache.RegionShortcut
*/
public static boolean isProxy(RegionShortcut shortcut) {
switch (shortcut) {
case PARTITION_PROXY:
case PARTITION_PROXY_REDUNDANT:
case REPLICATE_PROXY:
return true;
default:
return false;
}
}
/**
* Converts a {@link Region} name to a {@link Region} path.
*
* @param regionName a String specifying the name of the {@link Region}.
* @return a String path for the given {@link Region} by name.
* @see org.apache.geode.cache.Region#getFullPath()
* @see org.apache.geode.cache.Region#getName()
*/
public static String toRegionPath(String regionName) {
return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
}
}

View File

@@ -1,436 +0,0 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.geode.cache.AttributesMutator;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.query.SelectResults;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.gemfire.GemfireAccessor;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.session.ExpiringSession;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.events.AbstractSessionEvent;
import org.springframework.session.events.SessionDeletedEvent;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isA;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* The GemFireOperationsSessionRepositoryTest class is a test suite of test cases testing
* the contract and functionality of the GemFireOperationsSessionRepository class.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.apache.geode.cache.Region
*/
@RunWith(MockitoJUnitRunner.class)
public class GemFireOperationsSessionRepositoryTest {
protected static final int MAX_INACTIVE_INTERVAL_IN_SECONDS = 600;
@Mock
private ApplicationEventPublisher mockApplicationEventPublisher;
@Mock
private AttributesMutator<Object, ExpiringSession> mockAttributesMutator;
@Mock
private GemfireOperationsAccessor mockTemplate;
private GemFireOperationsSessionRepository sessionRepository;
@Mock
private Region<Object, ExpiringSession> mockRegion;
@Before
public void setup() throws Exception {
given(this.mockRegion.getAttributesMutator()).willReturn(this.mockAttributesMutator);
given(this.mockRegion.getFullPath()).willReturn("/Example");
given(this.mockTemplate.<Object, ExpiringSession>getRegion()).willReturn(this.mockRegion);
this.sessionRepository = new GemFireOperationsSessionRepository(this.mockTemplate);
this.sessionRepository.setApplicationEventPublisher(this.mockApplicationEventPublisher);
this.sessionRepository.setMaxInactiveIntervalInSeconds(MAX_INACTIVE_INTERVAL_IN_SECONDS);
this.sessionRepository.afterPropertiesSet();
assertThat(this.sessionRepository.getApplicationEventPublisher()).isSameAs(this.mockApplicationEventPublisher);
assertThat(this.sessionRepository.getFullyQualifiedRegionName()).isEqualTo("/Example");
assertThat(this.sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
@After
public void tearDown() {
verify(this.mockAttributesMutator, times(1)).addCacheListener(same(this.sessionRepository));
verify(this.mockRegion, times(1)).getFullPath();
verify(this.mockTemplate, times(1)).getRegion();
}
@Test
@SuppressWarnings("unchecked")
public void findByIndexNameValueFindsMatchingSession() {
ExpiringSession mockSession = mock(ExpiringSession.class, "MockSession");
given(mockSession.getId()).willReturn("1");
SelectResults<Object> mockSelectResults = mock(SelectResults.class);
given(mockSelectResults.asList()).willReturn(Collections.<Object>singletonList(mockSession));
String indexName = "vip";
String indexValue = "rwinch";
String expectedQql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), indexName);
given(this.mockTemplate.find(eq(expectedQql), eq(indexValue))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions =
this.sessionRepository.findByIndexNameAndIndexValue(indexName, indexValue);
assertThat(sessions).isNotNull();
assertThat(sessions.size()).isEqualTo(1);
assertThat(sessions.get("1")).isEqualTo(mockSession);
verify(this.mockTemplate, times(1)).find(eq(expectedQql), eq(indexValue));
verify(mockSelectResults, times(1)).asList();
verify(mockSession, times(1)).getId();
}
@Test
@SuppressWarnings("unchecked")
public void findByPrincipalNameFindsMatchingSessions() throws Exception {
ExpiringSession mockSessionOne = mock(ExpiringSession.class, "MockSessionOne");
ExpiringSession mockSessionTwo = mock(ExpiringSession.class, "MockSessionTwo");
ExpiringSession mockSessionThree = mock(ExpiringSession.class, "MockSessionThree");
given(mockSessionOne.getId()).willReturn("1");
given(mockSessionTwo.getId()).willReturn("2");
given(mockSessionThree.getId()).willReturn("3");
SelectResults<Object> mockSelectResults = mock(SelectResults.class);
given(mockSelectResults.asList())
.willReturn(Arrays.<Object>asList(mockSessionOne, mockSessionTwo, mockSessionThree));
String principalName = "jblum";
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
given(this.mockTemplate.find(eq(expectedOql), eq(principalName))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions = this.sessionRepository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
assertThat(sessions).isNotNull();
assertThat(sessions.size()).isEqualTo(3);
assertThat(sessions.get("1")).isEqualTo(mockSessionOne);
assertThat(sessions.get("2")).isEqualTo(mockSessionTwo);
assertThat(sessions.get("3")).isEqualTo(mockSessionThree);
verify(this.mockTemplate, times(1)).find(eq(expectedOql), eq(principalName));
verify(mockSelectResults, times(1)).asList();
verify(mockSessionOne, times(1)).getId();
verify(mockSessionTwo, times(1)).getId();
verify(mockSessionThree, times(1)).getId();
}
@Test
@SuppressWarnings("unchecked")
public void findByPrincipalNameReturnsNoMatchingSessions() {
SelectResults<Object> mockSelectResults = mock(SelectResults.class);
given(mockSelectResults.asList()).willReturn(Collections.emptyList());
String principalName = "jblum";
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
given(this.mockTemplate.find(eq(expectedOql), eq(principalName))).willReturn(mockSelectResults);
Map<String, ExpiringSession> sessions = this.sessionRepository.findByIndexNameAndIndexValue(
FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, principalName);
assertThat(sessions).isNotNull();
assertThat(sessions.isEmpty()).isTrue();
verify(this.mockTemplate, times(1)).find(eq(expectedOql), eq(principalName));
verify(mockSelectResults, times(1)).asList();
}
@Test
public void prepareQueryReturnsPrincipalNameOql() {
String actualQql =
this.sessionRepository.prepareQuery(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME);
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_PRINCIPAL_NAME_QUERY,
this.sessionRepository.getFullyQualifiedRegionName());
assertThat(actualQql).isEqualTo(expectedOql);
}
@Test
public void prepareQueryReturnsIndexNameValueOql() {
String attributeName = "testAttributeName";
String actualOql = this.sessionRepository.prepareQuery(attributeName);
String expectedOql = String.format(GemFireOperationsSessionRepository.FIND_SESSIONS_BY_INDEX_NAME_VALUE_QUERY,
this.sessionRepository.getFullyQualifiedRegionName(), attributeName);
assertThat(actualOql).isEqualTo(expectedOql);
}
@Test
public void createProperlyInitializedSession() {
long beforeOrAtCreationTime = System.currentTimeMillis();
ExpiringSession session = this.sessionRepository.createSession();
assertThat(session).isInstanceOf(AbstractGemFireOperationsSessionRepository.GemFireSession.class);
assertThat(session.getId()).isNotNull();
assertThat(session.getAttributeNames().isEmpty()).isTrue();
assertThat(session.getCreationTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(session.getLastAccessedTime()).isGreaterThanOrEqualTo(beforeOrAtCreationTime);
assertThat(session.getMaxInactiveIntervalInSeconds()).isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
}
@Test
public void getSessionDeletesMatchingExpiredSessionById() {
final String expectedSessionId = "1";
final ExpiringSession mockSession = mock(ExpiringSession.class);
given(mockSession.isExpired()).willReturn(true);
given(mockSession.getId()).willReturn(expectedSessionId);
given(this.mockTemplate.get(eq(expectedSessionId))).willReturn(mockSession);
given(this.mockTemplate.remove(eq(expectedSessionId))).willReturn(mockSession);
willAnswer(new Answer<Void>() {
public Void answer(final InvocationOnMock invocation) throws Throwable {
ApplicationEvent applicationEvent = invocation.getArgument(0);
assertThat(applicationEvent).isInstanceOf(SessionDeletedEvent.class);
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource())
.isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.<ExpiringSession>getSession()).isSameAs(mockSession);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
return null;
}
}).given(this.mockApplicationEventPublisher).publishEvent(any(ApplicationEvent.class));
assertThat(this.sessionRepository.getSession(expectedSessionId)).isNull();
verify(this.mockTemplate, times(1)).get(eq(expectedSessionId));
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(mockSession, times(1)).isExpired();
verify(mockSession, times(2)).getId();
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
public void getSessionFindsMatchingNonExpiredSessionById() {
String expectedId = "1";
long expectedCreationTime = System.currentTimeMillis();
long currentLastAccessedTime = (expectedCreationTime + TimeUnit.MINUTES.toMillis(5));
ExpiringSession mockSession = mock(ExpiringSession.class);
given(mockSession.isExpired()).willReturn(false);
given(mockSession.getId()).willReturn(expectedId);
given(mockSession.getCreationTime()).willReturn(expectedCreationTime);
given(mockSession.getLastAccessedTime()).willReturn(currentLastAccessedTime);
given(mockSession.getAttributeNames()).willReturn(Collections.singleton("attrOne"));
given(mockSession.getAttribute(eq("attrOne"))).willReturn("test");
given(this.mockTemplate.get(eq(expectedId))).willReturn(mockSession);
ExpiringSession actualSession = this.sessionRepository.getSession(expectedId);
assertThat(actualSession).isNotSameAs(mockSession);
assertThat(actualSession.getId()).isEqualTo(expectedId);
assertThat(actualSession.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(actualSession.getLastAccessedTime()).isNotEqualTo(currentLastAccessedTime);
assertThat(actualSession.getLastAccessedTime()).isGreaterThanOrEqualTo(expectedCreationTime);
assertThat(actualSession.getAttributeNames()).isEqualTo(Collections.singleton("attrOne"));
assertThat(String.valueOf(actualSession.<String>getAttribute("attrOne"))).isEqualTo("test");
verify(this.mockTemplate, times(1)).get(eq(expectedId));
verify(mockSession, times(1)).isExpired();
verify(mockSession, times(1)).getId();
verify(mockSession, times(1)).getCreationTime();
verify(mockSession, times(1)).getLastAccessedTime();
verify(mockSession, times(1)).getAttributeNames();
verify(mockSession, times(1)).getAttribute(eq("attrOne"));
}
@Test
public void getSessionReturnsNull() {
given(this.mockTemplate.get(anyString())).willReturn(null);
assertThat(this.sessionRepository.getSession("1")).isNull();
}
@Test
public void saveStoresSession() {
final String expectedSessionId = "1";
final long expectedCreationTime = System.currentTimeMillis();
final long expectedLastAccessTime = (expectedCreationTime + TimeUnit.MINUTES.toMillis(5));
ExpiringSession mockSession = mock(ExpiringSession.class);
given(mockSession.getId()).willReturn(expectedSessionId);
given(mockSession.getCreationTime()).willReturn(expectedCreationTime);
given(mockSession.getLastAccessedTime()).willReturn(expectedLastAccessTime);
given(mockSession.getMaxInactiveIntervalInSeconds())
.willReturn(MAX_INACTIVE_INTERVAL_IN_SECONDS);
given(mockSession.getAttributeNames()).willReturn(Collections.<String>emptySet());
given(this.mockTemplate.put(eq(expectedSessionId),
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class)))
.willAnswer(new Answer<ExpiringSession>() {
public ExpiringSession answer(InvocationOnMock invocation) throws Throwable {
ExpiringSession session = invocation.getArgument(1);
assertThat(session).isNotNull();
assertThat(session.getId()).isEqualTo(expectedSessionId);
assertThat(session.getCreationTime()).isEqualTo(expectedCreationTime);
assertThat(session.getLastAccessedTime()).isEqualTo(expectedLastAccessTime);
assertThat(session.getMaxInactiveIntervalInSeconds())
.isEqualTo(MAX_INACTIVE_INTERVAL_IN_SECONDS);
assertThat(session.getAttributeNames().isEmpty()).isTrue();
return null;
}
});
this.sessionRepository.save(mockSession);
verify(mockSession, times(2)).getId();
verify(mockSession, times(1)).getCreationTime();
verify(mockSession, times(1)).getLastAccessedTime();
verify(mockSession, times(1)).getMaxInactiveIntervalInSeconds();
verify(mockSession, times(1)).getAttributeNames();
verify(this.mockTemplate, times(1)).put(eq(expectedSessionId),
isA(AbstractGemFireOperationsSessionRepository.GemFireSession.class));
}
@Test
public void deleteRemovesExistingSessionAndHandlesDelete() {
final String expectedSessionId = "1";
final ExpiringSession mockSession = mock(ExpiringSession.class);
given(mockSession.getId()).willReturn(expectedSessionId);
given(this.mockTemplate.remove(eq(expectedSessionId))).willReturn(mockSession);
willAnswer(new Answer<Void>() {
public Void answer(final InvocationOnMock invocation) throws Throwable {
ApplicationEvent applicationEvent = invocation.getArgument(0);
assertThat(applicationEvent).isInstanceOf(SessionDeletedEvent.class);
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource())
.isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.<ExpiringSession>getSession()).isSameAs(mockSession);
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
return null;
}
}).given(this.mockApplicationEventPublisher).publishEvent(isA(SessionDeletedEvent.class));
this.sessionRepository.delete(expectedSessionId);
verify(mockSession, times(1)).getId();
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
@Test
public void deleteRemovesNonExistingSessionAndHandlesDelete() {
final String expectedSessionId = "1";
given(this.mockTemplate.remove(anyString())).willReturn(null);
willAnswer(new Answer<Void>() {
public Void answer(final InvocationOnMock invocation) throws Throwable {
ApplicationEvent applicationEvent = invocation.getArgument(0);
assertThat(applicationEvent).isInstanceOf(SessionDeletedEvent.class);
AbstractSessionEvent sessionEvent = (AbstractSessionEvent) applicationEvent;
assertThat(sessionEvent.getSource()).
isSameAs(GemFireOperationsSessionRepositoryTest.this.sessionRepository);
assertThat(sessionEvent.<ExpiringSession>getSession()).isNull();
assertThat(sessionEvent.getSessionId()).isEqualTo(expectedSessionId);
return null;
}
}).given(this.mockApplicationEventPublisher).publishEvent(isA(SessionDeletedEvent.class));
this.sessionRepository.delete(expectedSessionId);
verify(this.mockTemplate, times(1)).remove(eq(expectedSessionId));
verify(this.mockApplicationEventPublisher, times(1))
.publishEvent(isA(SessionDeletedEvent.class));
}
protected abstract class GemfireOperationsAccessor extends GemfireAccessor
implements GemfireOperations {
}
}

View File

@@ -1,407 +0,0 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.ExpirationAction;
import org.apache.geode.cache.ExpirationAttributes;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.GemfireOperations;
import org.springframework.data.gemfire.GemfireTemplate;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.session.ExpiringSession;
import org.springframework.session.data.gemfire.GemFireOperationsSessionRepository;
import org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
/**
* The GemFireHttpSessionConfigurationTest class is a test suite of test cases testing the
* contract and functionality of the {@link GemFireHttpSessionConfiguration} class.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.GemfireOperations
* @see org.springframework.data.gemfire.GemfireTemplate
* @see org.springframework.session.data.gemfire.GemFireOperationsSessionRepository
* @see org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
*/
public class GemFireHttpSessionConfigurationTest {
private GemFireHttpSessionConfiguration gemfireConfiguration;
@SuppressWarnings("unchecked")
protected <T> T getField(Object obj, String fieldName) {
try {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(obj);
}
catch (NoSuchFieldException e) {
throw new IllegalArgumentException(String.format(
"field with name [%1$s] was not found in class [%2$s]", fieldName, obj), e);
}
catch (IllegalAccessException e) {
throw new Error(String.format("unable to access field [%1$s] on object of type [%2$s]",
fieldName, obj.getClass().getName()), e);
}
}
protected <T> T[] toArray(T... array) {
return array;
}
@Before
public void setup() {
this.gemfireConfiguration = new GemFireHttpSessionConfiguration();
}
@Test
public void setAndGetBeanClassLoader() {
assertThat(this.gemfireConfiguration.getBeanClassLoader()).isNull();
this.gemfireConfiguration.setBeanClassLoader(Thread.currentThread().getContextClassLoader());
assertThat(this.gemfireConfiguration.getBeanClassLoader()).isEqualTo(
Thread.currentThread().getContextClassLoader());
this.gemfireConfiguration.setBeanClassLoader(null);
assertThat(this.gemfireConfiguration.getBeanClassLoader()).isNull();
}
@Test
public void setAndGetClientRegionShortcut() {
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT);
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.CACHING_PROXY);
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(
ClientRegionShortcut.CACHING_PROXY);
this.gemfireConfiguration.setClientRegionShortcut(null);
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_CLIENT_REGION_SHORTCUT);
}
@Test
public void setAndGetMaxInactiveIntervalInSeconds() {
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_MAX_INACTIVE_INTERVAL_IN_SECONDS);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(300);
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(300);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(Integer.MAX_VALUE);
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(Integer.MAX_VALUE);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(-1);
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(-1);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(Integer.MIN_VALUE);
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(Integer.MIN_VALUE);
}
@Test
public void setAndGetPoolName() {
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME);
this.gemfireConfiguration.setPoolName("TestPoolName");
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo("TestPoolName");
this.gemfireConfiguration.setPoolName(" ");
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME);
this.gemfireConfiguration.setPoolName("");
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME);
this.gemfireConfiguration.setPoolName(null);
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_GEMFIRE_POOL_NAME);
}
@Test
public void setAndGetServerRegionShortcut() {
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.REPLICATE_PERSISTENT);
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(
RegionShortcut.REPLICATE_PERSISTENT);
this.gemfireConfiguration.setServerRegionShortcut(null);
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SERVER_REGION_SHORTCUT);
}
@Test
public void setAndGetSpringSessionGemFireRegionName() {
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.gemfireConfiguration.setSpringSessionGemFireRegionName("test");
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo("test");
this.gemfireConfiguration.setSpringSessionGemFireRegionName(" ");
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.gemfireConfiguration.setSpringSessionGemFireRegionName("");
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.gemfireConfiguration.setSpringSessionGemFireRegionName(null);
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
@Test
public void setsImportMetadata() {
AnnotationMetadata mockAnnotationMetadata = mock(AnnotationMetadata.class);
Map<String, Object> annotationAttributes = new HashMap<String, Object>(4);
annotationAttributes.put("clientRegionShortcut", ClientRegionShortcut.CACHING_PROXY);
annotationAttributes.put("indexableSessionAttributes", toArray("one", "two", "three"));
annotationAttributes.put("maxInactiveIntervalInSeconds", 600);
annotationAttributes.put("poolName", "TestPool");
annotationAttributes.put("serverRegionShortcut", RegionShortcut.REPLICATE);
annotationAttributes.put("regionName", "TEST");
given(mockAnnotationMetadata.getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName())))
.willReturn(annotationAttributes);
this.gemfireConfiguration.setImportMetadata(mockAnnotationMetadata);
assertThat(this.gemfireConfiguration.getClientRegionShortcut()).isEqualTo(ClientRegionShortcut.CACHING_PROXY);
assertThat(this.gemfireConfiguration.getIndexableSessionAttributes()).isEqualTo(toArray("one", "two", "three"));
assertThat(this.gemfireConfiguration.getMaxInactiveIntervalInSeconds()).isEqualTo(600);
assertThat(this.gemfireConfiguration.getPoolName()).isEqualTo("TestPool");
assertThat(this.gemfireConfiguration.getServerRegionShortcut()).isEqualTo(RegionShortcut.REPLICATE);
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo("TEST");
verify(mockAnnotationMetadata, times(1)).getAnnotationAttributes(eq(EnableGemFireHttpSession.class.getName()));
}
@Test
public void createsAndInitializesSessionRepositoryBean() {
GemfireOperations mockGemfireOperations = mock(GemfireOperations.class);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(120);
GemFireOperationsSessionRepository sessionRepository = this.gemfireConfiguration.sessionRepository(
mockGemfireOperations);
assertThat(sessionRepository).isNotNull();
assertThat(sessionRepository.getTemplate()).isSameAs(mockGemfireOperations);
assertThat(sessionRepository.getMaxInactiveIntervalInSeconds()).isEqualTo(120);
}
@Test
@SuppressWarnings("unchecked")
public void createsAndInitializesSessionRegionTemplateBean() {
GemFireCache mockGemFireCache = mock(GemFireCache.class);
Region<Object, Object> mockRegion = mock(Region.class);
given(mockGemFireCache.getRegion(eq("Example"))).willReturn(mockRegion);
this.gemfireConfiguration.setSpringSessionGemFireRegionName("Example");
GemfireTemplate template = this.gemfireConfiguration.sessionRegionTemplate(mockGemFireCache);
assertThat(this.gemfireConfiguration.getSpringSessionGemFireRegionName()).isEqualTo("Example");
assertThat(template).isNotNull();
assertThat(template.getRegion()).isSameAs(mockRegion);
verify(mockGemFireCache, times(1)).getRegion(eq("Example"));
}
@Test
@SuppressWarnings("unchecked")
public void createsAndInitializesSessionRegionBean() {
GemFireCache mockGemFireCache = mock(GemFireCache.class);
RegionAttributes<Object, ExpiringSession> mockRegionAttributes = mock(RegionAttributes.class);
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.CACHING_PROXY);
this.gemfireConfiguration.setPoolName("TestPool");
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.REPLICATE_PERSISTENT);
this.gemfireConfiguration.setSpringSessionGemFireRegionName("TestRegion");
GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> sessionRegionFactoryBean =
this.gemfireConfiguration.sessionRegion(mockGemFireCache, mockRegionAttributes);
assertThat(sessionRegionFactoryBean).isNotNull();
assertThat(this.<ClientRegionShortcut>getField(sessionRegionFactoryBean, "clientRegionShortcut"))
.isEqualTo(ClientRegionShortcut.CACHING_PROXY);
assertThat(this.<GemFireCache>getField(sessionRegionFactoryBean, "gemfireCache"))
.isEqualTo(mockGemFireCache);
assertThat(this.<String>getField(sessionRegionFactoryBean, "poolName")).isEqualTo("TestPool");
assertThat(this.<RegionAttributes<Object, ExpiringSession>>getField(sessionRegionFactoryBean,
"regionAttributes")).isEqualTo(mockRegionAttributes);
assertThat(this.<String>getField(sessionRegionFactoryBean, "regionName")).isEqualTo("TestRegion");
assertThat(this.<RegionShortcut>getField(sessionRegionFactoryBean, "serverRegionShortcut"))
.isEqualTo(RegionShortcut.REPLICATE_PERSISTENT);
verifyZeroInteractions(mockGemFireCache);
verifyZeroInteractions(mockRegionAttributes);
}
@Test
@SuppressWarnings("unchecked")
public void createsAndInitializesSessionRegionAttributesWithExpiration() throws Exception {
Cache mockCache = mock(Cache.class);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(300);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.LOCAL);
RegionAttributesFactoryBean regionAttributesFactory =
this.gemfireConfiguration.sessionRegionAttributes(mockCache);
assertThat(regionAttributesFactory).isNotNull();
regionAttributesFactory.afterPropertiesSet();
RegionAttributes<Object, ExpiringSession> sessionRegionAttributes = regionAttributesFactory.getObject();
assertThat(sessionRegionAttributes).isNotNull();
assertThat(sessionRegionAttributes.getKeyConstraint()).isEqualTo(
GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT);
assertThat(sessionRegionAttributes.getValueConstraint()).isEqualTo(
GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT);
ExpirationAttributes entryIdleTimeoutExpiration = sessionRegionAttributes.getEntryIdleTimeout();
assertThat(entryIdleTimeoutExpiration).isNotNull();
assertThat(entryIdleTimeoutExpiration.getAction()).isEqualTo(ExpirationAction.INVALIDATE);
assertThat(entryIdleTimeoutExpiration.getTimeout()).isEqualTo(300);
}
@Test
@SuppressWarnings("unchecked")
public void createsAndInitializesSessionRegionAttributesWithoutExpiration() throws Exception {
ClientCache mockClientCache = mock(ClientCache.class);
this.gemfireConfiguration.setMaxInactiveIntervalInSeconds(300);
RegionAttributesFactoryBean regionAttributesFactory =
this.gemfireConfiguration.sessionRegionAttributes(mockClientCache);
assertThat(regionAttributesFactory).isNotNull();
regionAttributesFactory.afterPropertiesSet();
RegionAttributes<Object, ExpiringSession> sessionRegionAttributes = regionAttributesFactory.getObject();
assertThat(sessionRegionAttributes).isNotNull();
assertThat(sessionRegionAttributes.getKeyConstraint()).isEqualTo(
GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_REGION_KEY_CONSTRAINT);
assertThat(sessionRegionAttributes.getValueConstraint()).isEqualTo(
GemFireHttpSessionConfiguration.SPRING_SESSION_GEMFIRE_REGION_VALUE_CONSTRAINT);
ExpirationAttributes entryIdleTimeoutExpiration = sessionRegionAttributes.getEntryIdleTimeout();
assertThat(entryIdleTimeoutExpiration).isNotNull();
assertThat(entryIdleTimeoutExpiration.getAction()).isEqualTo(ExpirationAction.INVALIDATE);
assertThat(entryIdleTimeoutExpiration.getTimeout()).isEqualTo(0);
}
@Test
public void expirationIsAllowed() {
Cache mockCache = mock(Cache.class);
ClientCache mockClientCache = mock(ClientCache.class);
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.PROXY);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.REPLICATE);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockCache)).isTrue();
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockCache)).isTrue();
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.CACHING_PROXY);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION_PROXY);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockClientCache)).isTrue();
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.REPLICATE_PROXY);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockClientCache)).isTrue();
}
@Test
public void expirationIsNotAllowed() {
Cache mockCache = mock(Cache.class);
ClientCache mockClientCache = mock(ClientCache.class);
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.PROXY);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockClientCache)).isFalse();
this.gemfireConfiguration.setClientRegionShortcut(ClientRegionShortcut.LOCAL);
this.gemfireConfiguration.setServerRegionShortcut(RegionShortcut.PARTITION_PROXY);
assertThat(this.gemfireConfiguration.isExpirationAllowed(mockCache)).isFalse();
}
}

View File

@@ -1,295 +0,0 @@
/*
* Copyright 2014-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.InterestResultPolicy;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.data.gemfire.client.Interest;
import org.springframework.session.ExpiringSession;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* The GemFireCacheTypeAwareRegionFactoryBeanTest class is a test suite of test cases
* testing the contract and functionality of the GemFireCacheTypeAwareRegionFactoryBean
* class.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Rule
* @see org.junit.Test
* @see org.junit.rules.ExpectedException
* @see org.mockito.Mockito
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.GemFireCacheTypeAwareRegionFactoryBean
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.InterestResultPolicy
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionAttributes
* @see org.apache.geode.cache.RegionShortcut
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
@RunWith(MockitoJUnitRunner.class)
public class GemFireCacheTypeAwareRegionFactoryBeanTest {
@Rule
public ExpectedException exception = ExpectedException.none();
@Mock
Cache mockCache;
@Mock
ClientCache mockClientCache;
@Mock
Region<Object, ExpiringSession> mockClientRegion;
@Mock
Region<Object, ExpiringSession> mockServerRegion;
private GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession> regionFactoryBean;
@Before
public void setup() {
this.regionFactoryBean = new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>();
}
protected void afterPropertiesSetCreatesCorrectRegionForGemFireCacheType(final GemFireCache expectedCache,
Region<Object, ExpiringSession> expectedRegion) throws Exception {
this.regionFactoryBean = new GemFireCacheTypeAwareRegionFactoryBean<Object, ExpiringSession>() {
@Override
protected Region<Object, ExpiringSession> newClientRegion(GemFireCache gemfireCache) throws Exception {
assertThat(gemfireCache).isSameAs(expectedCache);
return GemFireCacheTypeAwareRegionFactoryBeanTest.this.mockClientRegion;
}
@Override
protected Region<Object, ExpiringSession> newServerRegion(GemFireCache gemfireCache) throws Exception {
assertThat(gemfireCache).isSameAs(expectedCache);
return GemFireCacheTypeAwareRegionFactoryBeanTest.this.mockServerRegion;
}
};
this.regionFactoryBean.setGemfireCache(expectedCache);
this.regionFactoryBean.afterPropertiesSet();
assertThat(this.regionFactoryBean.getGemfireCache()).isSameAs(expectedCache);
assertThat(this.regionFactoryBean.getObject()).isEqualTo(expectedRegion);
assertThat(this.regionFactoryBean.getObjectType()).isEqualTo(expectedRegion.getClass());
}
@Test
public void afterPropertiesSetCreatesClientRegionForClientCache() throws Exception {
afterPropertiesSetCreatesCorrectRegionForGemFireCacheType(this.mockClientCache, this.mockClientRegion);
}
@Test
public void afterPropertiesSetCreatesServerRegionForPeerCache() throws Exception {
afterPropertiesSetCreatesCorrectRegionForGemFireCacheType(this.mockCache, this.mockServerRegion);
}
@Test
public void allKeysInterestsRegistration() {
Interest<Object>[] interests = this.regionFactoryBean.registerInterests(true);
assertThat(interests).isNotNull();
assertThat(interests.length).isEqualTo(1);
assertThat(interests[0].isDurable()).isFalse();
assertThat(interests[0].getKey().toString()).isEqualTo("ALL_KEYS");
assertThat(interests[0].getPolicy()).isEqualTo(InterestResultPolicy.KEYS);
assertThat(interests[0].isReceiveValues()).isTrue();
}
@Test
public void emptyInterestsRegistration() {
Interest<Object>[] interests = this.regionFactoryBean.registerInterests(false);
assertThat(interests).isNotNull();
assertThat(interests.length).isEqualTo(0);
}
@Test
public void getObjectTypeBeforeInitializationIsRegionClass() {
assertThat(this.regionFactoryBean.getObjectType()).isEqualTo(Region.class);
}
@Test
public void isSingletonIsTrue() {
assertThat(this.regionFactoryBean.isSingleton()).isTrue();
}
@Test
public void setAndGetBeanFactory() {
BeanFactory mockBeanFactory = mock(BeanFactory.class);
this.regionFactoryBean.setBeanFactory(mockBeanFactory);
assertThat(this.regionFactoryBean.getBeanFactory()).isEqualTo(mockBeanFactory);
}
@Test
public void setBeanFactoryToNullThrowsIllegalArgumentException() {
this.exception.expect(IllegalArgumentException.class);
this.exception.expectMessage("BeanFactory must not be null");
this.regionFactoryBean.setBeanFactory(null);
}
@Test
public void getBeanFactoryWhenNullThrowsIllegalStateException() {
this.exception.expect(IllegalStateException.class);
this.exception.expectMessage("A reference to the BeanFactory was not properly configured");
this.regionFactoryBean.getBeanFactory();
}
@Test
public void setAndGetClientRegionShortcut() {
assertThat(this.regionFactoryBean.getClientRegionShortcut()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_CLIENT_REGION_SHORTCUT);
this.regionFactoryBean.setClientRegionShortcut(ClientRegionShortcut.LOCAL_PERSISTENT);
assertThat(this.regionFactoryBean.getClientRegionShortcut()).isEqualTo(
ClientRegionShortcut.LOCAL_PERSISTENT);
this.regionFactoryBean.setClientRegionShortcut(null);
assertThat(this.regionFactoryBean.getClientRegionShortcut()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_CLIENT_REGION_SHORTCUT);
}
@Test
public void setAndGetGemfireCache() {
Cache mockCache = mock(Cache.class);
this.regionFactoryBean.setGemfireCache(mockCache);
assertThat(this.regionFactoryBean.getGemfireCache()).isEqualTo(mockCache);
}
@Test
public void setGemfireCacheToNullThrowsIllegalArgumentException() {
this.exception.expect(IllegalArgumentException.class);
this.exception.expectMessage("GemFireCache must not be null");
this.regionFactoryBean.setGemfireCache(null);
}
@Test
public void getGemfireCacheWhenNullThrowsIllegalStateException() {
this.exception.expect(IllegalStateException.class);
this.exception.expectMessage("A reference to the GemFireCache was not properly configured");
this.regionFactoryBean.getGemfireCache();
}
@Test
public void setAndGetPoolName() {
assertThat(this.regionFactoryBean.getPoolName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_GEMFIRE_POOL_NAME);
this.regionFactoryBean.setPoolName("TestPoolName");
assertThat(this.regionFactoryBean.getPoolName()).isEqualTo("TestPoolName");
this.regionFactoryBean.setPoolName(" ");
assertThat(this.regionFactoryBean.getPoolName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_GEMFIRE_POOL_NAME);
this.regionFactoryBean.setPoolName("");
assertThat(this.regionFactoryBean.getPoolName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_GEMFIRE_POOL_NAME);
this.regionFactoryBean.setPoolName(null);
assertThat(this.regionFactoryBean.getPoolName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_GEMFIRE_POOL_NAME);
}
@Test
@SuppressWarnings("unchecked")
public void setAndGetRegionAttributes() {
RegionAttributes<Object, ExpiringSession> mockRegionAttributes = mock(RegionAttributes.class);
assertThat(this.regionFactoryBean.getRegionAttributes()).isNull();
this.regionFactoryBean.setRegionAttributes(mockRegionAttributes);
assertThat(this.regionFactoryBean.getRegionAttributes()).isSameAs(mockRegionAttributes);
this.regionFactoryBean.setRegionAttributes(null);
assertThat(this.regionFactoryBean.getRegionAttributes()).isNull();
}
@Test
public void setAndGetRegionName() {
assertThat(this.regionFactoryBean.getRegionName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.regionFactoryBean.setRegionName("Example");
assertThat(this.regionFactoryBean.getRegionName()).isEqualTo("Example");
this.regionFactoryBean.setRegionName(" ");
assertThat(this.regionFactoryBean.getRegionName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.regionFactoryBean.setRegionName("");
assertThat(this.regionFactoryBean.getRegionName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
this.regionFactoryBean.setRegionName(null);
assertThat(this.regionFactoryBean.getRegionName()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SPRING_SESSION_GEMFIRE_REGION_NAME);
}
@Test
public void setAndGetServerRegionShortcut() {
assertThat(this.regionFactoryBean.getServerRegionShortcut()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SERVER_REGION_SHORTCUT);
this.regionFactoryBean.setServerRegionShortcut(RegionShortcut.LOCAL_PERSISTENT);
assertThat(this.regionFactoryBean.getServerRegionShortcut()).isEqualTo(RegionShortcut.LOCAL_PERSISTENT);
this.regionFactoryBean.setServerRegionShortcut(null);
assertThat(this.regionFactoryBean.getServerRegionShortcut()).isEqualTo(
GemFireCacheTypeAwareRegionFactoryBean.DEFAULT_SERVER_REGION_SHORTCUT);
}
}

View File

@@ -1,132 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.config.annotation.web.http.support;
import org.apache.geode.cache.query.Index;
import org.junit.Before;
import org.junit.Test;
import org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Test suite of test cases testing the contract and functionality
* of the {@link SessionAttributesIndexFactoryBean} class.
*
* @author John Blum
* @since 1.3.0
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.session.data.gemfire.config.annotation.web.http.support.SessionAttributesIndexFactoryBean
*/
public class SessionAttributesIndexFactoryBeanTests {
static <T> T[] toArray(T... array) {
return array;
}
private SessionAttributesIndexFactoryBean indexFactoryBean;
@Before
public void setup() {
this.indexFactoryBean = new SessionAttributesIndexFactoryBean();
}
@Test
public void indexIsNotInitializedWhenNoIndexableSessionAttributesAreConfigured() throws Exception {
final Index mockIndex = mock(Index.class);
SessionAttributesIndexFactoryBean indexFactoryBean = new SessionAttributesIndexFactoryBean() {
@Override
protected Index newIndex() throws Exception {
return mockIndex;
}
};
indexFactoryBean.afterPropertiesSet();
assertThat(indexFactoryBean.getObject()).isNull();
assertThat(indexFactoryBean.getObjectType()).isEqualTo(Index.class);
}
@Test
public void initializesIndexWhenIndexableSessionAttributesAreConfigured() throws Exception {
final Index mockIndex = mock(Index.class);
SessionAttributesIndexFactoryBean indexFactoryBean = new SessionAttributesIndexFactoryBean() {
@Override
protected Index newIndex() throws Exception {
return mockIndex;
}
};
indexFactoryBean.setIndexableSessionAttributes(toArray("one", "two"));
indexFactoryBean.afterPropertiesSet();
assertThat(indexFactoryBean.getObject()).isEqualTo(mockIndex);
assertThat(indexFactoryBean.getObjectType()).isEqualTo(mockIndex.getClass());
}
@Test
public void isSingletonIsTrue() {
assertThat(this.indexFactoryBean.isSingleton()).isTrue();
}
@Test
public void setAndGetIndexableSessionAttributes() {
assertThat(this.indexFactoryBean.getIndexableSessionAttributes()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
assertThat(this.indexFactoryBean.getIndexableSessionAttributesAsGemFireIndexExpression()).isEqualTo("*");
this.indexFactoryBean.setIndexableSessionAttributes(toArray("one", "two", "three"));
assertThat(this.indexFactoryBean.getIndexableSessionAttributes()).isEqualTo(
toArray("one", "two", "three"));
assertThat(this.indexFactoryBean.getIndexableSessionAttributesAsGemFireIndexExpression()).isEqualTo(
"'one', 'two', 'three'");
this.indexFactoryBean.setIndexableSessionAttributes(toArray("one"));
assertThat(this.indexFactoryBean.getIndexableSessionAttributes()).isEqualTo(toArray("one"));
assertThat(this.indexFactoryBean.getIndexableSessionAttributesAsGemFireIndexExpression()).isEqualTo("'one'");
this.indexFactoryBean.setIndexableSessionAttributes(null);
assertThat(this.indexFactoryBean.getIndexableSessionAttributes()).isEqualTo(
GemFireHttpSessionConfiguration.DEFAULT_INDEXABLE_SESSION_ATTRIBUTES);
assertThat(this.indexFactoryBean.getIndexableSessionAttributesAsGemFireIndexExpression()).isEqualTo("*");
}
@Test
public void setAndGetRegionName() {
assertThat(this.indexFactoryBean.getRegionName()).isNull();
this.indexFactoryBean.setRegionName("Example");
assertThat(this.indexFactoryBean.getRegionName()).isEqualTo("Example");
this.indexFactoryBean.setRegionName(null);
assertThat(this.indexFactoryBean.getRegionName()).isNull();
}
}

View File

@@ -1,203 +0,0 @@
/*
* Copyright 2014-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.session.data.gemfire.support;
import java.io.Closeable;
import java.io.IOException;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
/**
* The GemFireUtilsTest class is a test suite of test cases testing the contract and
* functionality of the GemFireUtils utility class.
*
* @author John Blum
* @since 1.1.0
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.springframework.session.data.gemfire.support.GemFireUtils
*/
public class GemFireUtilsTest {
@Test
public void closeNonNullCloseableSuccessfullyReturnsTrue() throws IOException {
Closeable mockCloseable = mock(Closeable.class);
assertThat(GemFireUtils.close(mockCloseable)).isTrue();
verify(mockCloseable, times(1)).close();
}
@Test
public void closeNonNullCloseableObjectThrowingIOExceptionReturnsFalse() throws IOException {
Closeable mockCloseable = mock(Closeable.class);
willThrow(new IOException("test")).given(mockCloseable).close();
assertThat(GemFireUtils.close(mockCloseable)).isFalse();
verify(mockCloseable, times(1)).close();
}
@Test
public void closeNullCloseableObjectReturnsFalse() {
assertThat(GemFireUtils.close(null)).isFalse();
}
@Test
public void clientCacheIsClient() {
assertThat(GemFireUtils.isClient(mock(ClientCache.class))).isTrue();
}
@Test
public void genericCacheIsNotClient() {
assertThat(GemFireUtils.isClient(mock(GemFireCache.class))).isFalse();
}
@Test
public void peerCacheIsNotClient() {
assertThat(GemFireUtils.isClient(mock(Cache.class))).isFalse();
}
@Test
public void peerCacheIsPeer() {
assertThat(GemFireUtils.isPeer(mock(Cache.class))).isTrue();
}
@Test
public void genericCacheIsNotPeer() {
assertThat(GemFireUtils.isPeer(mock(GemFireCache.class))).isFalse();
}
@Test
public void clientCacheIsNotPeer() {
assertThat(GemFireUtils.isPeer(mock(ClientCache.class))).isFalse();
}
@Test
public void clientRegionShortcutIsLocal() {
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_HEAP_LRU)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_OVERFLOW)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_PERSISTENT)).isTrue();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isTrue();
}
@Test
public void clientRegionShortcutIsNotLocal() {
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY)).isFalse();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isLocal(ClientRegionShortcut.PROXY)).isFalse();
}
@Test
public void clientRegionShortcutIsProxy() {
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.PROXY)).isTrue();
}
@Test
public void clientRegionShortcutIsNotProxy() {
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_PERSISTENT)).isFalse();
assertThat(GemFireUtils.isProxy(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isFalse();
}
@Test
public void regionShortcutIsProxy() {
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PROXY_REDUNDANT)).isTrue();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PROXY)).isTrue();
}
@Test
public void regionIsProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.EMPTY);
assertThat(GemFireUtils.isProxy(mockRegion)).isTrue();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
}
@Test
public void regionIsNotProxy() {
Region mockRegion = mock(Region.class);
RegionAttributes mockRegionAttributes = mock(RegionAttributes.class);
given(mockRegion.getAttributes()).willReturn(mockRegionAttributes);
given(mockRegionAttributes.getDataPolicy()).willReturn(DataPolicy.NORMAL);
assertThat(GemFireUtils.isProxy(mockRegion)).isFalse();
verify(mockRegion, times(1)).getAttributes();
verify(mockRegionAttributes, times(1)).getDataPolicy();
}
@Test
public void regionShortcutIsNotProxy() {
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_PERSISTENT)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PERSISTENT)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PERSISTENT)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_OVERFLOW)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT)).isFalse();
assertThat(GemFireUtils.isProxy(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW)).isFalse();
}
@Test
public void toRegionPath() {
assertThat(GemFireUtils.toRegionPath("A")).isEqualTo("/A");
assertThat(GemFireUtils.toRegionPath("Example")).isEqualTo("/Example");
assertThat(GemFireUtils.toRegionPath("/Example")).isEqualTo("//Example");
assertThat(GemFireUtils.toRegionPath("/")).isEqualTo("//");
assertThat(GemFireUtils.toRegionPath("")).isEqualTo("/");
}
}

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<util:properties id="gemfireProperties">
<prop key="name">GemFireHttpSessionXmlConfigurationTests</prop>
<prop key="mcast-port">0</prop>
<prop key="log-level">warning</prop>
</util:properties>
<gfe:cache properties-ref="gemfireProperties"/>
<bean class="org.springframework.session.data.gemfire.config.annotation.web.http.GemFireHttpSessionConfiguration"
p:indexableSessionAttributes="one, two, three" p:maxInactiveIntervalInSeconds="3600"
p:serverRegionShortcut="#{T(org.apache.geode.cache.RegionShortcut).LOCAL}"
p:springSessionGemFireRegionName="XmlExample"/>
</beans>